使用一长串查询参数设计RESTful查询API

时间:2013-01-07 18:57:08

标签: api rest http-parameters

所以,我需要设计一个RESTful查询API,它基于一些过滤器返回一组对象。通常的HTTP方法是GET。唯一的问题是,它可以至少有十几个过滤器,如果我们将所有过滤器作为查询参数传递,则URL可能会变得很长(足够长以被某些防火墙阻止)。

减少参数数量不是一种选择。

我能想到的另一个选择是在URI上使用POST方法并将过滤器作为POST主体的一部分发送。这是不是RESTfull(对查询数据进行POST调用)。

任何人都有更好的设计建议吗?

由于

4 个答案:

答案 0 :(得分:101)

请记住,使用REST API,这都是您的观点问题。

REST API中的两个关键概念是端点和资源(实体)。松散地说,端点要么通过GET返回资源,要么通过POST和PUT等接受资源(或者上面的组合)。

接受POST后,您发送的数据可能会也可能不会导致创建新资源及其关联的端点,这很可能不会在POSTed网址下“生存”。换句话说,当您发布POST时,您可以将数据发送到某处进行处理。 POST端点不是通常可以找到资源的地方。

RFC 2616引用(省略了相关部分,突出显示了相关部分):

  

9.5 POST

     

POST方法用于请求源服务器接受   请求中包含的实体作为资源的新下属   由请求行中的Request-URI标识。 POST旨在   允许统一的方法来涵盖以下功能:

     
      
  • ...
  •   
  • 向数据处理流程提供数据块,例如提交表单的结果;
  •   
  • ...
  •   
     

...

     

POST方法执行的操作可能不会产生可由URI识别的资源。在这种情况下,200(OK)或204(No Content)是适当的响应状态,具体取决于响应是否包含描述结果的实体

     

如果在源服务器上创建了资源,则响应应为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": "..."
    }

这个端点没有任何非RESTful的东西。它以请求体的形式接受数据(实体)。该数据是搜索条件 - 与任何其他DTO一样。此端点生成响应请求的资源(实体):搜索结果。搜索结果资源是临时资源,立即提供给客户端,没有重定向,也没有从其他规范网址中公开。

它仍然是REST,除了实体不是书籍 - 请求实体是书籍搜索标准,而响应实体是书籍搜索结果。

答案 1 :(得分:71)

许多人已经接受了这样的做法:查询字符串太长或太复杂的GET(例如查询字符串不能轻易处理嵌套数据)可以作为POST发送,而复杂/长数据代表在请求的正文中。

在HTTP规范中查找POST的规范。这是非常广泛的。 (如果你想通过REST中的漏洞驾驶战舰......请使用POST。)

你失去了GET语义的一些好处......就像自动重试一样,因为GET是幂等的,但是如果你能接受它,那么接受使用POST处理真正冗长或复杂的查询可能更容易。

(lol long digression ...我最近发现,通过HTTP规范,GET 可以包含一个文档正文。有一节说明,“释义”,任何请求都可以有一个文档正文本节中列出的那些“......和它引用的部分没有列出任何内容。我搜索并找到了一个HTTP作者正在讨论的线程,这是有意的,所以路由器等不会必须要区分不同的消息。但是,实际上很多基础设施都会丢弃GET的主体。所以你可以使用体内代表的过滤器来获取,比如POST,但你要掷骰子。)< / p>

答案 2 :(得分:6)

简而言之:使用 X-HTTP-Method-Override 标头进行POST但覆盖HTTP方法。

真实请求

POST / books

实体正文

{   &#34; title&#34;:&#34; Ipsum&#34;,   &#34;年&#34;:2017年 }

<强>接头

X-HTTP-Method-Override:GET

在服务器端,检查是否存在标头X-HTTP-Method-Override,然后将其值作为构建到后端中最终端点的路由的方法。另外,将实体主体作为查询字符串。从后端的角度来看,请求只是一个简单的GET。

通过这种方式,您可以使设计与REST原则保持一致。

编辑:我知道这个解决方案最初是为了解决某些浏览器和服务器中的PATCH动词问题,但是对于我来说,对于我来说,如果网址很长就会出现GET动词在问题中描述。

答案 3 :(得分:-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&amp; code = 2&amp; code = 3

@QueryParam 会自动将查询参数“orderBy = age&amp; orderBy = name”转换为java.util.List。