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/

https://developer.github.com/guides/getting-started/

https://dev.twitter.com/rest/public

4 ответов


оба подхода можно считать RESTful, при условии, что вы не нарушаете ограничения REST, определенные в Глава 5 диссертации Роя Томаса Филдинга:

I не вижу серьезных подводных камней в обоих подходах, но я бы предпочел Приблизиться B на Подход: URL-адреса короче, легче запомнить, и не требуется много параметров.


бонусные баллы: Spotify и Facebook API следуют этому подходу. Конечно, есть и другие Аписы, но это те, которые пришли мне на ум.


  1. REST ничего не говорит о дизайне URL. Любая схема URL, которую вы придумаете, является RESTful. Вы должны спросить, хороший ли это дизайн. И да, второй подход предпочтительнее первого. Первый-это тонна шума для клиентов и огромная проблема обслуживания для владельца. Это также ограничивает гибкость.

  2. нет никаких существенных подводных камней, о которых я знаю, пока вы четко документируете, как использовать конечные точки. Например, это типично для вложенные конечные точки возвращают только связанные элементы, а удаление вложенного элемента удаляет только ассоциацию, а не сам элемент. Такое поведение так или иначе должно быть задокументировано.

бонусные баллы: запрос внешних ресурсов выходит за рамки.


подход к дизайну поднимает несколько вопросов, которые необходимо учитывать при выборе между ними:

зависимость существования

на 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)