Думи про web-API. частина друга

друге Наближення: Правильний шлях
Якщо раптом ви пропустили перше наближення, його можна знайти на тут. А в цьому наближенні я хотів би окремо поговорити про підходи до побудови унікальних шляхів до ресурсів і методів вашого web API і про тих архітектурних особливостях додатки, які впливають на зовнішній вигляд цього шляху і його компоненти.

Про що варто подумати, стоячи на березі

Версійність

Рано чи пізно будь-яка діюча система починає еволюціонувати: розвиватися, ускладнюватися, масштабуватися, усовремениваться. Для розробників REST API це загрожує в першу чергу тим, що необхідно запускати нові версії API при працюючих старих. Тут я кажу більше не про архітектурні зміни під капотом вашої системи, а про те, що змінюється сам формат даних і набір операцій з ними. У будь-якому випадку версійність потрібно передбачити як в початковій організації вихідного коду, так і у принципі побудови URL. Що стосується URL, тут існує два найбільш популярних способу вказівки версії API, якій адресовано запит. Префиксация шляху example-api.com/v1/ і розведення версій на рівні субдомену v1.example-api.com. Використовувати можна будь-який з них, залежно від потреби і потреби.

Автономність компонентів

Web API складних систем, що підтримують кілька ролей, часто вимагає поділу на частини, кожна з яких обслуговує свій спектр завдань. По суті, кожна частина може бути самостійним додатком, працювати на різних фізичних машинах і платформах. В контексті опису API нам абсолютно не важливо, як сервер обробляє запит і які сили і технології в цьому замішані. Для клієнта API — система инкапсулированная. Тим не менш різні частини системи можуть бути абсолютно різною функціональністю, наприклад, адміністративна і користувацька частина. І методологія роботи з одними і тими ж, здавалося б, ресурсами може істотно відрізнятися. Тому такі частини необхідно розділяти на рівні домену admin.v1.example-api.com або префікса шляху example-api.com/v1/admin. Це вимога не є обов'язковим, і багато що залежить від складності системи і її призначення.

Формат обміну даними
Найбільш зручним і функціональним, на мій погляд, форматом обміну даними є JSON, але ніхто не забороняє використовувати XML, YAML або будь-який інший формат, що дозволяє зберігати серіалізовані об'єкти без втрати типу даних (ми за типізацію). При бажанні можна зробити в API підтримку декількох форматів вводу/виводу. Достатньо задіяти HTTP заголовок запиту для зазначення бажаного формату відповіді Accept Content-Type для зазначення формату переданих у запиті даних. Іншим популярним способом є додавання до розширення URL ресурсу, наприклад, GET /users.xml, але такий спосіб здається менш гнучким і вродливим, хоча б тому, що обважнює URL і вірний швидше для GET-запити, ніж для всіх можливих операцій.

Локалізація і багатомовність

На практиці багатомовність API найчастіше зводиться до перекладу сервісних повідомлень і повідомлень про помилки на потрібну мову для прямого відображення кінцевому користувачеві. Багатомовний контент теж має місце бути, але збереження і видача контенту на різних мовах, на мій погляд, повинні розмежовуватися більш явно, наприклад, якщо у вас одна і та ж стаття існує на різних мовах, то фактично це дві різні сутності, згруповані за ознакою єдності змісту. Для ідентифікації очікуваного мови можна використовувати різні способи. Найпростішим можна вважати стандартний HTTP заголовок Accept-Language. Я зустрічав й інші способи, такі, як додавання GET-параметр language=«en», використання префікса шляху example-api.com/en/ або навіть на рівні доменного імені en.example-api.com. Мені здається, що вибір способу зазначення локалі залежить від конкретного додатка і завдань, що стоять перед ним.

Внутрішня маршрутизація
Отже, ми дісталися до кореневого вузла нашого API (або одного з його компонентів). Всі подальші маршрути будуть проходити вже безпосередньо всередині вашого серверного додатка, згідно з підтримуваним їм набором ресурсів.

