Этот вопрос касается оптимального дизайна API REST и проблемы, с которой я столкнулся, чтобы выбирать между вложенными ресурсами и коллекциями корневого уровня.
Чтобы продемонстрировать концепцию, предположим, что у меня есть коллекции City
, Business
и Employees
. Типичный API может быть построен следующим образом. Представьте, что ABC, X7N и WWW являются ключами, например. Идентификаторы GUID:
GET Api/City/ABC/Businesses (returns all Businesses in City ABC)
GET Api/City/ABC/Businesses/X7N (returns business X7N)
GET Api/City/ABC/Businesses/X7N/Employees (returns all employees at business X7N)
PUT Api/City/ABC/Businesses/X7N/Employees/WWW (updates employee WWW)
Это кажется чистым, потому что оно следует за исходной структурой домена - бизнес находится в городе, а сотрудники - в бизнесе. Отдельные элементы доступны через ключ под коллекцией (например, ../Businesses
возвращает все предприятия, а ../Businesses/X7N
возвращает отдельный бизнес).
Вот что должен делать пользователь API:
- Получить бизнес в городе
(GET Api/City/ABC/Businesses)
- Получить всех сотрудников в бизнесе
(GET Api/City/ABC/Businesses/X7N/Employees)
- Обновить информацию о персональном сотруднике
(PUT Api/City/ABC/Businesses/X7N/Employees/WWW)
Этот второй и третий вызовы, находясь в правильном месте, используют множество параметров, которые фактически не нужны.
- Чтобы получить сотрудников в бизнесе, единственным необходимым параметром является ключ к бизнесу (
X7N
). - Чтобы обновить отдельного сотрудника, единственным параметром должен был быть ключ сотрудника (
WWW
)
Ничто в коде бэкэнд не требует некрупной информации для поиска бизнеса или обновления сотрудника. Таким образом, вместо этого появляются следующие конечные точки:
GET Api/City/ABC/Businesses (returns all Businesses in City ABC)
GET Api/Businesses/X7N (returns business X7N)
GET Api/Businesses/X7N/Employees (returns all employees at business X7N)
PUT Api/Employees/WWW (updates employee WWW)
Как вы можете видеть, я создал новый root для предприятий и сотрудников, хотя с точки зрения домена они являются суб/суб-подсетей.
Ни одно из решений не кажется мне очень чистым.
- Первый пример запрашивает ненужную информацию, но структурирован таким образом, который кажется "естественным" для потребителя (отдельные элементы из коллекции извлекаются через нижние листья).
- Второй пример запрашивает только необходимую информацию, но не структурирован "естественным образом" - подколлекции доступны через корни.
- Индивидуальный корень сотрудника не будет работать при добавлении нового сотрудника, так как нам нужно знать, к какой компании добавить сотрудника, а это значит, что вызов должен, по крайней мере, находиться в корневом каталоге "Бизнес", например
POST Api/Businesses/X7N7/Employees
, что делает все еще более запутанным.
Есть ли более чистый, третий способ, о котором я не думаю?