Дизайн REST URL для операций больше, меньше, чем - PullRequest
27 голосов
/ 06 января 2011

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

Разбиение на страницы:

GET /customers/0/100

Получит 100 клиентов на страницу 0.

Больше / меньше, чем:

Мне также нужен дизайн URL, чтобы получить клиентов с идентификатором больше n (например, допустим, 716).Как бы вы включили «больше чем» или «меньше чем» в URL?Я должен помнить, что символы ">" и "<" недопустимы в URL.Я думаю, что этот дизайн URL выглядит странно: </p>

GET /customers/greaterthan/716
GET /customers/lessthan/716

Я не могу использовать диапазон, поскольку он конфликтует с шаблоном нумерации страниц, указанным выше, и не является хорошим решением в любом случае, например:

GET /customers/716/999999999999
GET /customers/0/716

Я уверен, что упускаю что-то очевидное - у кого-нибудь есть лучшее решение?

Ответы [ 9 ]

31 голосов
/ 06 января 2011

Разбиение на страницы , больше и меньше для меня звучит как параметр запроса, поскольку вы запрашиваете ресурс с этими параметрами. Поэтому вы должны сделать что-то вроде:

/ клиенты? Страница = 1 или
/ клиенты? Страница = 1 & gt = 716 или
/ клиенты? Страница = 1 & gt = 716 & lt = 819

Вы можете даже ограничить размер страницы:

/ клиенты? Страница = 1 & gt = 716 & lt = 819 & maxpagesize = 100

, где gt означает больше чем (так же, как в xml-escapeing), а lt означает меньше чем.

16 голосов
/ 22 ноября 2012

Если у вас есть несколько параметров и вам нужно применить некоторые условия для каждого параметра, я рекомендую вам передать объект JSON в параметры.

Предположим, вы хотите выполнить условие для id и page:

/customers?id={"lt": 100, "gt": 30}&page={"start": 1, "size": 10}

В нем говорится, что я хочу, чтобы клиенты с Id меньше 100 и больше 30 на странице 1 и из 10.

Так что теперь просто, если вы хотите применить другое условие для других параметров, вы можете сделать это:

/customers?id={"lt": 100, "gt": 30}&children={"lt": 5, "gt": 2}&page={"start": 1, "size": 10}

и этот запрос означает, что клиенты с Id меньше 100 и больше 30, дети меньше 5 и больше 2 в номере страницы 1 с размером страницы из 10.

Я настоятельно рекомендую вам прочитать этот документ о разработке RESTful API: http://blog.luisrei.com/articles/rest.html

7 голосов
/ 16 ноября 2012

@ Хулио Фаерман:

Ну, проблема начинается, когда вы получаете несколько параметров.Представьте себе строку запроса для «Клиенты старше 18 лет и моложе 60 лет с более чем двумя детьми».

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

/customers?min-age=19&max-age=59&min-children=3

в моем примере min и max являются целыми числами и включают в себя.Вы можете изменить это, если хотите.Помните, что все в URI означает часть идентификатора ресурса.Мое личное мнение состоит в том, что вещи после ? приравниваются к предложениям в части WHERE SQL-запроса (плюс ORDER BY и LIMIT, не показанные здесь):

SELECT * FROM customers WHERE age>=19 AND age<=59 AND children>=3

Редактировать:
Вместо префиксов min- и max- можно разрешить >, < (и, возможно, !) в качестве конечного символа имени параметра, поэтому вместо min-age у вас есть параметр с именем age>, который в сочетании со значением в строке запроса в конечном итоге будет выглядеть как age>=19: -)
Очевидно, вы можете использовать этот трюк только тогда, когда сравнение имеет знак равенствав нем.

7 голосов
/ 06 января 2011

REST - это архитектурный стиль, который не следует рассматривать как специфический для HTTP. Шаблон URI - это не то, что делает архитектуру RESTful.

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

/customers?min=0&max=76
2 голосов
/ 30 декабря 2016

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

