Przejdź do treści

Zwierzaki — przebieg integracji

Ścieżki są względne wobec /partner/v1/pets — poza tworzeniem i edycją zwierzaka, które trafiają wprost w /partner/v1/pets i są tu zapisane pełną ścieżką. Uwierzytelnienie jak w pozostałych modułach: x-client-id, x-api-key, x-user-id.

Dokument opisuje profil zwierzaka i jego cykl życia. Książeczka zdrowia — leczenia cykliczne, wizyty, leki i oś czasu — jest opisana osobno.

Zasada ogólna

Zwierzak jest punktem zaczepienia dla całej reszty integracji: identyfikator zwrócony przy jego utworzeniu wraca potem w kalkulatorze żywieniowym, prediagnozie i książeczce zdrowia.

Profil opiera się na naszych słownikach — gatunek, rasa, płeć, kastracja, przedział wiekowy i budowa są wybierane z list, a nie wpisywane tekstem.

Krok 1 — dane słownikowe

Jednym wywołaniem pobiera się komplet list do formularza:

GET /pets-profile-relations
{ "genders":    [ { "value": "…", "label": "Samiec" } ],
  "species":    [ { "value": "…", "label": "Pies" } ],
  "colors":     [  ],
  "castration": [  ],
  "age":        [  ],
  "build":      [  ] }

Rasy zależą od gatunku, więc pobiera się je dopiero po jego wyborze:

GET /races-list/{speciesId}

Zwraca { id, label, order }order służy do wyróżnienia najpopularniejszych ras na początku listy.

Dostępne jest też GET /species-list, jeśli potrzebne są same gatunki bez reszty formularza.

Krok 2 — sprawdzenie numeru chipa

GET /check-chip?chip=616093900123456
GET /check-chip?chip=616093900123456&pet_id={petId}     — przy edycji

Numer mikroczipa jest unikalny w całym systemie. Endpoint zwraca true, gdy numer jest wolny, albo 409, gdy jest już przypisany do innego zwierzęcia.

Parametr pet_id wyklucza z porównania samego edytowanego zwierzaka — bez niego edycja zwierzaka z niezmienionym chipem zgłosiłaby konflikt sama ze sobą.

Krok 3 — utworzenie zwierzaka

POST /partner/v1/pets
{ "name": "Burek",
  "gender": "<id>", "species_id": "<id>", "race_id": "<id>", "castration": "<id>",
  "age": "<id>", "build": "<id>",
  "weight": 12.5, "chip": "616093900123456", "birth_date": "2021-04-02" }
Pole Wymagane Skąd wartość
name tak
species_id tak GET /pets-profile-relations
race_id tak GET /races-list/{speciesId}
gender tak GET /pets-profile-relations
build tak GET /pets-profile-relations
age tak GET /pets-profile-relations
castration tak GET /pets-profile-relations
color nie GET /pets-profile-relations
weight nie kilogramy
birth_date nie data
chip nie numer mikroczipa, unikalny w całym systemie
image_id, image_src nie zdjęcie — patrz niżej

Innych pól nie przyjmujemy: nieznana nazwa kończy się 400.

species_id i race_id trzeba przekazać oba. Gatunek nie jest wyprowadzany z rasy — zapisujemy dokładnie to, co przyjdzie w żądaniu. Zwierzak bez gatunku nie przejdzie przez kalkulator żywieniowy, a prediagnoza zada mu komplet pytań zamiast skróconej ścieżki.

Sprawdzamy też, czy rasa należy do podanego gatunku; niezgodność kończy się 400.

Zdjęcie zwierzaka wgrywa się wcześniej ścieżką plików z purpose: "pet_avatar", a z potwierdzenia przekazuje się tutaj id jako image_id i path jako image_src.

Zwierzak zostaje przypisany do użytkownika z nagłówka x-user-id jako jego główny właściciel.

Krok 4 — odczyt

GET /pets-list?page=0&take=20
GET /pets-deceased-list?page=0&take=20
GET /profile/{petId}

Stronicowanie jest liczone od zerapage=0 to pierwsza strona. take domyślnie 20, maksymalnie 100. Odpowiedź listy zawiera total z pełną liczbą zwierząt, więc liczbę stron wylicza się po swojej stronie.

Lista zwraca dane skrócone: identyfikator, imię, zdjęcie, is_main_owner i status. Pełne dane — z rozwiniętymi słownikami — daje dopiero profile/{petId}: gatunek, rasa, płeć, kastracja, wiek, budowa i kolor przychodzą tam jako obiekty z nazwą w języku żądania, a nie same identyfikatory.

Zwierzaki oznaczone jako zmarłe nie pojawiają się na zwykłej liście — mają własną.

Krok 5 — edycja

PATCH /partner/v1/pets/{petId}
{ "name": "Burek",
  "species_id": "<id>", "race_id": "<id>", "gender": "<id>",
  "build": "<id>", "age": "<id>", "castration": "<id>",
  "weight": 13.1, "chip": "616093900123456" }

