RESTful服务中的非CRUD操作


106

将非CRUD操作添加到RESTful服务的“ RESTful”方式是什么?假设我有一项服务,允许CRUD访问以下记录:

GET /api/car/123           <- Returns information for the Car object with ID 123
POST /api/car              <- Creates a new car (with properties in the request)
PUT /api/car/123           <- Updates car 123 (with properties in the request)
DELETE /api/car/123        <- Deletes car 123    
POST /api/car/123/wheel/   <- Creates a wheel and associates it to car 123

如果要更改汽车的颜色,则只需POST /api/car/123添加新颜色的POST变量即可。

但是,假设我要购买汽车,并且该操作比简单地更新“用户”记录的“自有汽车”属性要复杂得多。简单地做类似RESTful的事情POST /api/car/123/purchase,其中“购买”本质上是一个方法名称?还是应该使用自定义HTTP动词,例如PURCHASE代替POST

还是非CRUD操作完全超出REST的范围?


5
如果要更改汽车的颜色,最好使用PATCH /api/car/123并发送颜色参数,或者使用PUT /api/car/123并发送整个汽车对象。POST会推断您正在制造一辆新车,并且可能永远不应在URL末尾包含id
RonnyKnoxville

Answers:


65

考虑将购买作为业务实体或RESTful词典中的资源。话虽如此,购买实际上是在创造新的资源。所以:

POST /api/purchase

将下新订单。详细信息(用户,汽车等)应通过发送到该地址的内容中的id(或URI)进行引用。

预订汽车并不只是数据库中的简单INSERT。实际上,REST与将数据库表公开为CRUD操作无关。从逻辑的角度来看,您正在创建订单(购买),但是服务器端可以根据需要自由执行任意数量的处理步骤。

您甚至可以进一步滥用HTTP协议。使用Location标头将链接返回到新创建的订单,仔细选择HTTP响应代码以通知用户有关问题(服务器端或客户端)等。


3
REST就是要处理资源的状态,每个业务操作都必须映射到状态CRUD操作。如果您需要严格的业务操作语义,则必须采用SOAP方式(SOAP实际上是消息传递,但是通常以请求-响应操作进行组织)。
Tomasz Nurkiewicz

23
“以资源采购”设计看起来很整洁。如果资源是“啤酒” ..并且我希望服务器喝它..(这是我的话,我肯定会得到它;))。 ?!..还是“喝啤酒”,一项艰苦的业务运营?更严重的是,RESTful设计是否将动作视为资源?!
。– Myobis

2
您将如何通过REST服务公开“批准采购订单”?我认为@TomaszNurkiewicz是正确的,因为任何无法以CRUD方式整齐地完成的工作都将需要SOAP提供的操作语义。除非“采购订单批准”是一个单独的模型/实体。例如POST / po-approval(请求中包含PO详细信息)。
mydoghasworms

2
从REST客户端的角度来看,“批准采购订单”应该只是该订单的另一个更新。例如,将“已批准”更改为“ true”,然后将更新发送到服务器。服务器可能需要进行大量检查,并且可能需要更新/创建其他资源。但这是服务器的问题,客户端不应该看到。
AVee

2
@antinome:“假设客户端知道其中的一些内容”,如果是这种情况,您就不进行REST(尽管它可能仍然是有效的,明智的软件!)。REST被设计为能够创建不知道那种事情的客户端,并创建在服务器的行为发生变化时仍可以工作的客户端。您想要做的是经典的RPC,您要么需要检查自己的方法以使其适合REST,要么接受您正在使用RPC并使用针对RPC的协议(例如SOAP)。REST非常努力地不成为RPC,因此当您想要/需要RPC时,它永远不会是一个合适的选择。
AVee

15

据我了解,REST式的方式是您不需要新的HTTP动词,某处有一个名词表示您需要做的事情。

买车?那不是吗

POST /api/order

2
因为PUT 是幂等的,所以不用于更新资源吗?这意味着您可以根据需要多次调用它,但是只有第一个/最后一个调用很重要。另一方面,POST用于创建资源,两次调用实际上应该创建两次。
Tomasz Nurkiewicz 2011年

1
@Tomas,是的,错别字。原则很重要,但是我们正在处理一个新事物,一个命令,不需要一个新的动词。
djna 2011年

5

您真正要做的是创建订单。因此,为订单添加另一个资源,然后在订单过程中过帐并放置在那里。

考虑资源而不是方法调用。

要最终确定订单,您可能需要POST / api / order // complete或类似的命令。


3

我觉得REST API不仅提供语义,还提供了更多帮助。因此,不能仅仅因为某些调用在RPC操作风格中似乎更有意义而选择RPC风格。示例是Google Maps API,用于查找两个地方之间的路线。看起来像这样:http : //maps.googleapis.com/maps/api/directions/json? origin=Jakkur&destination= Hebbal

他们可以将其称为“ findDirections”(动词)并将其视为一个操作。相反,他们将“方向”(名词)作为资源,并将查找方向作为对方向资源的查询(尽管在内部可能没有称为方向的真实资源,并且可以由业务逻辑实现以基于参数查找方向)。


那是一个不好的例子。在这种情况下,方向(所有可能的方向,无穷多个)就是资源,参数只是过滤器。但是您不能对此进行“购买”,因为过滤器仅对获取操作,下订单或取消订单有意义,因为这些操作会更改数据
Tseng 2015年

2
购买将是POST到/ order并在正文中带有json,表示已创建订单。cancel将通过将带有订单状态更改的json放置到/ order来指示这是幂等更新。我仍然会遇到无法以资源格式表示的操作。因此,我们很希望看到这样的例子
Maruthi 2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.