Сортировка и фильтрация в REST API
15 августа 2016
Среди информации по построению REST API встречаются две рекомендации на тему сортировки и фильтрации. Сортировку делать вот так:
GET /users?sort=-created_at,username
Сортируем по убыванию по дате создания и по имени пользователя в алфавитном порядке.
Фильтры делать вот так:
GET /tickets?status=open&assignee=123
Получаем открытые тикеты, назначенные на пользователя с ID=123.
Вроде всё красиво, но что если у очередного ресурса появится поле sort
? GET-параметр уже зарезервирован для сортировки, использовать его для фильтрации не получается. Выхода два: либо заставить пользователя никогда не использовать поле sort
(а к нему со временем добавится like
и ещё что-нибудь) либо ввести для фильтрации отдельный параметр filter
. Значение лучше всего описать в формате JSON: не придётся заботиться о специальных правилах экранирования, да и поддержка его есть во всех клиентах.
GET /tickets?filter={"status": "open", "assignee": 123}
В случае отдельного параметра, хоть синтаксис и не настолько интуитивен, конфликт имён исключается.
Комментарии RSS по email OK
Можно написать продолжение статьи, начинающееся со слов "Вроде всё красиво, но что если у очередного ресурса появится поле filter?" Или я не понял решаемую проблему?
zelenin, ну появится. Тогда будет так:
Sam, как начет варианта - использование
cлужебных префиксов
? Например,_sort
,_filter
.И почему полей с такими именами не может быть?
А почему должны? Часто встречаете названия полей с подчеркиванием в качестве префикса?
И не такое бывает :) В issue Yii сообщали об именовании полей юникодом с пробелами, например.
Sam, а есть какие-то рекомендации по структуре ответа в API? Чтобы с результатом запроса (есть там данные или нет) можно было легко работать и в web-app, и в mobile-app.
Может какие-то советы из личного опыта (а то об этом информации крайне мало).
Я сейчас использую такой формат (пока только json):
Есть jsonapi.org/. Большинство рекомендаций вполне соответствует действительности. Не все, но большинство.
Как вариант можно использовать массив: GET /ticket?formName[status]=open&formName[assignee]=123
Суть та же, но более привычная структура параметров. Да и в GridView уже есть такая реализация. Метод load() у моделей умеет читать такой формат.