Przejdź do treści

API REST

Aplikacja komunikuje się z serwerem Part-DB przez REST API w formacie JSON-LD / Hydra. Wszystkie żądania uwierzytelniane są tokenem Bearer.


Uwierzytelnianie

Każde żądanie zawiera nagłówek:

Authorization: Bearer <token>

Token pobierany jest z Flutter Secure Storage przy każdym uruchomieniu aplikacji. Przy logowaniu OAuth (Part-DB 2.15+) token dostępu jest odświeżany automatycznie przed wygaśnięciem; równoległe żądania czekają na jedno wspólne odświeżenie, a odpowiedź 401 powoduje jedno odświeżenie i ponowienie żądania.

Każde żądanie wysyła Accept: application/ld+json. Kolekcje w czystym application/json nie zawierają linków paginacji, więc aplikacja widziałaby tylko pierwszą stronę.


Wspólne parametry

Parametr Opis
itemsPerPage Maksymalna liczba wyników na stronę (domyślnie 30 w Part-DB)
hydra:view / view Paginacja – zawiera hydra:next (next) ze ścieżką następnej strony
hydra:member / member Tablica wyników w odpowiedzi kolekcji (obsługiwany JSON-LD z prefiksem i bez)

Timeouty

Typ żądania Timeout
Standardowe (GET/PATCH) 10 s
Upload załącznika (POST) 30 s

Endpointy

Weryfikacja tokenu

GET /api/tokens/current
Authorization: Bearer <token>

Odpowiedź 200:

{
  "id": 5,
  "user": "/api/users/3",
  "name": "scanner",
  ...
}

Używane przez ekran Konfiguracja do sprawdzenia tokenu API. Endpoint zna tylko tokeny API i dla tokenów OAuth zwraca 403, dlatego po logowaniu OAuth aplikacja sprawdza dostęp przez GET /api/parts?itemsPerPage=1, a nazwę użytkownika i przyznane zakresy odczytuje z tokena dostępu (JWT: sub, scopes).


Wyszukiwanie po IPN

GET /api/parts?ipn={ipn}

Odpowiedź:

{
  "hydra:member": [
    { "id": 42, "name": "Rezystor 10k", "ipn": "1234567", ... }
  ]
}

Używane gdy scanned/wpisany kod to dokładnie 7 cyfr.


Wyszukiwanie tekstowe

GET /api/parts?name=%25{query}%25&itemsPerPage=100
GET /api/parts?ipn=%25{query}%25&itemsPerPage=100
GET /api/parts?manufacturer_product_number=%25{query}%25&itemsPerPage=100
GET /api/parts?description=%25{query}%25&itemsPerPage=100

LikeFilter w Part-DB porównuje dokładnie, jeśli nie użyje się symboli %, dlatego zapytanie jest opakowane w %…%. Cztery żądania idą równolegle, a wyniki są łączone bez duplikatów (max 300 na pole).

Wyszukiwanie po wartości parametru

Odpowiedzi kolekcji zawierają tylko nazwy parametrów, a parametry nie mają endpointu kolekcji. Tryb „Value” pobiera więc GET /api/parts/{id} dla części z parametrami i zapisuje wartości w pamięci podręcznej na urządzeniu, kluczowanej polem lastModified. Dodatkowe żądania kosztuje tylko pierwsze wyszukiwanie (lub części zmienione od tego czasu).


Pobieranie wszystkich części

GET /api/parts?itemsPerPage=100

Aplikacja podąża za hydra:view.hydra:next aż do zebrania wszystkich rekordów. Używane przez Generator IPN, wyszukiwanie po parametrach i ekran przeglądu.

Baner niskiego stanu pobiera tylko części z ustawionym stanem minimalnym: GET /api/parts?minamount[gt]=0.


Szczegóły części

GET /api/parts/{id}

Odpowiedź (fragment):

