Разработка API запросов RESTful с длинным списком параметров запросов [закрыто]

153

Мне нужно спроектировать API запросов RESTful, который возвращает набор объектов на основе нескольких фильтров. Обычный метод HTTP для этого - GET. Единственная проблема заключается в том, что он может иметь по крайней мере дюжину фильтров, и если мы передадим все из них в качестве параметров запроса, URL-адрес может стать довольно длинным (достаточно длинным, чтобы быть заблокированным каким-либо брандмауэром).

Уменьшение количества параметров не вариант.

Я мог бы придумать одну альтернативу - использовать метод POST для URI и отправить фильтры как часть тела POST. Это против того, чтобы быть RESTfull (Выполнение вызова POST для запроса данных).

У кого-нибудь есть лучшие дизайнерские предложения?

missionE46
источник
2
Использовать короткие (1 символ и т. Д.) Имена параметров?
Madbreaks
2
Это может быть не совсем RESTful, но я думаю, что вы должны быть практичными, когда дело доходит до GET и POST. Если у вас есть так много переменных для отправки, и вы не можете их уменьшить, я бы ПОСТ их. Я не люблю набивать URL, но это только я.
Даг Доусон
Спасибо. Хотя этот вопрос закрыт, это именно тот вопрос, на который мне нужен был ответ. Я рад, что ты спросил.
Кейси Крукстон

Ответы:

142

Помните, что с REST API все зависит от вашей точки зрения.

Двумя ключевыми понятиями в REST API являются конечные точки и ресурсы (сущности). Проще говоря, конечная точка либо возвращает ресурсы через GET, либо принимает ресурсы через POST и PUT и т. Д. (Или комбинацию вышеперечисленного).

Принято считать, что с помощью POST отправляемые вами данные могут или не могут привести к созданию нового ресурса и связанных с ним конечных точек, которые, скорее всего, не будут «жить» под URL-адресом POST. Другими словами, когда вы отправляете POST, вы отправляете данные куда-то для обработки. Конечная точка POST находится не там, где обычно может быть найден ресурс.

Цитата из RFC 2616 (с опущенными нерелевантными частями и выделенными соответствующими частями):

9,5 ПОСТ

Метод POST используется для запроса, чтобы исходный сервер принял объект, включенный в запрос, в качестве нового подчиненного ресурса, идентифицируемого Request-URI в строке запроса. POST разработан для того, чтобы унифицированный метод мог выполнять следующие функции:

  • ...
  • Предоставление блока данных, такого как результат отправки формы, процессу обработки данных;
  • ...

...

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

Если ресурс был создан на исходном сервере, ответ ДОЛЖЕН быть 201 (Создан) ...

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

Рассмотрим следующий пример:

GET    /books?author=AUTHOR
POST   /books
PUT    /books/ID
DELETE /books/ID

Это типичный REST CRUD. Однако что если мы добавим:

POST /books/search

    {
        "keywords": "...",
        "yearRange": {"from": 1945, "to": 2003},
        "genre": "..."
    }

В этой конечной точке нет ничего плохого. Он принимает данные (сущность) в виде тела запроса. Эти данные являются критериями поиска - DTO, как и любой другой. Эта конечная точка создает ресурс (сущность) в ответ на запрос: Результаты поиска . Ресурс результатов поиска является временным ресурсом, который незамедлительно предоставляется клиенту, без перенаправления и без предоставления какого-либо другого канонического URL.

Это все еще REST, за исключением того, что сущности не являются книгами - сущность запроса - это критерии поиска книг, а сущность ответа - результаты поиска книг.

Амир Абири
источник
Не могли бы вы предложить некоторые соглашения об именах классов для DTO?
Квадз
Лично я бы пошел с BooksSearchCriteriaDTOи BooksSearchResultsDTO.
Амир Абири
Какой код ответа HTTP будет лучшим для этого случая POST / books / search? 201 еще применяется?
Л. Holanda
9
201 противоположен - это означает, что ресурс был создан. Ресурс, который где-то должен иметь свой уникальный URI. 201 подходит POSTдля C-части CRUD. Я бы выбрал обычные старые 200, возможно, с 204 для пустых результатов поиска.
Амир Абири
@AmirAbiri большое спасибо.
Мохамед-Мхири
84

