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

das*_*tan 21 api rest

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

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

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

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

<different combination of arguments>
Run Code Online (Sandbox Code Playgroud)

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

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

Ped*_*eck 16

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

S3 REST API和POST方法

简而言之.

  • POST是用于任何未通过HTTP标准化的操作的方法,并使有效负载受到目标URI的约束.
  • PUT用于完全替换当前URI处的资源,并将有效负载置于服务本身.
  • PATCH用于部分幂等更新,在当前状态和期望状态之间具有差异.
  • DELETE用于删除资源.
  • GET用于检索资源.

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

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

例如:

GET /apple 

{"state": "whole",
 "self": "/apple"}
Run Code Online (Sandbox Code Playgroud)

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

PUT /apple

{"state": "sliced"}
Run Code Online (Sandbox Code Playgroud)

或者您可以执行以下操作:

PATCH /apple

{"from_state": "whole", "to_state": "sliced"}
Run Code Online (Sandbox Code Playgroud)

甚至是:

POST /apple

{"transition": "slice"}
Run Code Online (Sandbox Code Playgroud)

我们的想法是,实现可以是通用的,您不必过于担心将资源耦合到HTTP方法.

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

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

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

  • 两个人都不是RESTful.第一个要求整个有效载荷是颜色资源的表示.第二个暗示命令updateColor由apple资源本身执行.我可以看到`PUT/apple/color`是RESTful,如果'red'是具有apple.color属性的media-type的整个有效负载,但是第二个选项是无法修复的. (6认同)

Nic*_*nks 5

我的RESTful HTTP API与您的完全不同.我有:

GET用于获取的资源.
POST用于将新资源附加到集合.用于替换资源的
PUT(包括截断集合).
DELETE用于删除资源.用于更新资源的
PATCH.用于指示两个资源之间关系的
LINK.
UNLINK用于删除两个资源之间的关系.

"叶子"资源也可以被认为是一个集合.

例如,说你有/fruits,你POST一个apple到该集合资源,即回报

201 Created
Location: /fruits/apple
Run Code Online (Sandbox Code Playgroud)

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

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

GET /fruits/apple/colour
->
red

GET /fruits/apple/diameter
->
47mm
Run Code Online (Sandbox Code Playgroud)

因此:

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

GET /fruits/apple
->
colour=red&diameter=47mm&slices=12
Run Code Online (Sandbox Code Playgroud)

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