API с поддержкой REST - проектирование суб-ресурсов
Я разрабатываю RESTful API, и я придумал проблему, связанную с субресурсами.
Я вижу другие API, использующие полный URL для работы над вложенными ресурсами. Возьмем пример, где Company has Departments
и Department has Employees
.
в начале я думал о реализации всех возможных адресов. В результате получается следующее:
Подход
01. ### COMPANY URLS ###
02. DELETE /companies/{companyId}
03. GET /companies/{companyId}
04. POST /companies
05. PUT /companies/{companyId}
06.
07. ### DEPARTMENT URLS ###
08. DELETE /companies/{companyId}/departments/{departmentId}
09. GET /companies/{companyId}/departments/{departmentId}
10. POST /companies/{companyId}/departments
11. PUT /companies/{companyId}/departments/{departmentId}
12. DELETE /departments/{departmentId}
13. GET /departments/{departmentId}
14. PUT /departments/{departmentId}
15.
16. ### EMPLOYEE URLS ###
17. DELETE /companies/{companyId}/departments/{departmentId}/employees/{employeeId}
18. GET /companies/{companyId}/departments/{departmentId}/employees/{employeeId}
19. POST /companies/{companyId}/departments/{departmentId}/employees
20. PUT /companies/{companyId}/departments/{departmentId}/employees/{employeeId}
21. DELETE /departments/{departmentId}/employees/{employeeId}
22. GET /departments/{departmentId}/employees/{employeeId}
23. POST /departments/{departmentId}/employees
24. PUT /departments/{departmentId}/employees/{employeeId}
25. DELETE /employees/{employeeId}
26. GET /employees/{employeeId}
27. PUT /employees/{employeeId}
как вы можете видеть, есть много адресов, которые делают то же самое. Пример: 08 дублируется 12; 09 дублируется 13; 17 дублируется 21 и 25...
Я хочу удалить дублирование, но сохранить согласованность. Итак, перепроектируем API с учетом принципа sup-resources are fine but sub-sub-resources are not
. Что привело к следующему:
Подход B
01. ### COMPANY URLS ###
02. DELETE /companies/{companyId}
03. GET /companies/{companyId}
04. POST /companies
05. PUT /companies/{companyId}
06.
07. ### DEPARTMENT URLS ###
08. DELETE /departments/{departmentId}
09. GET /departments/{departmentId}
10. GET /companies/{companyId}/departments
11. POST /companies/{companyId}/departments
12. PUT /departments/{departmentId}
13.
14. ### EMPLOYEE URLS ###
15. DELETE /employees/{employeeId}
16. GET /employees/{employeeId}
17. GET /departments/{departmentId}/employees
18. POST /departments/{departmentId}/employees
19. PUT /employees/{employeeId}
Мои Вопросы
Q1. Is Подход B считается спокойным? (Я предполагаю еще)
Q2. Есть ли подводные камни Подход B я должен подумайте, если предположить, что документация также предоставляется?
бонусные баллы, если вы укажете на другие API, следующие Подход B.
редактировать
Elad Tabak
представлены хорошие выводы.
Я люблю некоторые API, используя подход Б:
https://developers.google.com/youtube/v3/docs/
4 ответов
оба подхода можно считать RESTful, при условии, что вы не нарушаете ограничения REST, определенные в Глава 5 диссертации Роя Томаса Филдинга:
I не вижу серьезных подводных камней в обоих подходах, но я бы предпочел Приблизиться B на Подход: URL-адреса короче, легче запомнить, и не требуется много параметров.
бонусные баллы: Spotify и Facebook API следуют этому подходу. Конечно, есть и другие Аписы, но это те, которые пришли мне на ум.
REST ничего не говорит о дизайне URL. Любая схема URL, которую вы придумаете, является RESTful. Вы должны спросить, хороший ли это дизайн. И да, второй подход предпочтительнее первого. Первый-это тонна шума для клиентов и огромная проблема обслуживания для владельца. Это также ограничивает гибкость.
нет никаких существенных подводных камней, о которых я знаю, пока вы четко документируете, как использовать конечные точки. Например, это типично для вложенные конечные точки возвращают только связанные элементы, а удаление вложенного элемента удаляет только ассоциацию, а не сам элемент. Такое поведение так или иначе должно быть задокументировано.
бонусные баллы: запрос внешних ресурсов выходит за рамки.
подход к дизайну поднимает несколько вопросов, которые необходимо учитывать при выборе между ними:
зависимость существования
на A, это очень интуитивно, что при удалении компании, вы также удаляете все это суб ресурсы-отделы и сотрудники. В B, пользователь API должен подумать о таком действии-мне нужно вызвать delete для всех сотрудников или достаточно удалить компания? конечно, это можно документировать, но все же, это не прямолинейно.
A есть преимущество здесь, потому что это очень ясно - при удалении resouce, вы удаляете все это sub ресурсы.
конечная точка операции
возникает еще один вопрос - Как обновить объект? с какого конца?
Если я хочу удалить сотрудника, достаточно ли обновить компанию новым набором служащие? или я должен удалить сотрудника?
или сказать, что я хочу изменить сотрудника из одной компании в другую. В B, теоретически я могу обновить сотрудника с полем компании и покончить с этим. В A нет такого пути...
A имеют преимущество, когда это очень прямолинейно, как сделать действие-CRUD на URL сущности. B заставляет пользователя API остановиться и задаться вопросом, какое действие он может сделать, на котором URL-АДРЕС.
но в то же время, B имейте преимущество, что изменение "воспитания" сущности проще (в случаях, когда это актуально).
проверка
на A, вы должны проверить соответствие аргументов URL, так как пользователь может предоставить идентификатор сотрудника с неправильной компанией или отделом. В B нет такой проблемы.
Так что это может показаться немного безумным, но в HTTP/REST нет такого понятия, как "subresource".
в вашей модели предметной области, отдел не может существовать без компании.
теперь в вашем API вы выставляете JSON-представление компании по адресу /companies/{companyId}
и представление JSON отдела в /companies/{companyId}/departments/{departmentId}
.
это как "ресурсы". Ресурс, в терминологии HTTP/REST, просто означает то, на что указывает URL. Так что это представление JSON компания, а не сама компания.
дизайн URL сам по себе немного Тупиковый переулок-сами URL - адреса могут выглядеть как угодно, неважно, читаемы они или нет. Разработчики делают запросы, выбирая URL-адреса в зависимости от имен операций из документации*. Попытка добавить смысл к самим URL-адресам становится сложной быстро, и на самом деле может добавить путаницу с течением времени.
лучше потратить время на документацию, а не пытаться пускать люди делают выводы о поведении домена.
*или гипермедиа (например,https://github.com/kevinswiber/siren)