Многие люди согласились с практикой, что GET со слишком длинной или слишком сложной строкой запроса (например, строки запроса не обрабатывают вложенные данные легко) вместо этого можно отправлять как POST, причем сложные / длинные данные представлены в теле запроса.

Посмотрите спецификацию для POST в спецификации HTTP. Это невероятно широко. (Если вы хотите проплыть линкор через лазейку в REST ... используйте POST.)

Вы теряете некоторые преимущества семантики GET ... например, автоматические повторы, потому что GET является идемпотентом, но если вы можете с этим смириться, может быть проще просто принять обработку действительно длинных или сложных запросов с помощью POST.

(Длинное отступление ... Я недавно обнаружил, что по спецификации HTTP, GET может содержать тело документа. Есть один раздел, который говорит, перефразируя: «Любой запрос может иметь тело документа, кроме перечисленных в этом разделе» ... и раздел, на который он ссылается, ничего не перечисляет. Я искал и нашел поток, где авторы HTTP говорили об этом, и это было сделано намеренно, так что маршрутизаторам и тому подобному не пришлось бы различать разные сообщения. попрактикуйтесь во многих элементах инфраструктуры, которые действительно отбрасывают тело GET. Таким образом, вы можете получить GET с фильтрами, представленными в теле, например, POST, но вы будете бросать кости.)

обкрадывать
источник
11
Смотрите также этот вопрос для дальнейшего обсуждения HTTP GET с телом.
RickyA
6

В двух словах: создайте POST, но переопределите HTTP-метод, используя заголовок X-HTTP-Method-Override .

Реальный запрос

ПОСТ / книги

Тело сущности

{"title": "Ipsum", "year": 2017}

Заголовки

X-HTTP-Method-Override: GET

На стороне сервера проверьте, существует ли заголовок X-HTTP-Method-Override, затем примите его значение в качестве метода для построения маршрута к конечной конечной точке в серверной части. Также возьмите тело объекта в качестве строки запроса. С внутренней стороны запрос стал просто GET.

Таким образом, вы сохраняете дизайн в гармонии с принципами REST.

Изменить: Я знаю, что это решение изначально предназначалось для решения проблемы глагола PATCH в некоторых браузерах и серверах, но оно также работает для меня с глаголом GET в случае очень длинного URL, который является проблемой, описанной в вопросе.

Delmo
источник
2
IETF осудил HTTP-заголовки с префиксом X: tools.ietf.org/html/rfc6648
Яннис
@jannis RFC, на который вы ссылаетесь, остается 1.4. не дает никаких рекомендаций относительно существующего X-удаления и 1.5. он не отменяет существующие спецификации. ... X-останется ли ИМО здесь.
Ян Молнар
-3

Если вы разрабатываете на Java и JAX-RS, я рекомендую вам использовать @QueryParam с @GET

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

Смотрите пример:

import java.util.List;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Response;

@Path("/poc")
public class UserService {

    @GET
    @Path("/test/")
    @Produces(MediaType.APPLICATION_JSON)
    public Response test(@QueryParam("code") final List<Integer> code) {
                Integer int0 = codigo.get(0);
                Integer int1 = codigo.get(1);

        return Response.ok(new JSONObject().put("int01", int0)).build();
    }
}

Шаблон URI: «poc / test? Code = 1 & code = 2 & code = 3»

@QueryParam автоматически преобразует параметр запроса «orderBy = age & orderBy = name» в java.util.List.

acacio.martins
источник
Было бы лучше, если бы вы объяснили свой пример. На каком языке программирования это написано?
Алекс Андреев
Привет @АлексАндреев. Спасибо за ваше мнение. Стало лучше? tks
acacio.martins
Этот вопрос касается дизайна службы RESTful, а не реализации. Этот ответ не отвечает на вопрос.
Еретик Обезьяна
@ user1331413 ИМХО да, теперь лучше. Спасибо за ваши усилия. Однако, как сказал Майк МакКоган, вопрос касается концепции REST, а не ее реализации
Алекс Андреев