Посібник із побудови HTTP API
Даний посібник містить рекомендації щодо проектування HTTP API, які були взяті з роботи API хмарної платформи Heroku, крім того, воно також містить інформацію про новий функціонал і внутрішній API в Heroku.
Нашими основними цілями при побудові API є дотримання послідовності та концентрації на реалізації бізнес-логіки. Ми шукаємо різні, не обов'язково найкращі, але добре документовані способи розробки API.
При прочитанні цієї статті мається на увазі, що ви знайомі з основними принципами HTTP та JSON.
Принцип поділу відповідальності
Під час проектування намагайтеся зберігати простоту системи, розділяючи відповідальність між різними частинами циклу «запит-відповідь». При цьому простота прийнятих рішень дозволить концентруватися на вирішенні складніших завдань. Запити та відповіді виконуються для отримання доступу до певного ресурсу або набору ресурсів. Для визначення сутності, яку необхідно отримати, використовуйте шлях і тіло відповіді передачі вмісту, а заголовки — передачі метаданих. Можна передавати всі параметри в тілі запиту, але, як показує практика, таке рішення є менш гнучким. Найправильнішим підходом буде передача частини параметрів у заголовках.
Вимагайте використання захищених з'єднань
Для отримання даних за допомогою API використовуйте лише захищені з'єднання з TLS. Краще рішенням було б відхиляти всі запити, що не використовують TLS, а саме запити по http або на 80-й порт, щоб уникнути небезпечного обміну даними. У випадках, коли це неможливо, віддавайте відповідь 403 Forbidden.
Перенаправлення не вітаються, оскільки вони допускають некоректну поведінку клієнта, не надаючи при цьому чітких пояснень.Клієнти, які покладаються на редиректи, таким чином подвоюють трафік сервера і використання TLS у цьому випадку марно, оскільки важливі дані виявляються незахищеними при першому виклику.
Вимагайте наявність версії у заголовку Accept
Наявність кількох версій та переходи між ними може бути одним із найскладніших аспектів проектування та використання API. Тому краще заздалегідь врахувати цей момент.
Для того, щоб клієнт не користувався нестабільним API, краще перевіряти наявність його версії в кожному запиті. При цьому варто уникати вказівок за замовчуванням, оскільки це значно ускладнює заголовок, і ця версія також може змінюватися в майбутньому.
Найкраще – додати версію в заголовок разом з іншими метаданими, використовуючи заголовок Accept з типом вмісту користувача:
Використовуйте заголовок ETags для кешування
Включайте заголовок ETags у всі запити, визначаючи при цьому версію ресурсу, що повертається. Це дозволить користувачам кешувати ресурси та реалізовувати умовні запити за допомогою використання заголовка If-None-Match, який допоможе визначити, чи потрібно оновлювати кеш чи ні.
Використовуйте Request-ID для інтроспекції
Включайте заголовок Request-Id , що містить UUID значення, в кожну відповідь сервера. Реєструючи ці значення на клієнті, сервері чи іншому сервісі, ви отримуєте можливість налагоджувати та діагностувати проблеми, пов'язані із запитами.
Розділяйте великі відповіді сервера на кілька невеликих за допомогою заголовка Range
Великі відповіді необхідно розбивати на дрібніші, використовуючи заголовок Range. Для отримання більш детальної інформації про заголовки запитів/відповідей, коди станів та обмеження вивчіть Обговорення використання заголовкаRange в API платформи Heroku.
Повертайте відповідні коди станів
Повертайте відповідний код стану HTTP у кожній відповіді. Успішні відповіді повинні містити такі стани:
- 200 – GET запит завершився успішно, синхронний DELETE або PATCH запит завершився успішно, або синхронний PUT запит оновив існуючий ресурс.
- 201 – Синхронний запит POST завершився, синхронний PUT запит створив новий ресурс.
- 202 – Прийнятий POST, PUT, DELETE або PATCH запит, який буде оброблений асинхронно.
- 206 – GET запит завершився успішно, але буде повернено часткову відповідь (див. розділ про заголовок Range).
Повертайте відповідні коди помилок для надання додаткової інформації щодо їх причин:
- 422 Unprocessable Entity – Ваш запит було розпізнано, але містить неправильні параметри.
- 429 Too Many Requests – Перевищено ліміт запитів, спробуйте пізніше.
- 500 Internal Server Error – Проблема на стороні сервера, перевірте стан сайту та/або повідомте про проблему.
Для отримання більш детальної інформації про коди стану HTTP вивчіть специфікацію.
По можливості надавайте повні версії ресурсів
Повертайте користувачам вашого API повне представлення ресурсу (тобто об'єкт з усіма атрибутами) у всіх відповідях, де це можливо. Завжди надавайте повну версію ресурсу у відповідях на запити з кодами стану 200 та 201, включаючи PUT, PATCH та DELETE запити.
Відповіді на запити з кодом стану 202 не повинні містити поля об'єкта
Ваш API повинен приймати серіалізований JSON у запиті
Ваш API повинен передбачати можливість передачі сереалізованого JSON у тілі PUT/PATCH/POST запитівзамість, або на додаток до даних форми, що передаються. Таким чином створюється симетрія в JSON-відповідях:
Будьте послідовні під час конструювання шляху до ресурсу
Назви ресурсів
Намагайтеся проектувати такі кінцеві URL, які не вимагають додаткових дій для окремих ресурсів. У випадках, коли це необхідно, додайте до загального шляху компонент «action» для того, щоб чітко визначити ці дії:
Використовуйте назви компонентів шляху та атрибутів у нижньому регістрі
Для назв компонентів шляху до ресурсу використовуйте нижній регістр і поділяйте їх за допомогою дефісу.
Назви атрибутів краще писати в нижньому регістрі, а як роздільник краще використовувати нижнє підкреслення – таким чином назви полів можна писати без дужок у Javascript:
Ваш API повинен підтримувати доступ до ресурсу не тільки за його ID
У деяких випадках для кінцевих користувачів незручний доступ до ресурсу за його ідентифікатором. Наприклад, користувачеві зручніше для доступу до конкретної програми Heroku використовувати назву програми, а не її UUID. У таких випадках необхідно організувати доступ як по імені, так і за ідентифікатором:
Зведіть до мінімуму кількість вкладень у шляху для доступу до ресурсу
У моделях даних, у яких є батьківські відносини між сутностями, шляхи доступу до ресурсів можуть мати великий рівень вкладеності:
Ви можете обмежити глибину вкладеності, якщо розміщуватимете ресурси в кореневій директорії. Вкладеність краще використовувати для позначення доступу до колекцій ресурсів:
Надайте UUID запитуваних ресурсів
Кожен ресурс за промовчанням повинен мати атрибут id . Як значення ідентифікатора ресурсу намагайтеся завждивикористовувати UUID. Не використовуйте ідентифікатори, які не будуть унікальними в масштабі вашого сервісу, особливо автоінкрементні ідентифікатори. UUID ресурсу виводьте у форматі 8-4-4-4-12:
Надайте інформацію про дату створення та зміни ресурсу
За промовчанням ресурс повинен зберігати інформацію про дату створення created_at та оновлення updated_at .
Тимчасові величини мають бути форматовані згідно з ISO8601
Відносини із зовнішніми сутностями мають бути винесені у вкладений об'єкт
Зовнішні відносини мають бути серіалізовані як вкладений об'єкт:
А не як поле об'єкта:
Такий підхід дозволяє додати більше інформації про пов'язаний об'єкт без необхідності змінювати структуру відповіді:
Створюйте структуровані відповіді у разі виникнення помилок
Віддавайте послідовне, структуроване тіло відповіді у разі помилок. Відповідь при цьому повинна містити повідомлення про помилку, що легко читається і, опціонально, url , який вказує клієнту де можна отримати додаткову інформацію про проблему і способи її вирішення.
Показуйте обмеження щодо кількості запитів
Обмеження за кількістю запитів запроваджується для підтримки працездатності системи та можливості якісного обслуговування інших клієнтів. Для розрахунку обмежень кількості запитів можна використовувати алгоритм поточного відра. Повертайте кількість запитів для кожного запиту в заголовку відповіді RateLimit-Remaining .
JSON у всіх відповідях має бути мінімізований
Зайвий пробіл збільшує розмір відповіді і багато Javascript клієнти для зручності читання автоматично відформатують JSON. Тому краще мінімізувати JSON відповіді:
Ви можете опціонально додати можливістьотримувати більш розгорнуту відповідь, вказуючи додатковий параметр (наприклад, ?pretty=true ) або задаючи значення заголовка Accept ( Accept: application/vnd.heroku+json; version=3; indent=4; ).
Надайте зручну для обробки JSON-схему
Для точного опису API надавайте JSON-схему. Для керування схемою використовуйте prmd, а також переконайтеся, що вона проходить валідацію за допомогою команди prmd verify .
Надайте документацію, що легко читається.
Для того, щоб розробники зналися на принципах роботи вашого API, надайте їм зручну документацію. Якщо ви створили JSON-схему, використовуючи prmd як описано вище, ви можете легко згенерувати Markdown документацію для всіх кінцевих url, використовуючи команду prmd doc .
На додаток до опису кінцевих url, надайте огляд API, включаючи туди наступну інформацію:
- процес аутентифікації - отримання та використання користувальницького токена;
- стабільність API та її версію, і навіть інформацію у тому, як вибрати потрібну версію API;
- загальні заголовки запитів та відповідей;
- формат видачі помилки;
- приклади використання API з клієнтами різними мовами;
Надайте приклади запитів, які можна протестувати
Надайте приклади запитів, які можуть протестувати користувачі. Для тестування цих запитів користувач має виконати мінімум дій:
Якщо ви використовуєте prmd для створення документації, такі приклади будуть згенеровані автоматично для кожного кінцевого url.
Опишіть стабільність вашого API
Ви можете описати ступінь стабільності вашого API або окремих кінцевих URL за допомогою установки прапорів prototype / development / production .
ДляДля отримання додаткової інформації ви можете вивчити документ Політика сумісності Heroku API.
Як тільки ви оголосили ваш API готовим до релізу та стабільним, не варто здійснювати модифікацій, які порушують зворотну сумісність усередині цієї версії. Для внесення таких змін створіть нову гілку API із новим індексом версії.