Edycja przyjmuje dokładnie ten sam zestaw pól co tworzenie. Mimo metody PATCH żądanie nie jest częściowe: pola wymagane trzeba przesłać za każdym razem, nawet gdy się nie zmieniają.

Przy edycji dochodzą do nich chip i weight — te dwa pola są zapisywane bezwarunkowo, więc ich pominięcie skasowałoby dotychczasową wartość. Zamiast kasować po cichu, wymagamy ich obecności: wartość albo pusty łańcuch ("") lub null, jeśli mają zostać wyczyszczone. W formularzu wystarczy więc zwykłe pole tekstowe z pustą wartością domyślną.

Pozostałe pola opcjonalne — color, birth_date, image_id, image_src — pominięte zachowują dotychczasową wartość.

W praktyce: GET /profile/{petId}, podmiana zmienianych wartości, odesłanie kompletu.

Gatunek i rasa są sprawdzane tak samo jak przy tworzeniu — rasa musi należeć do podanego gatunku.

Edycja wymaga, by użytkownik był głównym właścicielem zwierzaka.

Zakończenie i usunięcie — dwie różne operacje

DELETE /kill?id={petId}
DELETE /delete?id={petId}

kill oznacza zwierzaka jako zmarłego — ustawia datę śmierci. Znika ze zwykłej listy, pojawia się na liście zmarłych, a cała historia medyczna zostaje nietknięta. Zwraca zaktualizowany profil.

delete usuwa powiązanie użytkownika ze zwierzakiem, a nie sam wpis. Zwraca { "count": 1 } — liczbę usuniętych powiązań, nie usuniętych zwierząt.

Obie wymagają uprawnień głównego właściciela.

Domyślny weterynarz

Zwierzakowi można przypisać weterynarza z naszej bazy:

GET   /search-vet?phrase=kowalski
PATCH /set-vet-default   { "pet_id": "…", "vet_id": "…" }
GET   /pet-default-vet/{petId}

Wyszukiwarka zwraca { vet: { id, label }, clinique }, gdzie label to imię i nazwisko, a clinique — nazwa i miasto placówki, jeśli weterynarz jest do którejś przypisany.

Przekazanie pustego vet_id w set-vet-default usuwa przypisanie.

Brak przypisanego weterynarza to pusta odpowiedź

pet-default-vet/{petId} odpowiada wtedy 200 z pustym ciałem — zero bajtów, a nie null ani {}. To nie jest błąd, ale response.json() się na tym wywraca, więc odpowiedź trzeba sprawdzić przed parsowaniem:

const res = await fetch(url, { headers });
const text = await res.text();
const vet = text ? JSON.parse(text) : null;

Po przypisaniu weterynarza endpoint zwraca normalny obiekt.

Aktywny zwierzak

POST /set-pet-active   { "id": "{petId}" }

Zaznacza, którego zwierzaka pokazywać domyślnie, gdy użytkownik ma ich kilka. Wartość wraca jako is_default_pet na liście zwierząt. Zwraca { "count": 1 }.

Jest to wyłącznie preferencja wyświetlania — nie wpływa na dostęp ani na dane.

Najczęstsze przyczyny błędów

Objaw Przyczyna
409 przy tworzeniu lub edycji Numer chipa jest już przypisany do innego zwierzęcia
409 przy edycji z niezmienionym chipem Pominięto pet_id w check-chip
403 przy edycji, kill lub delete Użytkownik nie jest głównym właścicielem
400 przy edycji jednego pola PATCH nie jest częściowy — komplet pól wymaganych trzeba dosłać za każdym razem
Chip albo waga zniknęły po edycji Nie przesłano ich w żądaniu — przy edycji są wymagane
Pusta lista mimo istniejących zwierząt Zwierzaki oznaczone jako zmarłe — patrz pets-deceased-list
400 przy tworzeniu lub edycji Rasa nie należy do podanego gatunku
400 z „property … should not exist" Pole spoza zestawu, np. passport czy behaviour
Kalkulator żywieniowy odrzuca zwierzaka Powstał bez species_id — oba pola są wymagane
delete nie usunął zwierzaka Usuwa powiązanie z użytkownikiem, nie sam wpis
Błąd parsowania przy pet-default-vet Brak weterynarza to puste ciało odpowiedzi, nie null

Przykładowa sekwencja

GET  /partner/v1/pets/pets-profile-relations       → listy wyboru
GET  /partner/v1/pets/races-list/{speciesId}       → rasy dla wybranego gatunku
GET  /partner/v1/pets/check-chip?chip=…            → czy numer wolny
POST /partner/v1/pets                              → { id }

GET  /partner/v1/pets/pets-list?page=0&take=20
GET  /partner/v1/pets/profile/{petId}
PATCH /partner/v1/pets/{petId}                     → aktualizacja (ten sam komplet pól)