Спроба розробити API для зовнішніх програм із передбаченням змін непроста, але трохи продуманий фронт може згодом полегшити життя. Я намагаюся створити схему, яка підтримуватиме майбутні зміни, залишаючись сумісними назад, залишаючи на місці обробники попередніх версій.
Основна проблема, що стосується цієї статті, полягає в тому, яку модель слід дотримуватися для всіх визначених кінцевих точок для даного товару / компанії.
Базова схема
Враховуючи шаблон базової URL-адреси, https://rest.product.com/
я припустив, що всі сервіси проживають /api
разом із /auth
іншими кінцевими точками на основі не відпочинку /doc
. Тому я можу встановити базові кінцеві точки таким чином:
https://rest.product.com/api/...
https://rest.product.com/auth/login
https://rest.product.com/auth/logout
https://rest.product.com/doc/...
Кінцеві точки обслуговування
Тепер про самі кінцеві точки. Заклопотаність POST
, GET
, DELETE
не є основною метою даної статті і є турботою про самих цих діях.
Кінцеві точки можна розділити на простори імен та дії. Кожна дія повинна також представляти себе таким чином, щоб підтримувати фундаментальні зміни типу повернення або необхідних параметрів.
Беручи гіпотетичну службу чату, де зареєстровані користувачі можуть надсилати повідомлення, у нас можуть бути такі кінцеві точки:
https://rest.product.com/api/messages/list/{user}
https://rest.product.com/api/messages/send
Тепер додамо підтримку версій для майбутніх змін API, які можуть бути порушеними. Ми могли або додати версію підпису після, /api/
або після /messages/
. З огляду на send
кінцеву точку, ми можемо мати наступне для v1.
https://rest.product.com/api/v1/messages/send
https://rest.product.com/api/messages/v1/send
Тож перше моє запитання - що рекомендується для ідентифікатора версії?
Керування кодом контролера
Отже, тепер ми встановили, що нам потрібно підтримувати попередні версії, щоб таким чином якось обробити код для кожної з нових версій, яка може з часом застаріти. Припускаючи, що ми пишемо кінцеві точки на Java, ми могли б керувати цим за допомогою пакетів.
package com.product.messages.v1;
public interface MessageController {
void send();
Message[] list();
}
Це має перевагу в тому, що весь код був розділений через простори імен, де будь-яка зміна перерви означатиме, що нова копія кінцевих точок служби. Шкода цього полягає в тому, що весь код потрібно скопіювати, а виправлення помилок, які бажають застосувати до нових та попередніх версій, потрібно застосувати / протестувати до кожної копії.
Інший підхід полягає у створенні обробників для кожної кінцевої точки.
package com.product.messages;
public class MessageServiceImpl {
public void send(String version) {
getMessageSender(version).send();
}
// Assume we have a List of senders in order of newest to oldest.
private MessageSender getMessageSender(String version) {
for (MessageSender s : senders) {
if (s.supportsVersion(version)) {
return s;
}
}
}
}
Це тепер виокремлює версію до кожної кінцевої точки і робить виправлення помилок зворотного порту сумісним, оскільки в більшості випадків потрібно застосовувати лише один раз, але це означає, що нам потрібно зробити трохи більше роботи до кожної окремої кінцевої точки, щоб підтримати це.
Отже, є моє друге питання "Який найкращий спосіб створити код служби REST для підтримки попередніх версій".