RESTful API — проектирование вспомогательных ресурсов

#rest #restful-url

#rest #restful-url

Вопрос:

Я разрабатываю RESTful API и столкнулся с проблемой, связанной с подресурсами.

Я вижу другие API, использующие полный URL-адрес для работы с подресурсами. Возьмем пример , где Company has Departments и Department has Employees .

Вначале я думал о реализации всех возможных URL-адресов. В результате получается следующее:

Подходите к

 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}
 

Как вы можете видеть, существует множество URL-адресов, которые делают то же самое. Пример: 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. Считается ли подход B спокойным? (Я предполагаю, что да)

Q2. Существуют ли подводные камни подхода B, которые я должен учитывать, предполагая, что документация также предоставляется?

Бонусные баллы, если вы укажете на другие API, следуя подходу B.

Редактировать

Elad Tabak представил хорошие идеи.

Мне нравится некоторый API, использующий подход B:

https://developers.google.com/youtube/v3/docs/

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

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

Комментарии:

1. Это слишком широко, Q3 и 4 в основном приглашают выпустить книгу по дизайну веб-сервисов. Предполагается, что вы задаете один вопрос, а не анкету. Ваш основной вопрос, похоже, состоит из Q1 Q2.

2. Спасибо, Джимби, согласен, он очень широкий, и я больше всего забочусь о Q1 и Q2.

Ответ №1:

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

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


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

Комментарии:

1. На самом деле ни один из URI не является RESTful как таковой! Это содержимое, которое они вернули, соответствует ограничениям RESTful или нет. REST не имеет ничего общего с чистым дизайном URI, а скорее с отделением клиентов от серверных API, и, следовательно, клиент должен использовать URI, возвращаемые с ответами, для выполнения дальнейших действий над своим текущим состоянием. Не знаю, почему все автоматически путают дизайн URI с RESTful подходом. В дополнение к этому Филдинг разъяснил некоторые ограничения, которым должен следовать RESTful API, в своем сообщении в блоге

Ответ №2:

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

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

В A очень интуитивно понятно, что когда вы удаляете компанию, вы также удаляете все ее вспомогательные ресурсы — отделы и сотрудников. В B пользователю API нужно немного подумать о таком действии — нужно ли мне вызывать delete для всех сотрудников или достаточно удалить компанию? конечно, это можно задокументировать, но, тем не менее, это не прямолинейно.

Здесь у меня есть преимущество, потому что это очень ясно — при удалении ресурса вы удаляете все его вложенные ресурсы.

Конечная точка операции

Возникает еще один вопрос — как мне обновить объект? из какой конечной точки?

Если я хочу удалить сотрудника, достаточно ли обновить компанию новым набором сотрудников? или я должен УДАЛИТЬ сотрудника?

Или, скажем, я хочу сменить сотрудника из одной компании в другую. В B теоретически я могу обновить employee с помощью поля company и покончить с этим. В A такого способа нет…

У меня есть преимущество в том, что очень просто, как выполнить действие — CRUD для URL-адреса объекта. B заставляет пользователя API останавливаться и задаваться вопросом, какое действие он может выполнить по какому URL.

Но в то же время у B есть преимущество, заключающееся в том, что изменение «родительского» объекта проще (в тех случаях, когда это актуально).

Проверка

В A необходимо проверить соответствие аргументов URL, поскольку пользователь может указать идентификатор сотрудника не той компании или отдела. В B такой проблемы нет.

Ответ №3:

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

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

Комментарии:

1. И в дополнение к этому, нет такого понятия, как «подресурс»

Ответ №4:

Так что это может показаться немного безумным, но в HTTP / REST нет такого понятия, как «подресурс».

В вашей доменной модели отдел не может существовать без компании.

Теперь в вашем API вы предоставляете json-представление компании at /companies/{companyId} и json-представление отдела at /companies/{companyId}/departments/{departmentId} .

Это оба «ресурса». Ресурс в терминологии HTTP / REST просто означает то, на что указывает URL. Таким образом, это «представление компании в формате json», а не сама компания.

Дизайн URL-адресов сам по себе немного тупиковый — сами URL-адреса могут выглядеть как УГОДНО, не имеет значения, читаемы они или нет. Разработчики делают запросы, выбирая URL-адреса в зависимости от названий операций из документации *. Попытка придать смысл самим URL-адресам быстро усложняется и со временем может привести к путанице.

Лучше потратить время на документацию, а не пытаться позволить людям делать выводы о поведении домена.

* или гипермедиа (например https://github.com/kevinswiber/siren )