在同一URI上执行多个操作时的RESTful API

时间:2014-10-19 04:20:44

标签: api rest

据我所知,RESTful API中使用了四种方法:

获取资源的

GET 用于更新资源的 POST 用于创建或替换资源的 PUT DELETE 用于删除资源。

假设我们有一个名为apple的资源,我们可以通过多种方式“更新”它。例如,将其切成薄片,切片或制成苹果汁 这三种不同的更新操作中的每一种都采用不同的参数,并且它们的API中,共同的部分将是:

POST /apple HTTP/1.1
Host: www.example.com

<different combination of arguments>

在这种情况下,三个API共享相同的URI和相同的请求方法,它们的唯一区别是参数。我认为这迫使后端准备好接受这些参数的联合集,并且为了区分实际请求的动作,后端需要检查参数的组合。它太复杂而且不优雅。

所以我的问题是:
在这个苹果案例中,如何设计出一套优雅的RESTful API,使后端可以轻松处理。

4 个答案:

答案 0 :(得分:15)

首先,尽量避免将HTTP方法与CRUD操作混淆。我相信这是REST中混淆的主要原因。 HTTP方法不像这样干净地转换为CRUD操作。我在这里有一个详细的答案:

S3 REST API and POST method

简而言之。

  • POST是用于任何未经HTTP标准化的操作的方法,并将有效负载置于目标URI中。
  • PUT用于完全替换当前URI的资源,并将有效负载置于服务本身。
  • PATCH用于部分幂等更新,在当前状态和所需状态之间存在差异。
  • DELETE用于删除资源。
  • GET用于检索资源。

现在,在后端方面,尝试将REST资源更像是一个状态机,您可以使用这些方法来强制转换而不是使用方法的对象。这样您就可以将实现集中在资源本身上,而不是与协议的交互上。例如,您可以直接从方法的有效负载中更改对象的属性,然后调用一个方法来检测所需的转换。

例如,您可能会认为苹果有三种状态,整个,削皮,切片和榨汁。您可以使用方法的标准化行为在状态之间转换。

例如:

GET /apple 

{"state": "whole",
 "self": "/apple"}

然后你要切片。你可以这样做:

PUT /apple

{"state": "sliced"}

或者您可能会这样做:

PATCH /apple

{"from_state": "whole", "to_state": "sliced"}

甚至可能是:

POST /apple

{"transition": "slice"}

这个想法是实现可以是通用的,你不必过于担心将资源耦合到HTTP方法。

  • PUT版本是幂等的,因此您的客户可以选择在需要幂等时使用它。
  • PATCH版本保证客户端知道当前状态并尝试有效转换。
  • POST版本是最灵活的,你可以做任何你想做的事情,但需要详细记录。您不能简单地假设您的客户将知道该方法的工作原理。

只要您的资源实现了解当apple.state更改为其他内容时,它应检测发生了哪些更改并执行适当的转换,您就完全脱离了协议。使用什么方法并不重要。

我相信这是最优雅的解决方案,让后端更容易处理。您可以实现您的对象,而无需过多担心协议。只要对象可以在状态之间转换,任何可以影响这些转换的协议都可以使用它们。

答案 1 :(得分:5)

我的RESTful HTTP API与您的非常相似。我有:

GET 获取资源 POST ,用于将新资源附加到集合中 用于替换资源的 PUT (包括截断集合) 删除以删除资源 用于更新资源的 PATCH LINK 用于指示两个资源之间的关系 取消链接用于删除两个资源之间的关系。

'leaf'资源也可以被认为是一个集合。

例如,假设您有/fruits POST apple到该集合资源,则会返回

201 Created
Location: /fruits/apple

以同样的方式,您可以将/fruits/apple视为其属性的集合,因此:

GET /fruits/apple
->
colour=red&diameter=47mm

GET /fruits/apple/colour
->
red

GET /fruits/apple/diameter
->
47mm

因此:

PUT /fruits/apple/slices
"12"
->
201 Created

GET /fruits/apple
->
colour=red&diameter=47mm&slices=12

总而言之,我建议将您的操作表示为名词,并将这些名词定位为您要将操作应用到的资源的子资源。

答案 2 :(得分:1)

从资源角度思考。 Apple是一个资源。

要添加一个或多个苹果以列出“/ apples”,请使用POST。 REST样式允许发布数组。

POST /apples HTTP/1.1
Host: www.example.com

现在假设您有一个ID为123的苹果。您可以使用“/ apple / 123”上的方法GET获取详细信息。

GET /apples/123 HTTP/1.1
Host: www.example.com

要对apple 123进行任何更改,只需直接发送到它。

PUT /apples/123 HTTP/1.1
Host: www.example.com

削减它,切片,或者做成苹果汁 - 这些都基本上改变了苹果123的一些属性。正如你所说的那样(正确),PUT不同的属性组合。

答案 3 :(得分:0)

我认为这取决于实施者的决定,但我看到了两种方法。从单一责任的角度来看,为这些不同的操作提供单独的服务可能是有意义的。

但是,如果你坚持单一服务,我猜你可以传递一个带有动作类型限定符的对象,以便于将请求委托给服务中的不同代码。然后,单个对象可以具有其他可选参数,以支持每个操作的数据需求。