#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/
Комментарии:
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:
- REST ничего не говорит о дизайне URL. Любая схема URL, которую вы придумываете, является RESTful. Вы должны спросить, хороший ли это дизайн. И да, второй подход весьма предпочтительнее первого. Первая — это тонна шума для клиентов и огромная проблема с обслуживанием для владельца. Это также ограничивает будущую гибкость.
- Я не знаю никаких существенных ошибок, если вы четко документируете, как использовать конечные точки. Например, для вложенных конечных точек типично возвращать только связанные элементы, и удаление вложенного элемента приведет только к удалению ассоциации, а не к удалению самого элемента. Такое поведение должно быть задокументировано так или иначе.
Бонусные баллы: запрос внешних ресурсов выходит за рамки.
Комментарии:
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 )