Подтвердить что ты не робот

Лучшая практика оператора фильтра API REST

Я создаю REST API, который использует параметр filter для управления результатами поиска. Например, можно было бы искать пользователя, вызывая:

GET /users/?filter=name%3Dfoo

Теперь мой API должен допускать множество разных операторов filter. Числовые операторы, такие как equals, greater than, less than, операторы строк, такие как contains, begins with или ends with и операторы даты, например year of или timediff. Более того, комбинации AND и OR должны быть возможны.
В принципе, я хочу поддерживать подмножество базовых операторов базы данных MySQL.

Я нашел много разных реализаций (два хороших примера: Google Analytics и LongJump), которые кажутся для использования пользовательского синтаксиса.
Рассматривая мои требования, я бы, вероятно, разработал специальный синтаксис, очень похожий на синтаксис оператора MySQL.
Однако мне было интересно, есть ли какие-либо лучшие практики, которые я должен соблюдать, и должен ли я рассматривать что-то еще. Спасибо!

4b9b3361

Ответ 1

Вам нужен уже существующий язык запросов, не пытайтесь изобретать колесо! По REST это сложная и не полностью решенная проблема. Есть некоторые ограничения REST, которые должно выполнить ваше приложение:

  • единый интерфейс/гипермедиа как двигатель состояния приложения:
    Вы должны отправлять гипермедийные ответы своим клиентам, и они должны следовать гиперссылкам, указанным в этих ответах, вместо того, чтобы создавать запросы самостоятельно. Таким образом, вы можете отделить клиентов от структуры URI.

  • единый интерфейс/самоописательные сообщения:
    Вы должны отправлять сообщения, аннотированные семантикой. Таким образом, вы можете отделить клиентов от структуры данных. Лучшим решением для этого является RDF с, например, открытыми связанными лексиками данных. Если вы не хотите использовать RDF, то второе лучшее решение для использования типа MIME для конкретного поставщика, поэтому ваши сообщения будут самоописательными, но клиенты должны знать, как анализировать ваш пользовательский тип MIME.

Чтобы описать простые поисковые ссылки, вы можете использовать шаблоны URI, например GET /users/{?name} будет ждать параметра name в строке запроса. Вы можете использовать hydra:IRITemplateMapping из hydra vocab, чтобы добавить семантику к параметрам типа name.

Описание специальных запросов - сложная задача. Вы должны каким-то образом описать, что может содержать ваш запрос.

  • Вы можете выбрать язык запросов URI и придерживаться шаблонов URI и, возможно, аннотации гидры. Существует много уже существующих языков запросов URI, например HTSQL, Запрос OData (ppl не нравится этот) и т.д.

  • Вы можете выбрать существующий язык запросов и отправить его в одном параметре URI. Это может быть все, что вы хотите, например SQL, SPARQL и т.д. Вы должны научить своего клиента генерировать этот параметр. Вы можете создать свой собственный словарь для описания ограничений реального запроса. Если вам не нужны сложные вещи, это не должно быть проблемой. Я не знаю уже существующей структуры запросов, описывающих словари, но я их никогда не искал...

  • Вы можете выбрать существующий язык запросов и отправить его в тело в запрос ПОИСК. Афаик ПОИСК не кэшируется или не поддерживается недавними HTTP-клиентами. Он был определен webdav. Вы можете описать свой запрос с помощью соответствующего типа MIME, и вы можете использовать тот же самый vocab, что и предыдущее решение.

  • Вы можете использовать решение RDF-запроса, например конечную точку SPARQL или тройные фрагменты шаблона и т.д. Итак, ваши запросы будут содержать семантические метаданные, а не описание вашей ссылки. По SPARQL вам не нужно трехкратно хранить данные, вы можете переводить запросы на стороне сервера SQL или все, что вы используете. Вероятно, вы можете использовать SPIN для описания ограничений запросов и шаблонов запросов, но это тоже ново для меня. Могут быть другие решения для описания структур запросов SPARQL...

Итак, чтобы обобщить, хотите ли вы реального решения REST, вы должны описывать своим клиентам, как они могут создавать запросы и какие параметры, логические операторы, которые они могут использовать. Без описаний запросов они не смогут генерировать, например, HTML-форму для пользователя. Если вы не хотите использовать REST-решение, выберите язык запросов, напишите на клиенте строитель, напишите парсер на сервере и все.

Ответ 2

Открытый протокол данных (OData)

Вы также можете проверить BreezeJs и посмотреть, как этот протокол реализован для node.js + mongodb с модулем breeze-mongodb и для .NET-проекта используя веб-API и EntityFramework с dll Breeze.ContextProvider.

Ответ 3

Обнимая набор общих, принятых разделителей, сравнение равенства может быть реализовано в прямолинейная мода. Установка значения параметра строки запроса фильтра в строку с использованием этих разделители создают список пар имя/значение, которые легко анализируются на стороне сервера и используются для увеличения запросов к базе данных по мере необходимости. Вы можете использовать выбранные вами разделители ( "|" ), чтобы отделить отдельные фразы фильтра для OR и ( "&" ), чтобы отделить отдельные фразы фильтров для AND и двойной двоеточия ( "::" ) для разделения имен и значений. Это обеспечивает уникальный набор ограничителей для поддержки большинства случаев использования и создает читаемый пользователем параметр строки запроса. Простой пример поможет прояснить эту технику. Предположим, мы хотим чтобы просить пользователей с именем "Тодд", которые живут в "Денвере" и имеют титул "Гранд Пообах".

URI запроса, содержащий строку запроса, может выглядеть так:

GET http://www.example.com/users?filter= "name:: todd & city:: denver & title:: grand poobah"

Разделитель двойного двоеточия ( "::" ) отделяет имя свойства от значения сравнения, позволяя сравнительному значению содержать пробелы, что упрощает анализ разделителя по значению на сервере. Обратите внимание, что имена свойств в парах имя/значение соответствуют имени свойств, которые будут возвращенный службой в полезной нагрузке.

Чувствительность к регистру, безусловно, должна обсуждаться в каждом конкретном случае, но в целом, фильтрация работает лучше всего, когда случай игнорируется. Вы также можете предлагать дикие карты по мере необходимости, используя звездочку ( "*" ) как часть значения пары имя/значение. Для запросов, требующих более простого сравнения или сравнения с дикими картами, введение операторов необходимо. В этом случае сами операторы должны быть частью значения и анализироваться на сервере а не часть имени свойства. Когда сложная функциональность типа запроса-языка необходимо рассмотреть вопрос о представлении концепции запроса из запроса на фильтрацию Open Data Protocol (OData) Спецификация опций (http://www.odata.org/documentation/odata-version-4-0/)

Ответ 4

Кажется, что существует множество стандартов (например, OData), но многие из них довольно сложны в том, что они вводят новый синтаксис.

Для простой мультифильтрации в следующем формате избегайте загрязнения пространства имен параметров, все еще стоящего поверх существующей веб-технологии.

GET /users?filter[name]=John&filter[title]=Manager

Он легко читается, а на бэкэнд-языках, например PHP, он получает его в виде массива фильтров.