Увійти Реєстрація
Блог Серії
Кар'єра
Вакансії Компанії
Навчання
Документація Співбесіди Тестування Відео
Екосистема
Пакети Ресурси Проєкти Інструменти Події
Інше
Про нас Реклама

Як моделювати в API сутності зі станами й допустимими переходами між ними?

Більшість бізнес-сутностей мають життєвий цикл: замовлення (нове → оплачене → відправлене → доставлене / скасоване), стаття (чернетка → на модерації → опублікована), заявка, платіж. API має відображати цей цикл явно.

1. Поле стану - перелічення з документованими значеннями:

{ "id": 42, "state": "paid", "paid_at": "2026-10-04T07:15:00Z" }

Не набір булевих прапорців (is_paid, is_shipped, is_cancelled) - вони допускають неможливі комбінації.

2. Стан змінюють не напряму, а через дії:

PATCH /orders/42 {"state": "shipped"}          # погано: обходить правила
POST  /orders/42/ship {"tracking": "UA123"}    # добре: явний перехід з даними

Google AIP-216 радить робити поле стану лише для читання (output only) і змінювати його власними методами. Тоді:

  • кожен перехід має свої параметри (трек-номер при відправці, причина при скасуванні);
  • свої права (скасувати може клієнт, відправити - лише склад);
  • свої побічні ефекти (лист, повернення коштів) - у явному місці коду.

3. Недопустимий перехід - явна помилка:

POST /orders/42/cancel
409 Conflict
{ "type": "/problems/invalid-state-transition", "title": "Замовлення вже відправлено", "current_state": "shipped" }

4. Клієнт має знати, що дозволено зараз:

{ "state": "paid", "allowed_actions": ["ship", "refund"] }

Інтерфейс показує кнопки за цим списком - логіку переходів не дублюють на клієнтах.

5. Історія переходів - окремий ресурс (GET /orders/42/events): хто, коли, з якого стану в який. Потрібна для підтримки, аудиту й спорів.

6. Конкурентні переходи: два запити «скасувати» й «відправити» одночасно. На сервері - перевірка поточного стану атомарно (UPDATE ... WHERE state = 'paid' чи блокування рядка), а в API - оптимістичне блокування через If-Match/версію.

7. Нові стани - зміна, що може зламати клієнтів: клієнт з switch по відомих станах не знає, що робити з новим. Документуйте, що перелік може розширюватися, і вимагайте від клієнтів обробки невідомих значень.

На бекенді Laravel це зручно оформити енумом стану з методом canTransitionTo() або пакетом станів (spatie/laravel-model-states), а дії - окремими класами-actions, на які спираються контролери.

Докладніше в документації: Google AIP-216: стани

Перевір себе

20 випадкових питань за спробу, після завершення - розбір кожної помилки

Схожі питання