如何deviseRESTfulsearch/过滤?

我目前正在用PHPdevise和实现一个RESTful API。 但是,我一直没有成功实施我的初步devise。

GET /users # list of users GET /user/1 # get user with id 1 POST /user # create new user PUT /user/1 # modify user with id 1 DELETE /user/1 # delete user with id 1 

到目前为止相当标准,对吧?

我的问题是第一个GET /users 。 我正在考虑发送请求体中的参数来过滤列表。 这是因为我想能够指定复杂的filter而不需要一个超长的URL,如:

 GET /users?parameter1=value1&parameter2=value2&parameter3=value3&parameter4=value4 

相反,我想有这样的东西:

 GET /users # Request body: { "parameter1": "value1", "parameter2": "value2", "parameter3": "value3", "parameter4": "value4" } 

这是更可读性,并给你很大的可能性来设置复杂的filter。

无论如何, file_get_contents('php://input')没有返回GET请求的请求正文。 我也尝试http_get_request_body() ,但我使用的共享主机没有pecl_http 。 不知道这会有什么帮助。

我发现这个问题,并意识到GET可能不应该有一个请求的身体。 这有点不确定,但他们反对。

所以现在我不知道该怎么做。 你如何devise一个RESTfulsearch/过滤function?

我想我可以使用POST ,但这似乎不是很RESTful。

实现RESTfulsearch的最好方法是将search本身视为资源。 那么你可以使用POST动词,因为你正在创build一个search。 您不必从字面上创build一个数据库中的东西来使用POST。

例如:

 Accept: application/json Content-Type: application/json POST http://example.com/people/searches { "terms": { "ssn": "123456789" }, "order": { ... }, ... } 

您正在从用户的angular度创build一个search。 这个的实现细节是不相关的。 一些RESTful API甚至可能不需要持久性。 这是一个实现细节。

如果您在GET请求中使用请求主体,那么您违反了REST原则,因为您的GET请求将无法被caching,因为caching系统仅使用URL。

更糟糕的是,您的url不能加书签,因为该url并不包含将用户redirect到此页面所需的所有信息

使用URL或Query参数而不是请求主体参数。

例如:

 /myapp?var1=xxxx&var2=xxxx /myapp;var1=xxxx/resource;var2=xxxx 

实际上,HTTP RFC 7231说:

GET请求消息中的有效载荷没有定义的语义; 在GET请求上发送有效负载体可能会导致一些现有的实现拒绝请求。

欲了解更多信息, 请看这里

似乎资源过滤/search可以用RESTful方式实现。 这个想法是引入一个叫做/filters//api/filters/的新端点。

使用这个端点filter可以被认为是一个资源,因此通过POST方法创build。 这样 – 当然,body可以用来承载所有的参数以及复杂的search/filter结构。

创build这样的filter后,有两种可能性来获得search/过滤结果。

  1. 具有唯一ID的新资源将随“ 201 Created状态码一起返回。 然后使用这个ID可以对/api/users/ like做一个GET请求:

     GET /api/users/?filterId=1234-abcd 
  2. 通过POST创build新的filterPOST它不会回复201 Created但立即与303 SeeOther以及Location标题指向/api/users/?filterId=1234-abcd 。 这个redirect将通过底层库自动处理。

在这两种情况下,需要两个请求来获得过滤结果 – 这可能被认为是一个缺点,特别是对于移动应用程序。 对于移动应用程序,我会使用单个POST调用/api/users/filter/

如何保持创build的filter?

他们可以存储在数据库中,以后使用。 他们也可以存储在一些临时存储,如redis,并有一些TTL之后,他们将过期,将被删除。

这个想法的优点是什么?

filter,过滤的结果是可caching的,甚至可以书签。

我想你应该去请求参数,但只要没有一个合适的HTTP头来完成你想要做的事情。 HTTP规范没有明确地说,GET不能有一个主体。 但是这篇论文指出:

按照惯例,当使用GET方法时,标识资源所需的所有信息都被编码在URI中。 在HTTP / 1.1中没有规定安全交互(例如,检索)的地方,客户端在HTTP实体主体中提供数据给服务器,而不是在URI的查询部分。 这意味着为了安全操作,URI可能很长。

如果您的初始API完全是RESTful或者不是,那么不要太担心(尤其是当您处于alpha阶段时)。 获得后端pipe道首先工作。 你总是可以做一些URL转换/重写来映射,迭代地进行改进,直到你得到足够稳定的广泛testing(“beta”)。

你可以定义URI的参数是按照URIs上的位置和约定进行编码的,前缀是一个你知道总是映射到某个东西的path。 我不知道PHP,但我会认为这样的设施存在(因为它存在于其他语言与Web框架):

.IE。 对于存储#1中的i = 1..4,使用param [i] = value [i]做一个“用户”types的search(value1,value2,value3,…作为URI查询参数的缩写):

 1) GET /store1/search/user/value1,value2,value3,value4 

要么

 2) GET /store1/search/user,value1,value2,value3,value4 

或者如下(尽pipe我不会推荐它,稍后再介绍)

 3) GET /search/store1,user,value1,value2,value3,value4 

使用选项1,将以/store1/search/user为前缀的所有URI映射到search处理程序(或指定的PHP)默认searchstore1下的资源(相当于/search?location=store1&type=user

按照约定由APIlogging和实施,参数值1至4以逗号分隔并按照该顺序呈现。

选项2将searchtypes(在这种情况下为user )添加为位置参数#1。 这两个选项都只是一个化妆品的select。

选项3也是可能的,但我不认为我会喜欢它。 我认为在特定资源内search的能力应该在search本身之前的URI中呈现(就好像在URI中明确指出search在资源内是特定的那样)。

与在URI上传递参数相比,优点是search是URI的一部分(因此将search视为一种资源,这种资源的内容可以 – 而且会随时间而改变)。缺点是参数顺序是强制性的。

一旦你做了这样的事情,你可以使用GET,它将是一个只读的资源(因为你不能POST或PUT到它 – 获取时得到更新)。 它也将是一个资源,只有当它被调用时才存在。

也可以通过将结果caching一段时间或使用DELETE导致caching被删除来为其添加更多的语义。 然而,这可能与人们通常使用DELETE的情况相反(并且因为人们通常使用caching标题来控制caching)。

你如何去做是一个devise决定,但这将是我想要的方式。 这是不完美的,我敢肯定,会有这样做的情况下,不是最好的事情(特别是对于非常复杂的search条件)。

仅供参考:我知道这有点迟,但对于任何有兴趣的人。 取决于你想要如何RESTful,你将不得不实施自己的过滤策略,因为HTTP规范不是很清楚。 我想build议url编码所有的filter参数例如

 GET api/users?filter=param1%3Dvalue1%26param2%3Dvalue2 

我知道这是丑陋的,但我认为这是最RESTful的方式来做到这一点,应该很容易parsing在服务器端:)

当我使用laravel / php后端时,我倾向于使用类似这样的东西:

/资源?filter[STATUS_ID] = 1&滤波器[城市] =悉尼&页= 2&包括= relatedResource

PHP会自动将params变成一个数组,所以在这个例子中,我将最终得到一个$ filtervariables,它包含一个filter的数组/对象,以及一个页面和我想要加载的相关资源。

如果您使用其他语言,这可能仍然是一个很好的约定,您可以创build一个parsing器将[]转换为数组。