Konwencje techniczne
Konwencje API są zbieżne z założeniami REST API – Założenia v1.0 (pharmind XF). Poniżej zastosowanie tych założeń w kontekście naszego systemu; elementy niewymienione w założeniach pozostają do doprecyzowania przez analityków.
1. Założenia ogólne
- W elementach API (ścieżki, nazwy pól, komunikaty) rekomendowane jest język angielski.
2. Adresy bazowe (Base URL)
| Element | Opis (do uzupełnienia) |
|---|---|
| Wzorzec URL | Np. https://<środowisko>.<domena>/api — do doprecyzowania |
| Środowiska | Produkcja, test, dev — do uzupełnienia |
| Uwagi | Punkt wejścia API, ewentualne prefixy — do doprecyzowania |
3. Nazewnictwo endpointów
3.1 Ogólne zasady
- Nazwy zasobów: proste, czytelne, odzwierciedlające reprezentowane dane.
- Rzeczowniki w liczbie mnogiej:
/users,/providers,/purchase-orders,/companies. - Liczba pojedyncza tylko dla zasobów jednoelementowych:
/profile,/status.
3.2 Konwencje zapisu
- Kebab-case w ścieżkach:
/medical-products,/purchase-orders,/goods-receipts. - Brak czasowników w endpointach — operacje reprezentują metody HTTP.
- Standardowe operacje:
GET /v1/<resource>POST /v1/<resource>PUT /v1/<resource>DELETE /v1/<resource>
3.3 Operacje niestandardowe
- Prefiks
$: np.POST /v1/reservation/{id}/$confirm-presence.
3.4 Hierarchia zasobów
- Zagnieżdżenia:
/departments/{id}/employees. - Unikać głębokich struktur — preferować filtry:
/products?user_id={userId}.
3.5 Parametry zapytań
- Snake_case:
user_id,search_query,start_date,end_date. - Parametry jednoznaczne.
3.6 Bezpieczeństwo
- Nie umieszczać wrażliwych danych w ścieżkach endpointów.
4. Wersjonowanie API
- Wersja w ścieżce:
/v1/users,/v1/purchase-orders. - Numeracja wersji: liczby całkowite (1, 2, 3…).
- Zasady zmian (breaking vs non-breaking, deprecation) — do uzupełnienia.
5. Autentykacja
- Model: Do uzupełnienia: np. OAuth 2.0, API key — wybór i uzasadnienie.
- Przepływ: Np. client credentials, resource owner — do doprecyzowania.
- Nagłówek:
Authorization: Bearer <token>(lub inny schemat po doprecyzowaniu). - Rejestracja aplikacji: Gdzie i w jakiej formie — do doprecyzowania.
6. Nagłówki HTTP
| Nagłówek | Wartość / uwagi |
|---|---|
| Authorization | Bearer <token> |
| Content-Type | application/json (request: POST/PUT/PATCH) |
| Accept | application/json (response) |
| Własne nagłówki | Prefiks ks-; małe litery, wyrazy oddzielone myślnikami: ks-client, ks-system-architecture. Spójnie w całym API. |
| Inne | Idempotency key, request-id — do doprecyzowania |
7. Metoda PATCH (częściowa aktualizacja)
- Jeden endpoint PATCH na zasób: np.
PATCH /v1/invoices/{id}. - Body: obiekt JSON zawierający tylko pola do zmiany. Nie wysyłamy całego zasobu ani tablicy operacji.
- Content-Type:
application/json. - Przykład — zmiana tagów i statusu w jednym wywołaniu:
8. Paginacja i filtrowanie
- Mechanizm: Np.
page,page_size(snake_case) lub cursor — do doprecyzowania. - Limit domyślny / max: Do uzupełnienia.
- Oznaczenie kolejnej strony: Np.
next_page_token,nextLink— do uzupełnienia. - Filtrowanie/sortowanie: parametry zapytań w snake_case (zgodnie z p. 3.5).
9. Obsługa błędów (Problem Details)
- Błędy sygnalizujemy odpowiednimi statusami HTTP.
- Format błędów: RFC 7807 Problem Details.
- Pola w odpowiedzi błędu:
status(numer HTTP)type(URI odwołania do typu błędu)title(krótki tytuł)detail(szczegóły)instance(ścieżka żądania)- Zalecenie dla klientów: sprawdzać status HTTP i parsować body błędu; logować
instance/ correlationId do wsparcia.
10. Statusy HTTP
- Sukces: 200 OK, 201 Created, 202 Accepted, 204 No Content.
- Błędy klienta: 400 Bad Request, 401 Unauthorized, 403 Forbidden, 404 Not Found, 409 Conflict, 422 Unprocessable Entity.
- Limity i serwer: 429 Too Many Requests, 500 Internal Server Error.
11. Modele Request i Response
- Format: JSON. Request:
Content-Type: application/json; response:application/json. - Nazwy pól w JSON: camelCase (spójnie w całym API).
- POST/PUT: body — obiekt z polami wymaganymi i opcjonalnymi zgodnie z operacją.
- PATCH: body — tylko pola do aktualizacji (zgodnie z sekcją 7).
- Nie umieszczać w body danych wrażliwych, które powinny być w nagłówkach lub chronione inaczej.
- Definicje pól, typów i wymagalności — w specyfikacji API (np. OpenAPI); niniejsze konwencje określają kształt (camelCase, PATCH = tylko zmieniane pola).
11a. DomainResource — Model bazowy dla wszystkich zasobów biznesowych (wzorowanie na FHIR)
Wszystkie zasoby biznesowe w API.ERP (Document, Invoice, InventoryDocument, Party, Employment, Ledger, itp.) dziedziczą z abstrakcyjnego modelu DomainResource (wzorowany na FHIR DomainResource). Zapewnia to spójność, rozszerzalność i compliance ze standardem Kamsoft.FAIR (Fast Adaptive Interoperable Resources): zasoby są Findable (identyfikatory), Accessible (CRUD endpoints), Interoperable (Reference + słowniki kodowe), Reusable (DomainResource inheritance) we wszystkich domenach.
11a.1 Struktura DomainResource
Każdy zasób biznesowy zawiera:
| Pole | Typ | Opis | Wymagane |
|---|---|---|---|
id |
string | Unikatowy identyfikator zasobu w API (zazwyczaj nadawany przez serwer) | Tak (na GET) |
meta |
object | Metadane zasobu: lastModified (datetime), version, profile, itd. |
Opcjonalnie |
identifier |
Identifier[] | Tablica identyfikatorów z różnych systemów (wewnętrzny id, numer z ERP, itp.) — patrz sekcja 12.1 | Opcjonalnie |
status |
CodeableConcept | Status zasobu (np. active, inactive, draft, finalized) — semantyka zależy od typu zasobu | Opcjonalnie |
type |
CodeableConcept | Typ zasobu (np. rodzaj dokumentu, rodzaj Party, rodzaj produktu) — semantyka zależy od modelu | Opcjonalnie |
11a.2 Dziedziczenie i specjalizacja
- Konkretne zasoby (Document, Invoice, EmploymentRecord, itp.) rozszerzają DomainResource, dodając pola specyficzne dla danej domeny.
- Przykład:
Invoice extends DomainResource, dodając pola specyficzne:issueDate,saleDate,dueDate,seller,buyer,totalNet,totalVat,totalGross,lines[],ksefAcquisitionDate. - Przykład:
InventoryDocument extends DomainResource, dodając:movementType,fromLocation,toLocation,product[],quantity[]. - W JSON Schema: wykorzystujemy
allOfz referencją doDomainResource.schema.json+ pola dodatkowe.
Przykład w OpenAPI/JSON Schema:
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "Invoice",
"allOf": [
{ "$ref": "#/components/schemas/DomainResource" },
{
"type": "object",
"properties": {
"issueDate": { "type": "string", "format": "date" },
"seller": { "$ref": "#/components/schemas/Reference" },
"buyer": { "$ref": "#/components/schemas/Reference" },
"totalNet": { "$ref": "#/components/schemas/Money" },
"totalVat": { "$ref": "#/components/schemas/Money" },
"totalGross": { "$ref": "#/components/schemas/Money" },
"lines": {
"type": "array",
"items": { "$ref": "#/components/schemas/InvoicePosition" }
}
}
}
]
}
11a.3 Korzyści z DomainResource
- Spójność: Wszystkie zasoby mają wspólne pola rdzeniowe (id, meta, identifier, attribute, status, type).
- Rozszerzalność: Rozszerzanie modelu realizujemy przez
attribute[]oraz profile zasobów. - FAIR compliance:
- Findable:
identifier[]wspiera wiele systemów identyfikacji - Accessible: wszystkie zasoby dostępne via standard CRUD endpoints
- Interoperable:
Reference[]wspiera linki pomiędzy zasobami - Reusable: struktura spójna dla wszystkich domen
- FHIR kompatybilność: Ułatwia interoperacyjność z systemami zdrowotnotnymi (jeśli potrzebna).
11a.4 Reference (Odniesienia między zasobami)
Pola typu Reference (np. seller, buyer, partOf) zawierają:
| Pole | Typ | Opis |
|---|---|---|
reference |
string | Ścieżka zasobu (np. Party/123 lub pełny URL) |
display |
string (opcjonalnie) | Tekst czytelny dla człowieka (cached copy) |
Patrz sekcja 12 — Reference jest też dostępnym typem w Identifier.type i innych polach.
12. Rozszerzalna identyfikacja: Identifier i Coding (wzorowane na FHIR)
Wszystkie modele (zasoby) w API mogą — a w wielu przypadkach powinny — zawierać rozszerzalną identyfikację inspirowaną FHIR: Identifier (identyfikatory z różnych systemów) oraz Coding (kody z systemów terminologicznych). Umożliwia to wielozakresową identyfikację i klasyfikację bez sztywnego schematu na poziomie API.
12.1 Identifier (identyfikator)
Pozwala opisać jeden lub wiele identyfikatorów zasobu (np. wewnętrzny ID, numer dokumentu z ERP, identyfikator z systemu zewnętrznego). Pola w camelCase:
| Pole | Typ | Opis |
|---|---|---|
use |
string (opcjonalnie) | Kontekst użycia: usual, official, temp, secondary — do doprecyzowania wartości |
type |
Coding lub obiekt (opcjonalnie) | Typ identyfikatora (np. „numer zamówienia”, „numer kontrahenta”) |
system |
string (URI) | Przestrzeń nazw identyfikatora (np. https://api.example.com/identifiers/order-number) |
value |
string | Wartość identyfikatora |
period |
obiekt (opcjonalnie) | Okres ważności: start, end (np. ISO 8601) |
assigner |
string / referencja (opcjonalnie) | Kto lub jaki system przypisał identyfikator |
Zasób może mieć tablicę identifiers (np. identifiers: [{ system, value }, ...]). Minimalny użyteczny zestaw: system + value.
12.2 Coding (kod z systemu terminologicznego)
Pozwala przypisać zasobowi kody z zewnętrznych lub wewnętrznych słowników (np. typ dokumentu, status, jednostka miary). Pola w camelCase:
| Pole | Typ | Opis |
|---|---|---|
system |
string (URI) | System kodów (np. https://api.example.com/codes/document-type) |
version |
string (opcjonalnie) | Wersja systemu kodów |
code |
string | Symbol kodu |
display |
string (opcjonalnie) | Tekst czytelny dla człowieka |
userSelected |
boolean (opcjonalnie) | Czy użytkownik wybrał ten kod z listy |
Zasób może mieć pola typu Coding (pojedynczy kod) lub CodeableConcept: obiekt z tablicą coding i opcjonalnym text (tekst swobodny). Przykład: documentType: { coding: [{ system: "...", code: "INV", display: "Invoice" }], text: "Invoice" }.
12.3 Zastosowanie w modelach
- Identifier: np.
PurchaseOrder.identifiers,Customer.identifiers— wiele identyfikatorów (wewnętrzny id, numer po stronie dostawcy, numer w systemie księgowym). - Coding / CodeableConcept: np.
statusjako Coding,documentType,unit,category— wszędzie, gdzie potrzebna jest klasyfikacja z możliwością rozszerzenia o nowe systemy kodów.
Szczegóły per zasób (które pola są wymagane, które opcjonalne, dopuszczalne wartości use i system) — do doprecyzowania w api-contracts.md i specyfikacji OpenAPI.
12.4 Wyszukiwanie po identyfikatorze biznesowym (query parameter ?identifier=)
Identifier to parametr filtrujący, przekazywany jako lista par system|wartość, rozdzielonych przecinkami.
Wszystkie kolekcyjne GET endpoints (np. GET /v1/parties, GET /v1/invoices, GET /v1/product-definitions) wspierają wyszukiwanie po identyfikatorze biznesowym poprzez parametr zapytania ?identifier.
Format
system— URI przestrzeni nazw identyfikatora (np.urn:pl:nip,https://api.example.com/identifiers/order-number)|(pipe) — separator między systemem a wartością,(przecinek) — separator między wieloma parami system|value
Przykłady
-
Parametr w zapytaniu — wiele par system|wartość
Zwraca zasoby, które mają identyfikator pasujący do którejkolwiek z podanych par (system + value). -
Wyszukanie Party (kontrahenta) po NIP (Numerze Identyfikacji Podatkowej)
Zwraca zasoby Party z identyfikatorem w systemieurn:pl:nipo wartości9542685559. -
Wyszukanie Party po NIP lub OID
Zwraca zasoby Party pasujące do KTÓREGOKOLWIEK z podanych identyfikatorów (logika OR między wartościami). -
Wyszukanie Invoice (faktury) po numerze KSeF i numerze wewnętrznym
Szuka Invoice pasujących do któregoś z identyfikatorów (OR logic) I statusem issued (AND między filtrami).
Logika wyszukiwania
- Wiele identyfikatorów w jednym
?identifier=: logika OR — zwraca zasoby pasujące do któregokolwiek identyfikatora. - Inne filtry (
?status=,?type=, itp.) łączą się zidentifier: logika AND — zwracane zasoby spełniają zarówno warunek identyfikatora, jak i inne filtry. - Brak wyniku: Gdy identyfikator nie matches żaden zasób, API zwraca 200 OK z pustą listą (
items: []), nie 404.
Implementacja
- Parametr
identifierjest dostępny na wszystkich GET endpoints kolekcji (zasoby biznesowe). - OpenAPI spec definiuje parametr w
components.parameters.Identifieri referencjonuje go via$refw każdym GET na kolekcję. - Backend: przy resolucji
identifier— szukać w tablicyresource.identifier[]każdego zasobu, sprawdzaćsystemivalue. - URL encoding: Separatory (
|,,) muszą być HTML encoded w URL (%7cdla|,,może pozostać lub być%2c).
13. Idempotency
- Cel: Uniknięcie duplikatów przy retry (np. tworzenie zamówienia, faktury).
- Mechanizm: Nagłówek idempotency key / pole w body / zewnętrzny identyfikator — do doprecyzowania.
- Zasady: Retry z tym samym kluczem = ten sam efekt — do uzupełnienia dla wybranych operacji.
- Idempotency key można reprezentować także jako Identifier (sekcja 12) z odpowiednim
system(np.https://api.example.com/identifiers/idempotency-key).