Przejdź do treści

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:
{
  "tags": ["tag1", "tag2"],
  "documentProcessingStatus": "Processed",
  "processingSystem": "ERP"
}

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 allOf z referencją do DomainResource.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. status jako 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

?identifier=system1|value1,system2|value2[,...]
  • 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

  1. Parametr w zapytaniu — wiele par system|wartość

    ?identifier=system1|val1,system2|val2
    
    Zwraca zasoby, które mają identyfikator pasujący do którejkolwiek z podanych par (system + value).

  2. Wyszukanie Party (kontrahenta) po NIP (Numerze Identyfikacji Podatkowej)

    GET /v1/parties?company=1234567890&identifier=urn:pl:nip|9542685559
    
    Zwraca zasoby Party z identyfikatorem w systemie urn:pl:nip o wartości 9542685559.

  3. Wyszukanie Party po NIP lub OID

    GET /v1/parties?company=1234567890&identifier=urn:pl:nip|9542685559,urn:oid|1.1.960959.145959
    
    Zwraca zasoby Party pasujące do KTÓREGOKOLWIEK z podanych identyfikatorów (logika OR między wartościami).

  4. Wyszukanie Invoice (faktury) po numerze KSeF i numerze wewnętrznym

    GET /v1/invoices?company=1234567890&identifier=https%3A%2F%2Fksef.mf.gov.pl%2F|ABC123,internal|FAK-2026-001&status=issued
    
    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ę z identifier: 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 identifier jest dostępny na wszystkich GET endpoints kolekcji (zasoby biznesowe).
  • OpenAPI spec definiuje parametr w components.parameters.Identifier i referencjonuje go via $ref w każdym GET na kolekcję.
  • Backend: przy resolucji identifier — szukać w tablicy resource.identifier[] każdego zasobu, sprawdzać system i value.
  • URL encoding: Separatory (|, ,) muszą być HTML encoded w URL (%7c dla |, , 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).