Шляху до колекцій

Для вказівки шляху до колекції ми просто використовуємо назву відповідної сутності, наприклад, якщо це список користувачів, то шлях буде таким /users. До колекції як такої застосовуються два методу: GET (отримання лімітованого списку сутностей) і POST (створення нового елемента). У запитах на отримання списків ми можемо використовувати безліч додаткових GET параметрів, що застосовуються для посторінкового виведення, сортування, фільтрації, пошуку etc, але вони повинні бути опціональними, тобто ці параметри не повинні передаватися як частину шляху!

Елементи колекції

Для звернення до конкретного елементу колекції ми використовуємо в маршруті його унікальний ідентифікатор /users/25. Це і є унікальний шлях до нього. Для роботи з об'єктом застосовні методи GET (отримання об'єкта), PUT/PATCH (зміна) і DELETE (видалення).

Унікальні об'єкти

У безлічі сервісів існують унікальні для поточного користувача об'єкти, наприклад, профіль поточного користувача /profile, або персональні налаштування /settings. Зрозуміло, з одного боку, це елементи однієї з колекцій, але вони є відправною точкою у використанні нашого Web API клієнтським додатком і до того ж дозволяють набагато більш широкий спектр операцій над даними. При цьому колекція, зберігає настроювання, може бути взагалі недоступна з міркувань безпеки та конфіденційності даних.

Властивості об'єктів і колекцій

Для того, щоб дістатися до будь-якої з властивостей об'єкта безпосередньо, достатньо додати до шляху до об'єкта ім'я властивості, наприклад отримати ім'я користувача /users/25/name. До властивості застосовні методи GET (одержання значення) і PUT/PATCH (зміна значення). Метод DELETE не застосовний, оскільки властивість є структурною частиною об'єкта, як формалізованої одиниці даних.

У попередній частині ми говорили про те, що у колекцій, як і у об'єктів, можуть бути власні властивості. На моїй пам'яті мені знадобилося лише властивість count, але ваш додаток може бути більш складним і специфічним. Шляхи до властивостей колекцій будуються за тим же принципом, що і до властивостей їх елементів: /users/count. Для властивостей колекцій застосуємо тільки метод GET (одержання властивості), т. к. колекція — це лише інтерфейс для доступу до списку.

Колекції пов'язаних об'єктів

Однієї з різновидів властивостей об'єктів можуть бути пов'язані об'єкти або колекції пов'язаних об'єктів. Такі сутності, як правило, не є власним властивістю об'єкта, а лише відсиланнями до його зв'язків з іншими сутностями. Наприклад, перелік ролей, які були присвоєні користувачеві /users/25/roles. Щодо роботи з вкладеними об'єктами і колекціями ми детально поговоримо в одній з наступних частин, а на даному етапі нам досить того, що ми маємо можливість звертатися до них безпосередньо, як до будь-якої іншої властивості об'єкта.

Функції об'єктів та колекцій

Для побудови шляху до інтерфейсу виклику функції у колекції або об'єкта ми використовуємо той самий підхід, що і для звернення до властивості. Наприклад, для об'єкта /users/25/sendPasswordReminder або колекції /users/disableOld. Для викликів функцій ми в будь-якому випадку використовуємо метод POST. Чому? Нагадаю, що в класичному REST не існує спеціального дієслова для виклику функцій, а тому нам доведеться використовувати один із існуючих. На мій погляд, для цього найбільше підходить метод POST, т. к. він дозволяє передавати на сервер необхідні аргументи, не є идемпотентным (повертає один і той же результат при багаторазовому зверненні) і найбільш абстрактний за семантикою.

Сподіваюся, що все більш-менш вклалося в систему:) У наступній частині ми поговоримо докладніше про запитах і відповідях, їх форматах, коди статусів.
Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.