При разработке интерфейса RESTful семантика типов запросов считается жизненно важной для проекта.
- GET - список коллекции или получить элемент
- PUT - заменить коллекцию или элемент
- POST - Создать коллекцию или элемент
- УДАЛИТЬ - Ну, ну, удалить коллекцию или элемент
Тем не менее, это не похоже на понятие «поиск».
Например, при разработке набора веб-служб, поддерживающих сайт поиска работы, у вас могут быть следующие требования:
- Получить индивидуальную работу объявления
- GET для
domain/Job/{id}/
- GET для
- Создать объявление о работе
- POST в
domain/Job/
- POST в
- Обновить вакансию
- Положить на
domain/Job/
- Положить на
- Удалить объявление о работе
- УДАЛИТЬ к
domain/Job/
- УДАЛИТЬ к
«Получить все рабочие места» также просто:
- GET для
domain/Jobs/
Однако как «поиск» попадает в эту структуру?
Вы можете утверждать, что это вариант «коллекции списков» и реализовывать как:
- GET для
domain/Jobs/
Однако поиск может быть сложным, и вполне возможно произвести поиск, который генерирует длинную строку GET. То есть, ссылаясь на вопрос SO здесь , возникают проблемы с использованием строк GET длиннее, чем около 2000 символов.
Примером может служить граненый поиск - продолжение примера «работа».
Я могу разрешить поиск по аспектам - «Технология», «Должность», «Дисциплина», а также ключевые слова в свободном тексте, возраст работы, местоположение и зарплата.
Благодаря гибкому пользовательскому интерфейсу и большому количеству технологий и названий должностей, возможно, что поиск может охватывать большое количество вариантов выбора.
Настройте этот пример на резюме, а не на вакансии, добавьте еще больше граней, и вы можете легко представить поиск с выбранной сотней граней или даже с 40 гранями, каждая из которых имеет длину 50 символов (например, названия должностей, названия университетов, Имена работодателя).
В этой ситуации может быть желательно переместить PUT или POST, чтобы обеспечить правильную отправку данных поиска. Например:
- POST в
domain/Jobs/
Но семантически это инструкция по созданию коллекции.
Вы могли бы также сказать , что вы будете выражать это как создание поиска:
- POST в
domain/Jobs/Search/
или (как предложено ниже)
- POST в
domain/JobSearch/
С семантической точки зрения это может иметь смысл, но вы на самом деле ничего не создаете, вы делаете запрос на данные.
Итак, семантически это GET , но GET не гарантирует поддержку того, что вам нужно.
Итак, вопрос в том, чтобы попытаться сохранить как можно более верный дизайн RESTful, и в то же время убедиться, что я соблюдаю ограничения HTTP, каков наиболее подходящий дизайн для поиска?
источник
domain/Jobs?keyword={keyword}
. Это прекрасно работает для меня :) Я надеюсь, чтоSEARCH
глагол станет стандартом. programmers.stackexchange.com/questions/233158/…Ответы:
Не следует забывать, что запросы GET имеют некоторые превосходящие преимущества перед другими решениями:
1) GET-запросы можно скопировать из строки URL, они перевариваются поисковыми системами, они «дружественные». Где «дружественный» означает, что обычно запрос GET не должен ничего изменять внутри вашего приложения (идемпотент) . Это стандартный случай для поиска.
2) Все эти концепции очень важны не только с точки зрения пользователя и поисковой системы, но и с точки зрения архитектуры и дизайна API .
3) Если вы создадите обходной путь с помощью POST / PUT, у вас будут проблемы, о которых вы сейчас не думаете. Например, в случае браузера нажмите кнопку возврата / обновить страницу / историю. Конечно, это можно решить, но это будет другой обходной путь, потом еще и еще ...
Учитывая все это, мой совет будет:
а) Вы должны уметь вписываться в ваш GET, используя умную структуру параметров . В крайнем случае, вы даже можете использовать такую тактику, как поиск в Google, где я установил множество параметров, но это очень короткий URL.
б) Создайте еще одну сущность в вашем приложении, например, JobSearch . Предполагая, что у вас есть так много вариантов, вполне вероятно, что вам нужно будет также сохранить эти запросы и управлять ими, так что это просто очистит ваше приложение. Вы можете работать с объектами JobSearch как с единым целым, то есть вы можете протестировать его / использовать его проще .
Лично я попытался бы бороться со всеми моими когтями, чтобы сделать это с a), и когда вся надежда была потеряна, я отполз со слезами на глазах к варианту b) .
источник
domain/Jobs/Search/
, может быть , сdomain/JobsSearch/
вместо этого, или же вы имеете в виду что - то другое? Вы можете уточнить?TL; DR: GET для фильтрации, POST для поиска
Я делаю различие между фильтрацией результатов из списка коллекции и сложным поиском. Лакмусовый тест, который я использую, в основном, если мне нужно больше, чем фильтрация (положительный, отрицательный или диапазон), я считаю это более сложным поиском, требующим POST.
Это имеет тенденцию быть усиленным, думая о том, что будет возвращено. Я обычно использую только GET, если ресурс имеет в основном полный жизненный цикл (PUT, DELETE, GET, collection GET) . Обычно в коллекции GET я возвращаю список URI, которые являются ресурсами REST, которые составляют эту коллекцию. В сложном запросе я могу извлекать данные из нескольких ресурсов, чтобы создать ответ (например, SQL-соединение), поэтому я не буду отправлять обратно URI, а только реальные данные. Проблема в том, что данные не будут представлены в ресурсе, поэтому мне всегда придется возвращать данные. Мне кажется, это очевидный случай, когда требуется POST.
-
Это было некоторое время, и мой оригинальный пост был немного небрежным, поэтому я думал, что буду обновлять.
GET - это интуитивно понятный выбор для возврата большинства видов данных, коллекций ресурсов REST, структурированных данных ресурса, даже единичных полезных нагрузок (изображений, документов и т. Д.).
POST - это метод catchall для всего, что не подходит под GET, PUT, DELETE и т. Д.
На данный момент я думаю, что простой поиск, фильтрация имеют смысл с помощью GET. Сложный поиск зависит от личных предпочтений, особенно если вы добавляете функции агрегации, взаимные корреляции (объединения), реформаторы и т. Д. Я бы сказал, что параметры GET не должны быть слишком длинными, и это большой запрос (однако он структурирован) ) часто может иметь больше смысла как тело запроса POST.
Я также рассматриваю опыт использования API. Как правило, я хочу сделать большинство методов максимально простыми и интуитивно понятными. Я вставлю вызовы, которые являются более гибкими (и, следовательно, более сложными), в POST и в другой URI ресурса, особенно если это не согласуется с поведением других ресурсов REST в том же API.
В любом случае, согласованность, вероятно, важнее, чем если вы выполняете поиск в GET или POST.
Надеюсь это поможет.
источник
GET /class?queryParams
. С точки зрения пользователя, «класс» всегда был чем-то особенным, и вам не нужно было делать какие-то странные SQL-объединения.В REST определение ресурса очень широкое. Однако на самом деле вы хотите связать некоторые данные.
Например, основной Google URI указывает на ресурс коллекции «ссылок на каждый сайт в Интернете». Параметры запроса сужают его до тех сайтов, которые вы хотите увидеть.
(URI = универсальный идентификатор ресурса, из которых URL = универсальный локатор ресурса, где знакомый «http: //» является форматом по умолчанию для URI. Таким образом, URL является локатором, но в REST целесообразно обобщить это для идентификатора ресурса Люди используют их взаимозаменяемо, хотя.)
А затем используйте POST, который является глаголом добавления или обработки, чтобы добавить новые элементы в эту коллекцию:
Обратите внимание, что
job
в каждом случае это одна и та же структура объекта. Клиент может ПОЛУЧИТЬ набор заданий, используя параметры запроса для сужения поиска, а затем использовать тот же формат для одного из элементов, чтобы ПОСТАВИТЬ новое задание. Или может взять один из этих элементов и PUT на его URI, чтобы обновить этот.Для действительно длинных или сложных строк запросов соглашение позволяет вместо этого отправлять их как запросы POST. Объедините параметры запроса в виде пар имя / значение или вложенных объектов в структуре JSON или XML и отправьте их в теле запроса. Например, если ваш запрос содержит вложенные данные вместо набора пар имя / значение. Спецификация HTTP для POST описывает его как глагол добавления или процесса. (Если вы хотите проплыть линкор через лазейку в REST, используйте POST.)
Я бы использовал это как запасной план.
Что вы теряете, когда делаете это, хотя это: а) GET является нульпотентным - то есть он ничего не меняет - POST - нет. Поэтому, если вызов не удался, промежуточное ПО не будет автоматически повторять или кэшировать результаты, и 2) с параметрами поиска в теле, вы не сможете больше вырезать и вставить URI. То есть URI не является конкретным идентификатором для поиска, который вы хотите.
Чтобы отличить «создать» от «поиска». Есть несколько вариантов, которые соответствуют практике REST:
Вы можете сделать это в URI, добавив что-то к имени коллекции, например, поиск работы вместо рабочих мест. Это просто означает, что вы рассматриваете коллекцию поиска как отдельный ресурс.
Так как семантика POST является процессом добавления ИЛИ, вы можете идентифицировать тела поиска с полезной нагрузкой. Как {работа: ...} против {поиск: ...}. Это зависит от логики POST, чтобы разместить или обработать его соответствующим образом.
Это в значительной степени предпочтение дизайна / реализации. Я не думаю, что есть четкое соглашение.
Итак, как вы уже изложили, идея состоит в том, чтобы определить ресурс коллекции для
jobs
Поиск с GET + запрос параметров, чтобы сузить поиск. Длинные или структурированные запросы данных попадают в тело POST (возможно, в отдельную коллекцию поиска). Создать с помощью POST, чтобы добавить в коллекцию. И обновить с PUT для конкретного URI.
(FWIW соглашение о стиле с URI состоит в том, чтобы использовать все строчные буквы со словами, разделенными дефисами. Но это не значит, что вы должны делать это таким образом.)
(Кроме того, я должен сказать, что из вашего вопроса ясно, что вы далеко продвинулись по этому пути. Я прописал некоторые вещи просто для того, чтобы выстроить их в ряд, но ваш вопрос уже затрагивал большинство семантических проблем в этом ответ. Я просто связывал это с некоторыми соглашениями и практикой.)
источник
route
самом деле не может справиться с выбором обработки. Я должен был бы взглянуть на это ...Обычно я использую запросы OData, они работают как вызов GET, но позволяют вам ограничивать возвращаемые свойства и фильтровать их.
Вы используете токены, такие как
$select=
и$filter=
поэтому вы получите URI, который выглядит примерно так:Вы также можете сделать пейджинг с помощью
$skip
и$top
и заказ.Для получения дополнительной информации, проверьте OData.org . Вы не указали, какой язык вы используете, но если это ASP.NET, платформа WebApi поддерживает запросы OData - для других (PHP и т. Д.), Вероятно, есть библиотеки, которые вы можете использовать для перевода их в запросы к базе данных.
источник
JobsNearMeAddedInTheLast7Days
или что-то еще для инкапсуляции запроса, который слишком длинный / сложный для OData, а затем выставил бы его только через вызовы GET ,Один из подходов, который следует рассмотреть, - это обработка множества возможных запросов как ресурса коллекции, например
/jobs/filters
.POST
запросы к этому ресурсу, с параметрами запроса в теле, либо создать новый ресурс или определить существующий эквивалентный фильтр и возвращают URL , содержащий его идентификатор:/jobs/filters/12345
.Идентификатор может быть использован в запросе GET для заданий:
/jobs?filter=12345
. ПоследующиеGET
запросы к ресурсу фильтра будут возвращать определение фильтра.Преимущество этого подхода состоит в том, что он освобождает вас от формата параметра запроса для определения фильтра, потенциально предоставляя вам больше возможностей для определения сложных фильтров. Условия OR - один из примеров, который я могу придумать, который трудно выполнить с помощью строк запроса.
Недостатком этого подхода является то, что вы теряете удобочитаемость URL-адреса (хотя это может быть смягчено путем получения определения посредством
GET
запроса ресурса фильтра). По этой причине вы также можете захотеть поддерживать те же или подмножество параметров запроса для/jobs
ресурса, что и для ресурса фильтра. Это может быть использовано для более коротких запросов. Если эта функция предоставляется, чтобы поддерживать кешируемость между двумя типами фильтрации, при использовании параметров запроса к/jobs
ресурсу реализация должна внутренне создавать / повторно использовать ресурс фильтра и возвращать состояние302
или,303
указывающее URL-адрес в форме/jobs?filter=12345
.источник
GET /jobs/37
и получить результат, затем кто-то удалит ресурс, и через 2 секунды тот же запрос вернет 404. Аналогично, если выPOST /searches
и вы перенаправлены на результат поиска (поиск создан, и вы получаете 201 с Заголовок местоположения ресурса), через 2 секунды этот результат может быть удален из памяти и должен быть восстановлен. Нет необходимости в длительном хранении.Это старый ответ, но я все еще могу внести небольшой вклад в обсуждение. Я очень часто наблюдал недопонимание REST, RESTful и Architecture. RESTful никогда не упоминает ничего о НЕ построении поиска, в RESTful ничего нет об архитектуре, это набор принципов или критериев проектирования.
Чтобы лучше описать поиск, нам нужно поговорить об архитектуре, в частности, и лучше всего подходит ресурсно-ориентированная архитектура (ROA).
В RESTful есть принципы для разработки, идемпотент не означает, что результат не может измениться, как я прочитал в некоторых ответах, это означает, что результат независимого запроса не зависит от того, сколько раз выполнено. Это может измениться, давайте представим, что я постоянно обновляю базу данных, снабжая ее некоторыми данными, которые обслуживаются RESTful Api, выполнение того же GET может изменить результат, но это не зависит от того, сколько раз он был выполнен. Если я могу заморозить мир, это означает, что в сервисе нет состояния, преобразования или чего-либо еще, когда я запрашиваю ресурс, который приводит к другому результату.
В архитектуре, ориентированной на ресурсы (далее для краткости будем называть ее ROA), мы ориентируемся на ресурс, который может быть многим:
То, что делает его уникальным с точки зрения ресурса, это доступность, что означает, что он имеет только один URI
Таким образом, поиск идеально подходит для RESTful, учитывая ROA . Мы должны использовать GET, потому что я предполагаю, что ваш поиск - это обычный поиск, и он ничего не меняет, поэтому он идемпотентен (даже если он возвращает разные вещи в зависимости от добавленных новых элементов). Таким образом, здесь возникает путаница, потому что я могу придерживаться RESTful, а не ROA, это означает, что я могу следовать шаблону, который создает поиск и возвращать разные вещи с одинаковыми параметрами, потому что я не использую принцип адресуемости ROA. Как так? Хорошо, если вы отправляете поисковые фильтры в теле или заголовке, ресурс НЕ АДРЕСОВАН.
Вы можете найти принципы того, что именно и URI в оригинальном документе W3:
https://www.w3.org/DesignIssues/Axioms
Любой URL в этой архитектуре должен быть информативным. Это необходимо, если вы следуете принципам, чтобы обращаться ко всему в URI, это означает, что вы можете использовать / (косую черту) для разделения всего, что вам нужно или запроса параметров. Мы знаем, что на это есть ограничения, но это образец архитектуры.
Следуя шаблону ROA в RESTful, поиск не более чем любой другой ресурс, единственное отличие состоит в том, что ресурсы поступают из вычислений, а не из прямой связи с самим объектом. Основываясь на этом принципе, я мог бы обратиться и получить простую услугу арифметических вычислений на основе следующей схемы:
http://myapi.com/sum/1/2
Там, где суммы, 1 и 2 могут быть изменены, но результат вычислений является уникальным и адресуемым, каждый раз, когда я звоню с одинаковыми параметрами, я получаю одно и то же, и в сервисе ничего не меняется. Ресурсы / sum / 1/2 и / substract / 5/4 отлично придерживаются принципов.
источник
GET в порядке, если у вас есть статическая коллекция, которая всегда возвращает одинаковые результаты (представление) для одного URI. Это также подразумевает, что данные, генерирующие эти представления, никогда не изменяются. Источник - база данных только для чтения.
Если GET возвращает разные результаты для одного и того же URI, это нарушает идемпотентность / безопасность и принцип CoolURI и, следовательно, не является RESTful . Идемпотентные глаголы могут быть записаны в базу данных, но они никогда не должны влиять на представление.
Общий поиск начинается с запроса POST, который возвращает ссылку на результат. Он генерирует результат (он новый и может быть получен с последующим GET). Этот результат, конечно, может быть иерархическим (дополнительные ссылки с URI, которые вы можете получить GET) и может повторно использовать элементы более ранних поисков, если это имеет смысл для приложения.
Кстати, я знаю, что люди делают это по-другому. Вам не нужно объяснять мне, как удобно нарушать REST.
источник