{
    "protocol": "http",
    "host": "example.domain.com",
    "path": "/apis/classified/server/logs",
    "method": "GET",
    "ip": "::ffff:127.0.0.1",
    "time": 1483066346338,
    "usingTime": 12,
    "status": 200,
    "headers": {
        "user-agent": "Mozilla/5.0 Chrome"
    }
}

И вы хотите сделать запрос следующим образом, где

  • protocol равно 'http'.
  • host равно 'example.domain.com' или не равно 'example.domain.me'.
  • path равно '/apis/classified/server/logs' или нравится /*classified\/server*/.
  • method равно 'DELETE' или не равно 'GET' или ['POST', 'PUT', 'DELETE'].
  • ip равно '127.0.0.1' или не равно '127.0.0.1'.
  • usingTime больше 3500 или больше или равно 1500 и меньше или равно 3500.
  • status равно 404 или не равно 200 или больше или равно 400 и меньше 500.
  • headers.user-agent лайки /*chrome*/i.

Здесь маршруты идут так:

  • /apis/classified/server/logs?path=/apis/classfied
  • /apis/classified/server/logs?path.regex=*classfied*
  • /apis/classified/server/logs?method.ne=GET
  • /apis/classified/server/logs?method=POST&method=PATCH&method=PUT
  • /apis/classified/server/logs?usingTime.gte=1500&usingTime.lte=2500
  • /apis/classified/server/logs?headers.user-agent.regex=*chrome*

Если вы используете express.js в качестве сервера, ваш запрос req.query будет структурирован как:

  • {"path": "/apis/classfied"}
  • {"path": {"regex": "*classfied*"}}
  • {"method": "DELETE"}
  • {"method": ["GET","POST","PUT"]}
  • {"usingTime": {"gte": "1500","lte": "2500"}} (lte: меньше или равно)
  • {"status": {"ne": "200"}}} (ne: не равно)
  • {"path": {"regex": "*classfied*"}}
  • {"headers": {"user-agent": {"regex": "*chrome*", "flag": "i"}}}

И вы собираетесь использовать множество if-else дляПридумайте метод запроса mongoose или строку SQL.

1 голос
/ 21 ноября 2012

Я бы реализовал его как диапазон, и если любая из сторон открыта, просто не заполняйте его.

GET /customers/16-
GET /customers/-716

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

GET /customers

Или, когда вам нужно - введите свой номер / код, используйте это:

GET /customers/16/
GET /customers//716
GET /customers/16/716

Вы можете избежать косой черты, если они являются частью номера.

0 голосов
/ 23 мая 2017

Некоторые стандарты на основе REST предлагают адекватные подходы к этой проблеме.Например, https://www.hl7.org/fhir/stu3/search.html

Ваша проблема может быть решена следующим образом: GET /customers?id=ge500&id=lt1000

Также есть OData , которая гораздо более совместима, чем любой стандарт промышленного уровня.,И он предлагает этот стиль: GET /customers?$filter=id ge 500 and id lt 1000

0 голосов
/ 18 октября 2016

ВНИМАНИЕ: Прочитайте заявление об отказе от ответственности ниже

Я не знаю, связана ли эта очередь с c #.Но если вы используете linq для запросов на стороне сервера, у меня есть еще одно предложение:

GET /customers?filter=CustomerNo>=16 AND CustomerNo<=716

Затем, на стороне сервера:

using System.Linq.Dynamic;

var filteredCustomers = myCustomerTable.Where(filter);

Это должно быть наиболее гибкимЯ думаю, что это решение всех проблем.


ПРЕДУПРЕЖДЕНИЕ добавлено 19 января 2017 г. Только что привлек мое внимание, что существует эксплойт для внедрения кода для Dynamic Linq.Приведенный выше пример открывает возможность того, что клиент может начать выполнение кода на сервере.

0 голосов
/ 06 января 2011

Я бы взял

 GET /customers/greaterthan=16;lessthan=716/

так как порядок не важен. Вы можете даже разбить на страницы сверху:

 GET /customers/greaterthan=16;lessthan=716/page/10

В качестве альтернативы (с соответствующим маршрутизатором запроса):

 GET /customers/16-716/page/10

и без «фильтра»:

 GET /customers/all/page/10
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...