Przejdź do treści

Kalkulator żywieniowy — przebieg integracji

Wszystkie ścieżki poniżej są względne wobec /partner/v1/nutrition-calculators. Uwierzytelnienie jak w pozostałych endpointach: x-client-id, x-api-key, x-user-id.

Zasada ogólna

Kalkulator działa na profilu żywieniowym zwierzaka — osobnym bycie, powiązanym z profilem zwierzaka. Kolejne wywołania uzupełniają ten profil kawałek po kawałku, a calculate na koniec wylicza dzienną rację na podstawie tego, co się w nim zebrało.

Każdy setter zwraca cały zaktualizowany profil, więc nie trzeba po nich dopytywać o stan.

Krok 0 — obowiązkowy

GET /measurements/{petId}

To nie jest zwykły odczyt: jeśli profil żywieniowy jeszcze nie istnieje, ten endpoint go zakłada. Wszystkie pozostałe wywołania wymagają istniejącego profilu.

Wywołanie settera przed założeniem profilu kończy się 404 z komunikatem mówiącym wprost, czego brakuje i czym to naprawić.

Kroki 1–5 — uzupełnianie profilu

Kolejność jest dowolna, poniższa jest naturalna dla formularza.

Krok Endpoint Body
1 POST /measurements/{petId}/puppy-status { "isPuppy": true }
2 POST /measurements/{petId}/weight { "weight": 4.2, "age": 6 }
3 POST /measurements/{petId}/activeness { "activeness": "MEDIUM" }
4 POST /measurements/{petId}/feed-type { "feedType": "MIXED" }
5 POST /measurements/{petId}/feed-noutrishments wartości odżywcze, patrz niżej
5b POST /measurements/{petId}/feed-proportions { "wetFeedProportion": 40 }
  • activeness: LOW | MEDIUM | HIGH
  • feedType: DRY | WET | MIXED
  • weight: kilogramy, zakres 0–100
  • age: miesiące, zakres 0–12

Wiek ma znaczenie tylko dla młodych

age jest używane wyłącznie wtedy, gdy isPuppy: true — wtedy wyliczenie idzie wzorem wzrostowym. Dla dorosłego zwierzaka pole jest ignorowane, więc w interfejsie warto pokazywać je dopiero po zaznaczeniu, że to szczenię lub kocię.

Wartości odżywcze zależą od rodzaju karmy

{
  "protein": 26,
  "rawFat": 14,
  "rawAsh": 7,
  "rawFibre": 3,
  "humidity": 9,
  "feedType": "DRY"
}
  • feedType w tym wywołaniu przyjmuje tylko DRY albo WET — to osobne zestawy wartości, po jednym dla każdego rodzaju karmy.
  • Przy DRY wystarczy zestaw dla suchej, przy WET — dla mokrej.
  • Przy MIXED trzeba wysłać oba zestawy, dwoma wywołaniami.
  • Węglowodanów się nie podaje — są wyliczane jako 100 − suma pozostałych. Suma pięciu pól musi być większa od zera i mniejsza od 100, inaczej wywołanie zostanie odrzucone.

Proporcja tylko dla karmy mieszanej

feed-proportions ma znaczenie wyłącznie przy feedType: "MIXED". Przy DRY i WET całe zapotrzebowanie pokrywa jeden rodzaj karmy i pole jest pomijane.

wetFeedProportion: 40 oznacza, że 40% dziennego zapotrzebowania energetycznego ma pochodzić z karmy mokrej, a 60% z suchej.

Wartość 0 jest traktowana jak brak proporcji — jeśli zwierzak ma dostawać wyłącznie suchą karmę, należy ustawić feedType: "DRY", a nie MIXED z zerem.

Krok opcjonalny — własne zapotrzebowanie

POST /measurements/{petId}/custom-der
{ "DER": 500 }

Nadpisuje wyliczone zapotrzebowanie energetyczne. Nie działa dla młodych zwierząt — przy isPuppy: true z podanym wiekiem pierwszeństwo ma wzór wzrostowy.

Krok końcowy — wyliczenie

POST /calculate/{petId}

Odpowiedź:

