init
This commit is contained in:
@@ -0,0 +1,799 @@
|
||||
openapi: 3.0.3
|
||||
info:
|
||||
title: Test REST API
|
||||
version: 1.0.0
|
||||
description: |
|
||||
Testowy serwis REST API (CakePHP 5): klienci (`customers`), ich auta (`cars`) i użytkownicy (`users`).
|
||||
|
||||
## Uwierzytelnianie
|
||||
1. Wywołaj `POST /api/auth/login` z e-mailem i hasłem.
|
||||
2. Skopiuj `data.token` i kliknij **Authorize** (u góry strony) – wklej sam token (bez `Bearer`).
|
||||
3. Token wysyłany jest w nagłówku `Authorization: Bearer <token>` i jest ważny 8 godzin.
|
||||
|
||||
Konta testowe:
|
||||
|
||||
| Rola | E-mail | Hasło |
|
||||
|-------|---------------------|------------|
|
||||
| admin | admin@example.com | Admin123! |
|
||||
| user | user@example.com | User1234! |
|
||||
|
||||
## Uprawnienia
|
||||
* **admin** – pełny dostęp, w tym CRUD użytkowników (`/api/users`).
|
||||
* **user** – logowanie, własny profil (`/api/auth/me`), CRUD klientów i aut.
|
||||
|
||||
## Format odpowiedzi
|
||||
* Sukces: `{"success": true, "data": ...}` (listy dodatkowo mają `meta` z paginacją).
|
||||
* Błąd: `{"success": false, "error": {"code": 422, "message": "...", "fields": {...}}}`.
|
||||
* `DELETE` zwraca `204 No Content`.
|
||||
|
||||
## Listy
|
||||
Wszystkie listy obsługują `page`, `limit` (domyślnie 20, max 100), `sort` i `direction` (`asc`/`desc`).
|
||||
Łączna liczba rekordów jest również w nagłówku `X-Total-Count`.
|
||||
servers:
|
||||
- url: /
|
||||
description: Ten serwer
|
||||
security:
|
||||
- bearerAuth: []
|
||||
tags:
|
||||
- name: Auth
|
||||
description: Logowanie i profil zalogowanego użytkownika
|
||||
- name: Customers
|
||||
description: Klienci (wszyscy zalogowani)
|
||||
- name: Cars
|
||||
description: Auta klientów (wszyscy zalogowani)
|
||||
- name: Users
|
||||
description: Użytkownicy systemu (tylko admin)
|
||||
|
||||
paths:
|
||||
/api/auth/login:
|
||||
post:
|
||||
tags: [Auth]
|
||||
summary: Logowanie – zwraca token JWT
|
||||
security: []
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required: [email, password]
|
||||
properties:
|
||||
email: { type: string, format: email, example: admin@example.com }
|
||||
password: { type: string, format: password, example: Admin123! }
|
||||
responses:
|
||||
'200':
|
||||
description: Zalogowano
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
success: { type: boolean, example: true }
|
||||
data:
|
||||
type: object
|
||||
properties:
|
||||
token: { type: string, example: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9... }
|
||||
token_type: { type: string, example: Bearer }
|
||||
expires_in: { type: integer, description: Czas ważności w sekundach, example: 28800 }
|
||||
user: { $ref: '#/components/schemas/User' }
|
||||
'401': { $ref: '#/components/responses/Unauthorized' }
|
||||
|
||||
/api/auth/me:
|
||||
get:
|
||||
tags: [Auth]
|
||||
summary: Profil zalogowanego użytkownika
|
||||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: '#/components/schemas/UserResponse' }
|
||||
'401': { $ref: '#/components/responses/Unauthorized' }
|
||||
patch:
|
||||
tags: [Auth]
|
||||
summary: Edycja własnego profilu (imię, nazwisko, e-mail, hasło)
|
||||
description: Pola `role` i `active` są ignorowane – może je zmienić tylko admin przez `/api/users/{id}`.
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: '#/components/schemas/ProfileInput' }
|
||||
responses:
|
||||
'200':
|
||||
description: Zaktualizowano
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: '#/components/schemas/UserResponse' }
|
||||
'401': { $ref: '#/components/responses/Unauthorized' }
|
||||
'422': { $ref: '#/components/responses/ValidationError' }
|
||||
put:
|
||||
tags: [Auth]
|
||||
summary: Edycja własnego profilu (alias PATCH)
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: '#/components/schemas/ProfileInput' }
|
||||
responses:
|
||||
'200':
|
||||
description: Zaktualizowano
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: '#/components/schemas/UserResponse' }
|
||||
'401': { $ref: '#/components/responses/Unauthorized' }
|
||||
'422': { $ref: '#/components/responses/ValidationError' }
|
||||
|
||||
/api/customers:
|
||||
get:
|
||||
tags: [Customers]
|
||||
summary: Lista klientów
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/page'
|
||||
- $ref: '#/components/parameters/limit'
|
||||
- name: sort
|
||||
in: query
|
||||
schema:
|
||||
type: string
|
||||
enum: [id, type, first_name, last_name, email, company_name, city, country, created, modified]
|
||||
- $ref: '#/components/parameters/direction'
|
||||
- name: q
|
||||
in: query
|
||||
description: Szukaj w imieniu, nazwisku, e-mailu, telefonie, nazwie firmy, mieście i NIP
|
||||
schema: { type: string }
|
||||
- name: type
|
||||
in: query
|
||||
schema: { type: string, enum: [individual, company] }
|
||||
- name: city
|
||||
in: query
|
||||
schema: { type: string }
|
||||
- name: country
|
||||
in: query
|
||||
schema: { type: string, example: PL }
|
||||
- name: with_cars
|
||||
in: query
|
||||
description: Dołącz listę aut każdego klienta
|
||||
schema: { type: boolean }
|
||||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
success: { type: boolean, example: true }
|
||||
data:
|
||||
type: array
|
||||
items: { $ref: '#/components/schemas/Customer' }
|
||||
meta: { $ref: '#/components/schemas/PaginationMeta' }
|
||||
'401': { $ref: '#/components/responses/Unauthorized' }
|
||||
post:
|
||||
tags: [Customers]
|
||||
summary: Dodaj klienta
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: '#/components/schemas/CustomerCreate' }
|
||||
responses:
|
||||
'201':
|
||||
description: Utworzono
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: '#/components/schemas/CustomerResponse' }
|
||||
'401': { $ref: '#/components/responses/Unauthorized' }
|
||||
'422': { $ref: '#/components/responses/ValidationError' }
|
||||
|
||||
/api/customers/{id}:
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/id'
|
||||
get:
|
||||
tags: [Customers]
|
||||
summary: Szczegóły klienta (z autami)
|
||||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
success: { type: boolean, example: true }
|
||||
data: { $ref: '#/components/schemas/CustomerWithCars' }
|
||||
'401': { $ref: '#/components/responses/Unauthorized' }
|
||||
'404': { $ref: '#/components/responses/NotFound' }
|
||||
patch:
|
||||
tags: [Customers]
|
||||
summary: Częściowa edycja klienta
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: '#/components/schemas/CustomerInput' }
|
||||
responses:
|
||||
'200':
|
||||
description: Zaktualizowano
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: '#/components/schemas/CustomerResponse' }
|
||||
'401': { $ref: '#/components/responses/Unauthorized' }
|
||||
'404': { $ref: '#/components/responses/NotFound' }
|
||||
'422': { $ref: '#/components/responses/ValidationError' }
|
||||
put:
|
||||
tags: [Customers]
|
||||
summary: Edycja klienta
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: '#/components/schemas/CustomerInput' }
|
||||
responses:
|
||||
'200':
|
||||
description: Zaktualizowano
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: '#/components/schemas/CustomerResponse' }
|
||||
'401': { $ref: '#/components/responses/Unauthorized' }
|
||||
'404': { $ref: '#/components/responses/NotFound' }
|
||||
'422': { $ref: '#/components/responses/ValidationError' }
|
||||
delete:
|
||||
tags: [Customers]
|
||||
summary: Usuń klienta (razem z jego autami)
|
||||
responses:
|
||||
'204': { description: Usunięto }
|
||||
'401': { $ref: '#/components/responses/Unauthorized' }
|
||||
'404': { $ref: '#/components/responses/NotFound' }
|
||||
|
||||
/api/customers/{customer_id}/cars:
|
||||
parameters:
|
||||
- name: customer_id
|
||||
in: path
|
||||
required: true
|
||||
schema: { type: integer, example: 1 }
|
||||
get:
|
||||
tags: [Cars]
|
||||
summary: Auta danego klienta
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/page'
|
||||
- $ref: '#/components/parameters/limit'
|
||||
- $ref: '#/components/parameters/carSort'
|
||||
- $ref: '#/components/parameters/direction'
|
||||
responses:
|
||||
'200': { $ref: '#/components/responses/CarList' }
|
||||
'401': { $ref: '#/components/responses/Unauthorized' }
|
||||
'404': { $ref: '#/components/responses/NotFound' }
|
||||
post:
|
||||
tags: [Cars]
|
||||
summary: Dodaj auto do klienta
|
||||
description: '`customer_id` jest brany ze ścieżki.'
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: '#/components/schemas/CarCreateNested' }
|
||||
responses:
|
||||
'201':
|
||||
description: Utworzono
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: '#/components/schemas/CarResponse' }
|
||||
'401': { $ref: '#/components/responses/Unauthorized' }
|
||||
'404': { $ref: '#/components/responses/NotFound' }
|
||||
'422': { $ref: '#/components/responses/ValidationError' }
|
||||
|
||||
/api/cars:
|
||||
get:
|
||||
tags: [Cars]
|
||||
summary: Lista aut
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/page'
|
||||
- $ref: '#/components/parameters/limit'
|
||||
- $ref: '#/components/parameters/carSort'
|
||||
- $ref: '#/components/parameters/direction'
|
||||
- name: q
|
||||
in: query
|
||||
description: Szukaj w marce, modelu, VIN i numerze rejestracyjnym
|
||||
schema: { type: string }
|
||||
- name: customer_id
|
||||
in: query
|
||||
schema: { type: integer }
|
||||
- name: make
|
||||
in: query
|
||||
schema: { type: string, example: Toyota }
|
||||
- name: fuel_type
|
||||
in: query
|
||||
schema: { $ref: '#/components/schemas/FuelType' }
|
||||
- name: transmission
|
||||
in: query
|
||||
schema: { type: string, enum: [manual, automatic] }
|
||||
- name: year_from
|
||||
in: query
|
||||
schema: { type: integer, example: 2015 }
|
||||
- name: year_to
|
||||
in: query
|
||||
schema: { type: integer, example: 2022 }
|
||||
- name: with_customer
|
||||
in: query
|
||||
description: Dołącz dane właściciela
|
||||
schema: { type: boolean }
|
||||
responses:
|
||||
'200': { $ref: '#/components/responses/CarList' }
|
||||
'401': { $ref: '#/components/responses/Unauthorized' }
|
||||
post:
|
||||
tags: [Cars]
|
||||
summary: Dodaj auto
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: '#/components/schemas/CarCreate' }
|
||||
responses:
|
||||
'201':
|
||||
description: Utworzono
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: '#/components/schemas/CarResponse' }
|
||||
'401': { $ref: '#/components/responses/Unauthorized' }
|
||||
'422': { $ref: '#/components/responses/ValidationError' }
|
||||
|
||||
/api/cars/{id}:
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/id'
|
||||
get:
|
||||
tags: [Cars]
|
||||
summary: Szczegóły auta (z właścicielem)
|
||||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
success: { type: boolean, example: true }
|
||||
data: { $ref: '#/components/schemas/CarWithCustomer' }
|
||||
'401': { $ref: '#/components/responses/Unauthorized' }
|
||||
'404': { $ref: '#/components/responses/NotFound' }
|
||||
patch:
|
||||
tags: [Cars]
|
||||
summary: Częściowa edycja auta
|
||||
description: Zmiana `customer_id` przenosi auto do innego klienta.
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: '#/components/schemas/CarInput' }
|
||||
responses:
|
||||
'200':
|
||||
description: Zaktualizowano
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: '#/components/schemas/CarResponse' }
|
||||
'401': { $ref: '#/components/responses/Unauthorized' }
|
||||
'404': { $ref: '#/components/responses/NotFound' }
|
||||
'422': { $ref: '#/components/responses/ValidationError' }
|
||||
put:
|
||||
tags: [Cars]
|
||||
summary: Edycja auta
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: '#/components/schemas/CarInput' }
|
||||
responses:
|
||||
'200':
|
||||
description: Zaktualizowano
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: '#/components/schemas/CarResponse' }
|
||||
'401': { $ref: '#/components/responses/Unauthorized' }
|
||||
'404': { $ref: '#/components/responses/NotFound' }
|
||||
'422': { $ref: '#/components/responses/ValidationError' }
|
||||
delete:
|
||||
tags: [Cars]
|
||||
summary: Usuń auto
|
||||
responses:
|
||||
'204': { description: Usunięto }
|
||||
'401': { $ref: '#/components/responses/Unauthorized' }
|
||||
'404': { $ref: '#/components/responses/NotFound' }
|
||||
|
||||
/api/users:
|
||||
get:
|
||||
tags: [Users]
|
||||
summary: Lista użytkowników (admin)
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/page'
|
||||
- $ref: '#/components/parameters/limit'
|
||||
- name: sort
|
||||
in: query
|
||||
schema:
|
||||
type: string
|
||||
enum: [id, email, first_name, last_name, role, active, last_login, created, modified]
|
||||
- $ref: '#/components/parameters/direction'
|
||||
- name: q
|
||||
in: query
|
||||
description: Szukaj w e-mailu, imieniu i nazwisku
|
||||
schema: { type: string }
|
||||
- name: role
|
||||
in: query
|
||||
schema: { $ref: '#/components/schemas/Role' }
|
||||
- name: active
|
||||
in: query
|
||||
schema: { type: boolean }
|
||||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
success: { type: boolean, example: true }
|
||||
data:
|
||||
type: array
|
||||
items: { $ref: '#/components/schemas/User' }
|
||||
meta: { $ref: '#/components/schemas/PaginationMeta' }
|
||||
'401': { $ref: '#/components/responses/Unauthorized' }
|
||||
'403': { $ref: '#/components/responses/Forbidden' }
|
||||
post:
|
||||
tags: [Users]
|
||||
summary: Dodaj użytkownika (admin)
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: '#/components/schemas/UserCreate' }
|
||||
responses:
|
||||
'201':
|
||||
description: Utworzono
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: '#/components/schemas/UserResponse' }
|
||||
'401': { $ref: '#/components/responses/Unauthorized' }
|
||||
'403': { $ref: '#/components/responses/Forbidden' }
|
||||
'422': { $ref: '#/components/responses/ValidationError' }
|
||||
|
||||
/api/users/{id}:
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/id'
|
||||
get:
|
||||
tags: [Users]
|
||||
summary: Szczegóły użytkownika (admin)
|
||||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: '#/components/schemas/UserResponse' }
|
||||
'401': { $ref: '#/components/responses/Unauthorized' }
|
||||
'403': { $ref: '#/components/responses/Forbidden' }
|
||||
'404': { $ref: '#/components/responses/NotFound' }
|
||||
patch:
|
||||
tags: [Users]
|
||||
summary: Częściowa edycja użytkownika (admin)
|
||||
description: Admin nie może zmienić własnej roli ani dezaktywować własnego konta.
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: '#/components/schemas/UserInput' }
|
||||
responses:
|
||||
'200':
|
||||
description: Zaktualizowano
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: '#/components/schemas/UserResponse' }
|
||||
'400': { $ref: '#/components/responses/BadRequest' }
|
||||
'401': { $ref: '#/components/responses/Unauthorized' }
|
||||
'403': { $ref: '#/components/responses/Forbidden' }
|
||||
'404': { $ref: '#/components/responses/NotFound' }
|
||||
'422': { $ref: '#/components/responses/ValidationError' }
|
||||
put:
|
||||
tags: [Users]
|
||||
summary: Edycja użytkownika (admin)
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: '#/components/schemas/UserInput' }
|
||||
responses:
|
||||
'200':
|
||||
description: Zaktualizowano
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: '#/components/schemas/UserResponse' }
|
||||
'400': { $ref: '#/components/responses/BadRequest' }
|
||||
'401': { $ref: '#/components/responses/Unauthorized' }
|
||||
'403': { $ref: '#/components/responses/Forbidden' }
|
||||
'404': { $ref: '#/components/responses/NotFound' }
|
||||
'422': { $ref: '#/components/responses/ValidationError' }
|
||||
delete:
|
||||
tags: [Users]
|
||||
summary: Usuń użytkownika (admin)
|
||||
description: Nie można usunąć własnego konta.
|
||||
responses:
|
||||
'204': { description: Usunięto }
|
||||
'400': { $ref: '#/components/responses/BadRequest' }
|
||||
'401': { $ref: '#/components/responses/Unauthorized' }
|
||||
'403': { $ref: '#/components/responses/Forbidden' }
|
||||
'404': { $ref: '#/components/responses/NotFound' }
|
||||
|
||||
components:
|
||||
securitySchemes:
|
||||
bearerAuth:
|
||||
type: http
|
||||
scheme: bearer
|
||||
bearerFormat: JWT
|
||||
|
||||
parameters:
|
||||
id:
|
||||
name: id
|
||||
in: path
|
||||
required: true
|
||||
schema: { type: integer, example: 1 }
|
||||
page:
|
||||
name: page
|
||||
in: query
|
||||
schema: { type: integer, minimum: 1, default: 1 }
|
||||
limit:
|
||||
name: limit
|
||||
in: query
|
||||
schema: { type: integer, minimum: 1, maximum: 100, default: 20 }
|
||||
direction:
|
||||
name: direction
|
||||
in: query
|
||||
schema: { type: string, enum: [asc, desc], default: asc }
|
||||
carSort:
|
||||
name: sort
|
||||
in: query
|
||||
schema:
|
||||
type: string
|
||||
enum: [id, customer_id, make, model, production_year, registration_number, fuel_type, mileage, power_hp, created, modified]
|
||||
|
||||
responses:
|
||||
Unauthorized:
|
||||
description: Brak lub nieprawidłowy token / błędne dane logowania
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: '#/components/schemas/Error' }
|
||||
example: { success: false, error: { code: 401, message: Authentication is required to continue } }
|
||||
Forbidden:
|
||||
description: Brak uprawnień (wymagana rola admin)
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: '#/components/schemas/Error' }
|
||||
example: { success: false, error: { code: 403, message: This action requires the admin role. } }
|
||||
NotFound:
|
||||
description: Nie znaleziono rekordu
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: '#/components/schemas/Error' }
|
||||
example: { success: false, error: { code: 404, message: Record not found in table `customers`. } }
|
||||
BadRequest:
|
||||
description: Niedozwolona operacja
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: '#/components/schemas/Error' }
|
||||
ValidationError:
|
||||
description: Błędy walidacji (klucz = pole, wartość = reguła => komunikat)
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: '#/components/schemas/Error' }
|
||||
example:
|
||||
success: false
|
||||
error:
|
||||
code: 422
|
||||
message: Validation failed.
|
||||
fields:
|
||||
email: { _isUnique: This email is already in use. }
|
||||
phone: { _required: This field is required }
|
||||
CarList:
|
||||
description: OK
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
success: { type: boolean, example: true }
|
||||
data:
|
||||
type: array
|
||||
items: { $ref: '#/components/schemas/Car' }
|
||||
meta: { $ref: '#/components/schemas/PaginationMeta' }
|
||||
|
||||
schemas:
|
||||
Error:
|
||||
type: object
|
||||
properties:
|
||||
success: { type: boolean, example: false }
|
||||
error:
|
||||
type: object
|
||||
properties:
|
||||
code: { type: integer }
|
||||
message: { type: string }
|
||||
fields:
|
||||
type: object
|
||||
additionalProperties:
|
||||
type: object
|
||||
additionalProperties: { type: string }
|
||||
|
||||
PaginationMeta:
|
||||
type: object
|
||||
properties:
|
||||
page: { type: integer, example: 1 }
|
||||
limit: { type: integer, example: 20 }
|
||||
total: { type: integer, example: 100 }
|
||||
pages: { type: integer, example: 5 }
|
||||
has_next_page: { type: boolean, example: true }
|
||||
has_prev_page: { type: boolean, example: false }
|
||||
sort: { type: string, nullable: true, example: id }
|
||||
direction: { type: string, nullable: true, example: asc }
|
||||
|
||||
Role:
|
||||
type: string
|
||||
enum: [admin, user]
|
||||
|
||||
FuelType:
|
||||
type: string
|
||||
enum: [petrol, diesel, lpg, hybrid, electric]
|
||||
|
||||
# ---------- Users ----------
|
||||
User:
|
||||
type: object
|
||||
properties:
|
||||
id: { type: integer, readOnly: true, example: 1 }
|
||||
email: { type: string, format: email, example: admin@example.com }
|
||||
first_name: { type: string, example: Adam }
|
||||
last_name: { type: string, example: Administrator }
|
||||
role: { $ref: '#/components/schemas/Role' }
|
||||
active: { type: boolean, example: true }
|
||||
last_login: { type: string, format: date-time, nullable: true, readOnly: true }
|
||||
created: { type: string, format: date-time, readOnly: true }
|
||||
modified: { type: string, format: date-time, readOnly: true }
|
||||
UserInput:
|
||||
type: object
|
||||
properties:
|
||||
email: { type: string, format: email, maxLength: 255 }
|
||||
password: { type: string, format: password, minLength: 8, maxLength: 72 }
|
||||
first_name: { type: string, maxLength: 100 }
|
||||
last_name: { type: string, maxLength: 100 }
|
||||
role: { $ref: '#/components/schemas/Role' }
|
||||
active: { type: boolean }
|
||||
UserCreate:
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/UserInput'
|
||||
- type: object
|
||||
required: [email, password, first_name, last_name]
|
||||
example:
|
||||
email: jan.kowalski@example.com
|
||||
password: Haslo123!
|
||||
first_name: Jan
|
||||
last_name: Kowalski
|
||||
role: user
|
||||
active: true
|
||||
ProfileInput:
|
||||
type: object
|
||||
properties:
|
||||
email: { type: string, format: email }
|
||||
password: { type: string, format: password, minLength: 8 }
|
||||
first_name: { type: string }
|
||||
last_name: { type: string }
|
||||
example:
|
||||
first_name: Jan
|
||||
password: NoweHaslo123!
|
||||
UserResponse:
|
||||
type: object
|
||||
properties:
|
||||
success: { type: boolean, example: true }
|
||||
data: { $ref: '#/components/schemas/User' }
|
||||
|
||||
# ---------- Customers ----------
|
||||
CustomerInput:
|
||||
type: object
|
||||
properties:
|
||||
type:
|
||||
type: string
|
||||
enum: [individual, company]
|
||||
default: individual
|
||||
description: Dla `company` wymagane jest `company_name`
|
||||
first_name: { type: string, maxLength: 100, example: Anna }
|
||||
last_name: { type: string, maxLength: 100, example: Nowak }
|
||||
email: { type: string, format: email, maxLength: 255, description: Unikalny, example: anna.nowak@example.com }
|
||||
phone: { type: string, pattern: '^\+?[0-9 ()-]{6,30}$', example: '+48 600 100 200' }
|
||||
company_name: { type: string, nullable: true, maxLength: 255, example: null }
|
||||
tax_id: { type: string, nullable: true, pattern: '^[0-9]{10}$', description: NIP (10 cyfr), example: null }
|
||||
street: { type: string, nullable: true, maxLength: 255, example: ul. Długa 5/12 }
|
||||
city: { type: string, nullable: true, maxLength: 100, example: Kraków }
|
||||
postal_code: { type: string, nullable: true, pattern: '^[0-9]{2}-[0-9]{3}$', example: 30-001 }
|
||||
country: { type: string, pattern: '^[A-Z]{2}$', default: PL, description: ISO 3166-1 alpha-2, example: PL }
|
||||
birth_date: { type: string, format: date, nullable: true, example: '1985-04-12' }
|
||||
notes: { type: string, nullable: true, maxLength: 5000, example: Preferuje kontakt telefoniczny. }
|
||||
CustomerCreate:
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/CustomerInput'
|
||||
- type: object
|
||||
required: [first_name, last_name, email, phone]
|
||||
Customer:
|
||||
allOf:
|
||||
- type: object
|
||||
properties:
|
||||
id: { type: integer, readOnly: true, example: 1 }
|
||||
- $ref: '#/components/schemas/CustomerInput'
|
||||
- type: object
|
||||
properties:
|
||||
created_by: { type: integer, nullable: true, readOnly: true, description: ID użytkownika, który dodał klienta }
|
||||
created: { type: string, format: date-time, readOnly: true }
|
||||
modified: { type: string, format: date-time, readOnly: true }
|
||||
CustomerWithCars:
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/Customer'
|
||||
- type: object
|
||||
properties:
|
||||
cars:
|
||||
type: array
|
||||
items: { $ref: '#/components/schemas/Car' }
|
||||
CustomerResponse:
|
||||
type: object
|
||||
properties:
|
||||
success: { type: boolean, example: true }
|
||||
data: { $ref: '#/components/schemas/Customer' }
|
||||
|
||||
# ---------- Cars ----------
|
||||
CarFields:
|
||||
type: object
|
||||
properties:
|
||||
make: { type: string, maxLength: 50, example: Toyota }
|
||||
model: { type: string, maxLength: 50, example: Corolla }
|
||||
production_year: { type: integer, minimum: 1900, example: 2020 }
|
||||
vin:
|
||||
type: string
|
||||
pattern: '^[A-HJ-NPR-Z0-9]{17}$'
|
||||
description: 17 znaków, bez liter I, O, Q. Unikalny. Zapisywany wielkimi literami.
|
||||
example: JTDBR32E720123456
|
||||
registration_number:
|
||||
type: string
|
||||
description: 4-10 liter/cyfr. Unikalny. Spacje są usuwane, litery zamieniane na wielkie.
|
||||
example: KR12345
|
||||
fuel_type: { $ref: '#/components/schemas/FuelType' }
|
||||
color: { type: string, nullable: true, maxLength: 30, example: srebrny }
|
||||
engine_capacity: { type: integer, nullable: true, minimum: 0, maximum: 10000, description: Pojemność w cm³, example: 1798 }
|
||||
power_hp: { type: integer, nullable: true, minimum: 1, maximum: 2000, description: Moc w KM, example: 122 }
|
||||
transmission: { type: string, nullable: true, enum: [manual, automatic], example: automatic }
|
||||
mileage: { type: integer, nullable: true, minimum: 0, description: Przebieg w km, example: 45000 }
|
||||
notes: { type: string, nullable: true, maxLength: 5000, example: null }
|
||||
CarInput:
|
||||
allOf:
|
||||
- type: object
|
||||
properties:
|
||||
customer_id: { type: integer, example: 1 }
|
||||
- $ref: '#/components/schemas/CarFields'
|
||||
CarCreate:
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/CarInput'
|
||||
- type: object
|
||||
required: [customer_id, make, model, production_year, vin, registration_number, fuel_type]
|
||||
CarCreateNested:
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/CarFields'
|
||||
- type: object
|
||||
required: [make, model, production_year, vin, registration_number, fuel_type]
|
||||
Car:
|
||||
allOf:
|
||||
- type: object
|
||||
properties:
|
||||
id: { type: integer, readOnly: true, example: 1 }
|
||||
- $ref: '#/components/schemas/CarInput'
|
||||
- type: object
|
||||
properties:
|
||||
created: { type: string, format: date-time, readOnly: true }
|
||||
modified: { type: string, format: date-time, readOnly: true }
|
||||
CarWithCustomer:
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/Car'
|
||||
- type: object
|
||||
properties:
|
||||
customer: { $ref: '#/components/schemas/Customer' }
|
||||
CarResponse:
|
||||
type: object
|
||||
properties:
|
||||
success: { type: boolean, example: true }
|
||||
data: { $ref: '#/components/schemas/Car' }
|
||||
Reference in New Issue
Block a user