Когда я могу использовать параметры пути или параметры запроса в RESTful API?


142

Я хочу, чтобы мой RESTful API был очень предсказуемым. Как лучше всего решить, когда производить сегментацию данных с использованием URI, а не с помощью параметров запроса.

Мне кажется логичным, что системные параметры, поддерживающие разбиение на страницы, сортировку и группировку, должны быть после символа "?" Но как насчет таких полей, как «статус» и «регион» или других атрибутов, которые сегментируют вашу коллекцию? Если это также должны быть параметры запроса, каково эмпирическое правило, чтобы знать, когда использовать параметры пути?


1
ответ на аналогичный вопрос здесь ... stackoverflow.com/questions/3198492/…
Lalit Mehra

Ответы:


241

Лучшая практика для разработки RESTful API заключается в том, что параметры пути используются для идентификации конкретного ресурса или ресурсов, а параметры запроса используются для сортировки / фильтрации этих ресурсов.

Вот пример. Предположим, вы реализуете конечные точки RESTful API для объекта с именем Car. Вы должны структурировать свои конечные точки следующим образом:

GET /cars
GET /cars/:id
POST /cars
PUT /cars/:id
DELETE/cars/:id

Таким образом, вы используете параметры пути только тогда, когда указываете, какой ресурс извлекать, но это никоим образом не сортирует / фильтрует ресурсы.

Теперь предположим, что вы хотите добавить возможность фильтрации автомобилей по цвету в ваших GET-запросах. Поскольку цвет не является ресурсом (это свойство ресурса), вы можете добавить параметр запроса, который делает это. Вы должны добавить этот параметр запроса в свой запрос GET/cars следующим образом:

ПОЛУЧИТЬ /cars?color=blue

Эта конечная точка будет реализована так, чтобы возвращались только синие автомобили.

Что касается синтаксиса, ваши имена URL должны быть полностью строчными. Если у вас есть имя объекта, которое обычно состоит из двух слов на английском языке, вы должны использовать дефис для разделения слов, а не верблюжий регистр.

Ex. /two-words


3
Спасибо за ответ, Майк. Это четкая и простая методология; стоит моего голоса. Тем не менее, часто разработчики выбирают подход `` автомобили / синий '', мне интересно, как они это делают ... возможно, они решают сделать параметры пути для полей, которые являются обязательными, или, может быть, они делают это, чтобы указать, что база данных разделена на этот сегмент.
cosbor11 07

1
Я не уверен, что они рассуждают. Честно говоря, я с этим не согласен. Я думаю, что соблюдение условностей и простота имеет наибольший смысл. Поступая таким образом, вы позволяете потребителям вашего API лучше понимать, что им нужно делать, чтобы получить доступ к его функциям.
Майк,

3
как насчет / cars? id = 1 & color = blue вместо cars / 1 /? color = blue. вы в основном фильтруете ресурсы автомобилей в каждом сценарии
mko

1
Неправильно, поскольку автомобиль с идентификатором 1 существует только один, а автомобилей с синим цветом может быть много. Существует различие между идентичностью и фильтром
Паыля

1
Моя гипотеза относительно того, почему использование параметров пути так широко распространена, заключается в том, что многие разработчики учились на фреймворках, разработанных людьми, которые плохо разбирались в принципах REST (в частности, Ruby on Rails).
Крис Броски,

58

Основной способ думать об этом предмете следующий:

URI - это идентификатор ресурса, который однозначно идентифицирует конкретный экземпляр ТИПА ресурса. Как и все остальное в жизни, каждый объект (который является экземпляром какого-либо типа) имеет набор атрибутов, которые либо не зависят от времени, либо являются временными.

В приведенном выше примере автомобиль - это очень осязаемый объект, у которого есть такие атрибуты, как марка, модель и VIN, которые никогда не меняются, а также цвет, подвеска и т. Д., Которые могут меняться со временем. Поэтому, если мы закодируем URI с атрибутами, которые могут изменяться со временем (временными), мы можем получить несколько URI для одного и того же объекта:

GET /cars/honda/civic/coupe/{vin}/{color=red}

А годы спустя, если цвет этой самой машины поменять на черный:

GET /cars/honda/civic/coupe/{vin}/{color=black}

Обратите внимание, что сам экземпляр автомобиля (объект) не изменился - изменился только цвет. Наличие нескольких URI, указывающих на один и тот же экземпляр объекта, заставит вас создать несколько обработчиков URI - это неэффективный дизайн и, конечно, не интуитивно понятный.

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

GET /cars/honda/civic/coupe/{vin}?color={black}

Итог - подумайте о полиморфизме.


2
Интересная парадигма .. Это часто используемый шаблон дизайна? Можете ли вы предоставить некоторые API-интерфейсы, которые используют это в своей документации, или ссылки, описывающие эту стратегию?
cosbor11 07