{
  "id": 42,
  "name": "Rezystor 10k",
  "ipn": "1234567",
  "minamount": 10,
  "description": "...",
  "comment": "...",
  "category": "/api/categories/5",
  "manufacturer": "/api/manufacturers/3",
  "tags": "smd,resistor",
  "partLots": [
    { "id": 7, "amount": 12.0, "storageLocation": "/api/storage_locations/2" }
  ],
  "parameters": [
    { "id": 101, "name": "Wartość", "value": "10k", "unit": "Ω" }
  ]
}

Note

Ilości są liczbami zmiennoprzecinkowymi (metry, gramy…) i aplikacja nigdy ich nie zaokrągla. Partie z instock_unknown nie wliczają się do sumy i wyłączają ostrzeżenie o niskim stanie.


Aktualizacja partii magazynowej

PATCH /api/part_lots/{id}
Content-Type: application/merge-patch+json

{
  "amount": 15,
  "comment": "[2026-09-27] Dostawa TME\npoprzedni komentarz…",
  "last_stocktake_at": "2026-09-27T10:00:00Z"
}

Odpowiedź 200: zaktualizowany obiekt PartLot.

  • comment jest wysyłany tylko, gdy użytkownik wpisał notatkę: datowana linia jest dopisywana na początku istniejącego komentarza partii (API Part-DB nie pozwala dołączyć komentarza do wpisu w dzienniku zdarzeń).
  • last_stocktake_at wysyła Inwentaryzacja dla każdej policzonej partii, także bez rozbieżności.
  • Pole description partii nigdy nie jest modyfikowane.

Aktualizacja parametru

PATCH /api/parameters/{id}
Content-Type: application/merge-patch+json

{
  "value_text": "SOT-223"
}

Wartość zapisywana jest do pola, z którego pochodzi: value_text dla parametrów tekstowych, value_typical (liczba) dla pojedynczych wartości liczbowych. Parametry-zakresy (value_min/value_max) są w aplikacji tylko do odczytu.


Nadanie IPN

PATCH /api/parts/{id}
Content-Type: application/merge-patch+json

{
  "ipn": "3847291"
}

Pobieranie kategorii

GET /api/categories?itemsPerPage=200

Aplikacja pobiera do 200 kategorii stronicując przez hydra:next. Używane przez Przeglądarkę kategorii.

Odpowiedź (fragment):

{
  "hydra:member": [
    { "id": 1, "name": "Rezystory", "parent": null },
    { "id": 2, "name": "SMD", "parent": "/api/categories/1" }
  ]
}


Pobieranie typów załączników

GET /api/attachment_types?itemsPerPage=1

Pobiera pierwszy dostępny typ załącznika do użycia przy uploadzie zdjęcia.


Upload załącznika (zdjęcie)

POST /api/attachments
Content-Type: application/ld+json
Authorization: Bearer <token>

{
  "name": "Zdjęcie - Rezystor 10k",
  "element": "/api/parts/42",
  "attachment_type": "/api/attachment_types/1",
  "upload": {
    "data": "data:image/jpeg;base64,/9j/4AAQSkZJRgAB...",
    "filename": "Rezystor_10k_1727430000000.jpg",
    "private": false,
    "becomePreviewIfEmpty": true
  }
}

Part-DB wymaga pola attachment_type; jeśli na serwerze nie ma żadnego typu załącznika, upload jest odrzucany z czytelnym komunikatem.

Odpowiedź 201: obiekt załącznika.

Zdjęcie jest pobierane z aparatu lub galerii, kompresowane do JPEG i kodowane base64 bezpośrednio w body żądania.


Obsługa błędów

Aplikacja parsuje odpowiedzi błędów w następującej kolejności:

  1. Pole hydra:description
  2. Tablica violations[].message (błędy walidacji)
  3. Pole detail
  4. Tekst statusu HTTP

Błędy wyświetlane są użytkownikowi przez SnackBar.

// Przykładowa odpowiedź błędu walidacji (422)
{
  "@type": "ConstraintViolationList",
  "violations": [
    { "propertyPath": "ipn", "message": "This value is already used." }
  ]
}