
В этом посте рассмотрим принципы и лучщие решения проектирования и именования элементов REST.
Ресурсы в REST
Ресурсом можеть элемент или коллекция элементов. К приемру, customers
(клиенты) — это ресурс-коллекция, а customer
(клиент) — ресурс-элемент. Мы можем идентифицировать ресурс коллекции customers
, используя URI /customers
, а ресурс одного клиента customer
с помощью URI /customers/{customerId}
.
Ресурс также может содержать вложенные коллекции. К примеру, вложенная коллекция accounts
конкретного клиента (customer
) может быть идентифицирована с использованием URI /customers/{customerId}/accounts
. Аналогичным образом, одноэлементный ресурс account
внутри вложенного ресурса accounts
можно определить следующим образом: /customers/{customerId}/accounts/{accountId}
.
Ограничение единообразного интерфейса частично устраняется комбинацией URI и HTTP-глаголов, и использует их в соответствии со стандартами и соглашениями.
Виды REST ресурсов
Архетипы ресурсов можно разделить на четыре категории:
- документ
- коллекция
- хранилище
- контроллер.
Каждый из этих видов ресурсов нужно использовать в URI в соответствии с назначением и выполняемой функцией по данному эндпойнту.
Не нужно отклоняться от правил и сопротивляться соблазну проектировать ресурсы, которые являются гибридами более чем одного архетипа.
Правила именования ресурсов REST
Опишем правила именования всех перечисленных видов ресурсов. Выше уже указали, что удачнос проектирвоанный ресурс — это отнести его к одному единственному типу архетипов и использовать соглашение об именовании.
Существительные для представления ресурсов
RESTful URI должен ссылаться на ресурс, который является предметом (существительным), а не ссылкой на действие (глагол), поскольку существительные обладают свойствами, которых нет у глаголов — подобно тому, как у ресурсов есть некие атрибуты. Несколько примеров ресурсов:
- пользователи системы
- учётные записи пользователей
- сетевые устройства и т.д.
URI этих ресурсов можно представить следующим образом:
http://api.example.com/device-management/managed-devices
http://api.example.com/device-management/managed-devices/{device-id}
http://api.example.com/user-management/users/
http://api.example.com/user-management/users/{id}
Документ
Ресурс документа представляет собой отдельный элемент, что по сути близко к экземпляру объекта или записи в базе данных. В REST Вы можете рассматривать документ как отдельный ресурс в коллекции ресурсов. Представление состояния документа обычно включает в себя как поля со значениями, так и ссылки на другие связанные ресурсы.
Архетипы ресурсов документа необходимо использовать в единственном числе:
http://api.example.com/device-management/managed-devices/{device-id}
http://api.example.com/user-management/users/{id}
http://api.example.com/user-management/users/admin
Коллекция
Ресурс коллекция (коллекция ресурсов) — это управляемый сервером каталог ресурсов. Клиенты могут предлагать новые ресурсы для добавления в коллекцию. Тем не менее, коллекция сама определяет, создавать новый ресурс, или нет. Ресурс-коллекция определяет то, что будет содержать в себе, а также определяет, каким будет URI каждого ресурса, который относится к этой коллекции.
Архетипы ресурсов-коллекций нужно именовать во множественном числе:
http://api.example.com/device-management/managed-devices
http://api.example.com/user-management/users
http://api.example.com/user-management/users/{id}/accounts
Репозиторий
Ресурс репозиторий представляет собой управляемый клиентом хранилище ресурсов. Ресурс хранилища позволяет клиенту API вставлять ресурсы, возвращать их и решать, когда их удалять. Хранилище после себя не содержит новые URI.
Архетипы ресурсов-репозиторий нужно именовать во множественном числе:
http://api.example.com/cart-management/users/{id}/carts
http://api.example.com/song-management/users/{id}/playlists
Контроллер
Ресурс контроллер моделирует процедурную концепцию. Контроллеры похожи на исполняемые функции с параметрами и возвращаемыми значениями.
Архетипы ресурсов-контроллера нужно обазначать в виде глаголов:
http://api.example.com/cart-management/users/{id}/cart/checkout
http://api.example.com/song-management/users/{id}/playlist/play
Последовательность и согласованность
Соглашения об именовании и форматировании URI необходимы, чтобы минимизировать двумысленность и максимимализировать удобочитаемость.
1. Использование слэша (/) для обозначения иерархических отношений
Символ слэша (/) используется для разделения URI на части, чтобы указать иерархическую взаимосвязь между ресурсами. Например:
http://api.example.com/device-management
http://api.example.com/device-management/managed-devices
http://api.example.com/device-management/managed-devices/{id}
http://api.example.com/device-management/managed-devices/{id}/scripts
http://api.example.com/device-management/managed-devices/{id}/scripts/{id}
2. Не использовать в URI завершающий слэш
В качестве последнего символа в URI слэш не добавляет никакого семантического значения и может вызвать путаницу. Лучше отказаться от подобной практики.
http://api.example.com/device-management/managed-devices/
http://api.example.com/device-management/managed-devices // Эта версия гораздо лучше
3. Использование дефиса для улучшения читаемости URI
Чтобы Ваши URI можно было легко сканировать и интерпретировать, нужно использовать символ дефиса. Так улучшится читаемость имен в сегментах длинного пути.
http://api.example.com/inventory-management/managed-entities/{id}/install-script-location
4. Не использовать нижние подчёркивания (_)
В качестве разделителя можно было бы использовать вместо дефиса и знак подчеркивания. Но в зависимости от шрифта приложения, возможно, что подчеркивания (_) могут быть частично закрыты или полностью скрыты в некоторых браузерах или не отображаться на некоторых экранах.
Чтобы избежать этой путаницы, используйте только дефисы.
http://api.example.com/inventory-management/managed-entities // Хорошо читается
http://api.example.com/inventory_management/managed_entities // Более подвержен ошибкам
5. Используйте в URI буквы в нижнем регистре
Следует отдавать предпочтение строчным буквам в путях. При этом следует знать, что RFC 3986 определяет URI как чувствительные к регистру, за исключением схемы и компонентов хоста.
http://api.example.org/my-folder/my-doc // 1
HTTP://API.EXAMPLE.ORG/my-folder/my-doc // 2
http://api.example.org/My-Folder/my-doc // 3
Примеры 1 и 2 являются идентичными. Но путь в примере 3 отличается, поскольку использует заглавные буквы (My-Folder).
6. Не используйте расширения файлов
Расширения файлов выглядят плохо и не добавляют никаких преимуществ. Удаление их также уменьшает длину URI. Поэтому нет причин включать их в пути.
В случаях, когда Вы хотите указать, как нужно обрабатывать контент, не следует выделять медиа-тип с помощью расширений, лучше передать медиа-тип в заголовке Content-Type.
http://api.example.com/device-management/managed-devices.xml // Не делайте так
http://api.example.com/device-management/managed-devices // Это корректный URI
Никогда не использовать в URI имена CRUD-функци
URI не должны использоваться для указания того, что выполняется функция CRUD. URI следует использовать для уникальной идентификации ресурсов, а не для каких-либо действий. А для указания функции CRUD должны использоваться методы HTTP-запроса.
HTTP GET http://api.example.com/devices // Получить все устройства
HTTP POST http://api.example.com/devices // Создать новое устройство
HTTP GET http://api.example.com/devices/{id} // Получить устройство с указанным Id
HTTP PUT http://api.example.com/devices/{id} // Обновить устройство с указанным Id
HTTP DELETE http://api.example.com/devices/{id} // Удалить устройство с указанным Id
Использовать компонент запроса для фильтрации коллекции URI
Много раз вы будете сталкиваться с требованиями, в которых вам понадобится коллекция ресурсов, отсортированных, отфильтрованных или ограниченных на основе некоторого определенного атрибута ресурса. Для этой цели не следует создавать новые API — интерфейсы — лучше включите функции сортировки, фильтрации и разбивки на страницы в API сбора ресурсов и передайте входные параметры в качестве параметров запроса. Например:
http://api.example.com/device-management/managed-devices
http://api.example.com/device-management/managed-devices?region=USA
http://api.example.com/device-management/managed-devices?region=USA&brand=XYZ