{
  "diet": {
    "DER": 900,
    "wet": { "energy": 360, "portion": 480 },
    "dry": { "energy": 540, "portion": 150 }
  }
}
  • DER — dzienne zapotrzebowanie energetyczne w kcal
  • energy — ile kcal ma pochodzić z danego rodzaju karmy; sumuje się do DER
  • portion — dzienna porcja w gramach

Uwaga na interpretację: proporcja dotyczy energii, nie masy. Karma mokra ma znacznie niższą gęstość energetyczną (dużo wody), więc przy 40% energii z mokrej jej udział wagowy będzie wyraźnie wyższy. Gramatury nie będą w stosunku 40:60 i nie jest to błąd.

Pola wet i dry przyjmują null, gdy dany rodzaj karmy nie występuje — przy feedType: "DRY" zawsze wet: null, przy WET odwrotnie.

Niekompletny profil nie kończy się błędem

calculate nie sprawdza, czy profil jest gotowy. Dla karmy mieszanej bez ustawionej proporcji zwraca 200 z samym zapotrzebowaniem:

{ "diet": { "DER": 323, "wet": null, "dry": null } }

null w obu polach jest więc wieloznaczne: może znaczyć „ten rodzaj karmy nie występuje" albo „profil nie został jeszcze uzupełniony". Z samej odpowiedzi nie da się tego rozróżnić.

Gotowość profilu sprawdza się przed wywołaniem, na podstawie GET /measurements/{petId}:

feedType Profil jest kompletny, gdy
DRY feedNourishments zawiera wpis DRY
WET feedNourishments zawiera wpis WET
MIXED są oba wpisy i ustawione wetFeedProportion

Brak wartości odżywczych dla wybranego rodzaju karmy to jedyny przypadek, w którym calculate zgłasza błąd — 422 "Missing nutrient values for the selected feed type".

Kody błędów w tym module

Sytuacja Odpowiedź
Setter wywołany przed GET /measurements/{petId} 404 "Nutrition profile does not exist - call GET /measurements/{petId} first"
Suma pięciu wartości odżywczych ≥ 100 400 "Incorrect noutrishments: the five values must add up to less than 100"
calculate bez wartości odżywczych dla wybranego rodzaju karmy 422 "Missing nutrient values for the selected feed type"
Zwierzak bez gatunku albo gatunku innego niż pies i kot 422 "Selected pet should be either dog or cat"
Zwierzak nie należy do użytkownika 403
Wartości activeness i feedType, zakres wagi 400

Wszystkie to błędy żądania, nie awarie — ponawianie nic nie da. 422 oznacza tu żądanie poprawne składniowo, ale niewykonalne przy obecnym stanie profilu.

Warunki da się sprawdzić przed wywołaniem: profil zakłada GET /measurements, sumę składników liczy się lokalnie, a gotowość profilu opisuje tabela wyżej.

Najczęstsze przyczyny błędów

Objaw Przyczyna
404 przy pierwszym setterze Nie wywołano GET /measurements/{petId}
400 „Incorrect noutrishments" Suma pięciu pól równa 100 lub większa
422 przy calculate Brak zestawu wartości odżywczych dla wybranego rodzaju karmy
wet: null i dry: null mimo MIXED Nie ustawiono wetFeedProportion (lub ustawiono 0) — odpowiedź to 200, nie błąd
Wynik ignoruje custom-der Zwierzak oznaczony jako młody i ma podany wiek

Przykładowa pełna sekwencja (kot, karma mieszana)

GET  /measurements/{petId}
POST /measurements/{petId}/puppy-status      { "isPuppy": false }
POST /measurements/{petId}/weight            { "weight": 4.2 }
POST /measurements/{petId}/activeness        { "activeness": "MEDIUM" }
POST /measurements/{petId}/feed-type         { "feedType": "MIXED" }
POST /measurements/{petId}/feed-noutrishments { ...wartości..., "feedType": "DRY" }
POST /measurements/{petId}/feed-noutrishments { ...wartości..., "feedType": "WET" }
POST /measurements/{petId}/feed-proportions  { "wetFeedProportion": 40 }
POST /calculate/{petId}

Profil jest trwały — przy kolejnych wizytach w kalkulatorze wystarczy GET /measurements/{petId}, żeby odczytać zapisane wartości, i zaktualizować tylko to, co się zmieniło, a następnie ponownie wywołać calculate.