1
Мне нравится, как вы подчеркнули «TYPE», когда написали «URI - это идентификатор ресурса, который однозначно идентифицирует конкретный экземпляр TYPE ресурса». Я думаю, это важное различие.
jrahhali

15

В REST API вас не должны слишком беспокоить предсказуемые URI. Само предположение о предсказуемости URI намекает на неправильное понимание архитектуры RESTful. Предполагается, что клиент должен сам создавать URI, чего на самом деле не должно быть.

Однако я предполагаю, что вы создаете не настоящий REST API, а API, вдохновленный REST (например, Google Drive). В этих случаях практическое правило - «параметры пути = идентификация ресурса» и «параметры запроса = сортировка ресурсов». Итак, возникает вопрос, можете ли вы однозначно идентифицировать свой ресурс БЕЗ статуса / региона? Если да, то, возможно, это параметр запроса. Если нет, то это параметр пути.

НТН.


12
Я не согласен, хороший API должен быть предсказуемым; RESTful или иначе.
cosbor11

3
Я думаю так. Должна быть рифма и причина того, как формируется URI, а не произвольное именование конечных точек. Когда можно интуитивно написать клиент API, не обращаясь постоянно к документации, на мой взгляд, вы написали хороший API.
cosbor11 01

2
«Когда можно интуитивно написать клиент API, не обращаясь постоянно к документации». Вот где, я думаю, наше понимание REST отличается ... клиенту API никогда не нужно «создавать» URL. Они должны выбрать его из ответа на предыдущий вызов API. Если взять за аналогию веб-сайт ... Заходишь на facebook.com, затем выбираешь ссылку на страницу событий. Вам все равно, является ли URL-адрес событий facebook «предсказуемым», поскольку вы не набираете его. Вы попадаете туда через гиперссылки. То же самое и с REST api. Итак, сделайте URI значимыми для вас (сервера), но не для вашего клиента,
Оливер Макфи

2
Добавлено примечание. Это не означает, что URI не должны следовать легкому для понимания шаблону, это просто означает, что это не ограничение RESTful API. Самая большая проблема в этой области заключается в том, что люди предполагают, что клиент должен сам создавать URL-адреса. Их не должно быть, поскольку это создает связь между клиентом и сервером, которой не должно быть. (например, сервер не может изменить URL без нарушения работы всех клиентских приложений). В REST API сервер может изменять их по своему усмотрению.
Оливер Макфи

3
+1 за использование следующих слов: «'параметры пути = идентификация ресурса' и 'параметры запроса = сортировка ресурсов'». Это действительно прояснило мне ситуацию.
Дуг

3

Однажды я разработал API, основным ресурсом которого был people. Обычно пользователи запрашивают фильтрацию, peopleпоэтому /people?settlement=urbanя реализовал , чтобы пользователи не вызывали что-то подобное каждый раз, /people/urbanчто позже позволило мне легко добавить /people/rural. Также это позволяет получить доступ к полному /peopleсписку, если он понадобится позже. Короче говоря, я хотел добавить путь к общим подмножествам

От сюда :

Псевдонимы для общих запросов

Чтобы сделать работу с API более приятной для среднего потребителя, рассмотрите возможность упаковки наборов условий в легко доступные пути RESTful. Например, приведенный выше запрос недавно закрытых билетов может быть упакован какGET /tickets/recently_closed


1

Вообще говоря, я обычно использую параметры пути, когда в ресурсе существует очевидная «иерархия», например:

/region/state/42

Если этот единственный ресурс имеет статус, можно:

/region/state/42/status

Однако, если «регион» на самом деле не является частью предоставляемого ресурса, он, вероятно, относится к одному из параметров запроса - аналогично разбивке на страницы (как вы упомянули).


0

Сегментация более иерархична и «симпатична», но может быть ограничивающей.

Например, если у вас есть URL-адрес с тремя сегментами, каждый из которых передает разные параметры для поиска автомобиля по марке, модели и цвету:

www.example.com/search/honda/civic/blue

Это очень красивый URL-адрес, который легче запоминается конечным пользователем, но теперь вы застряли в этой структуре. Допустим, вы хотите сделать так, чтобы в поиске пользователь мог искать ВСЕ синие автомобили или ВСЕ Honda Civics? Параметр запроса решает эту проблему, потому что он дает пару значений ключа. Итак, вы могли пройти:

www.example.com/search?color=blue
www.example.com/search?make=civic

Теперь у вас есть способ ссылаться на значение с помощью его ключа - либо «цвет», либо «сделать» в коде запроса.

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

www.example.com/search/make/honda/model/civic/color/blue

Надеюсь, это имеет смысл ..


-2

Пример URL: /rest/{keyword}

Этот URL-адрес является примером параметров пути. Мы можем получить эти данные URL с помощью @PathParam.

Пример URL: /rest?keyword=java&limit=10

Этот URL-адрес является примером параметров запроса. Мы можем получить эти данные URL с помощью @Queryparam.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.