呼吁资源的服务器端方法REST方式 [英] Call a Server-side Method on a Resource in a RESTful Way

查看:156
本文介绍了呼吁资源的服务器端方法REST方式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请我有休息基本的了解。比方说,我有这个网址:

  http://api.animals.com/v1/dogs/1/

而现在,我想使服务器使狗叫。只有服务器知道如何做到这一点。比方说,我想有它的cron作业,使狗叫每10分钟为永恒的其余部分运行。这是什么电话是什么样子?我有种想做到这一点:

网址:

 操作http://api.animals.com/v1/dogs/1/

在请求正文:

  {行动:汪汪}

让你之前气死我作出了我自己的HTTP方法,帮助我,并给我我应该怎么REST方式调用服务器端方法更好的主意。 :)

编辑澄清

一些澄清更多的围绕着汪汪的方法做了什么。这里有一些可能会导致不同结构的API调用的选项:


  1. 树皮只是发送一封电子邮件dog.email并记录什么。

  2. 树皮发送一封电子邮件dog.email和增加1 dog.barkCount。

  3. 树皮创建了bark.timestamp记录一个新的汪汪记录时树皮发生。它还增加了1 dog.barkCount。

  4. 树皮运行系统命令拉最新版本的狗code从GitHub下来。然后它发送短信到dog.owner告诉他们,新的狗code是在生产中。


解决方案

为什么瞄准一个RESTful设计?

在RESTful的原则带来,使网站的功能很容易(为的随机人类用户的为冲浪他们)以Web服务API的设计,所以他们很容易为程序员使用。 休息不好,因为它的休息,这是好事,因为它是很好的。而这主要是好事,因为它是的简单

纯HTTP的简单(没有SOAP信封和单URI重载 POST 服务),什么有些人可能会调用的缺乏特色 ,其实就是其最大的优势。马上蝙蝠,HTTP要求你必须的寻址的和的无国籍的:两个基本的设计决策,保持HTTP可扩展到今天的大型网站(和大型服务)。

但REST是不是银bulltet:有时,RPC风格(远程过程调用 - 如SOAP)的可适当,有时其他需要采取precedence在Web上的美德。这可以。我们真的不喜欢什么的是不必要的复杂性即可。往往一个程序员或公司带来RPC样式的服务工作是普通的老HTTP可以处理得很好。其效果是,HTTP减少到传输协议,用于解释什么是真正走出产生巨大的XML有效载荷(不是URI或HTTP方法给出一个关于它的线索)。由此带来的业务太复杂,无法调试,并不会工作,除非你的客户都在精确设置作为开发者的预期。

同样的方式的Java / C#code能的的面向对象的,仅仅使用HTTP不会使设计REST风格。人们可以在匆忙赶了上来思维关于他的服务在行动和远程方法应称为条款。难怪这将主要在RPC式的服务(或者REST-RPC混合动力)结束。第一步是考虑不同。 REST风格的设计,可以通过多种方式来实现,一种方式(最简单的,有人可能会说)就是在资源方面考虑您的应用程序,而不是动作:


  • 相反的动作的时候,(做地图上的地点一搜)的,

  • 想在行动(地图匹配搜索条件的地方名单)结果的条款。

我会去下面的例子。
(REST的其他重要方面是使用HATEOAS的 - 这里我就不刷吧,但是我谈论它迅速地在另一篇文章

关于第一个设计

让我们来看看一个被提议的设计:

 操作http://api.animals.com/v1/dogs/1/

首先,我们不应该考虑创建一个新的HTTP动词 ACTION )。一般来说,这是的不良的有以下几个原因:


  • (1)由于只有服务URI,如何将一个随机程序员知道 ACTION 谓词存在?

  • (2)如果程序员知道它的存在,他怎么会知道它的语义?这是什么意思动词?

  • (3)应该想到的是动词有哪些?什么样的属性(安全,幂等)

  • (4)如果有什么程序员有一个非常简单的客户端,只处理标准的HTTP动词?

  • (5) ...

现在,让我们的考虑使用 POST (我将讨论为什么下面,只是把我的话了):

  POST / V1 /狗/ 1 / HTTP / 1.1
主持人:api.animals.com{行动:汪汪}

此的可能的是确定......但仅在


  • {行动:汪汪} 是一个文件;和

  • / V1 /狗/ 1 / 是送稿器(工厂等)URI。 <子> A文件处理是一个URI,你只是在扔东西和忘记对他们 - 处理器可在扔之后您重定向到一个新创建的资源。例如。该URI在消息代理服务,其中,后发布,你会重定向到一个URI,显示消息的处理状态发布消息。

我不知道很多关于你的系统,但我已经打赌,都是不正确的:


  • {行动:汪汪} 不是文档,它实际上与方法您正在尝试的忍者潜入的到服务;和

  • / V1 /狗/ 1 / URI重新presents狗资源(可能与 ID狗== 1 ),而不是一个文档处理器。

因此​​,所有我们现在知道的是,上面的设计不是那么RESTful的,但什么是什么呢? 什么是坏呢?基本上,这是不好的,因为这是复杂的URI复杂的含义。你不能推断任何事情。程序员怎么会知道狗有可与 POST偷偷注入一个树皮操作成吗?

设计你的问题的API调用

因此​​,让我们切入正题,并尝试通过资源的角度思考 REST风格设计的树皮。请允许我引用 RESTful Web服务书:


  

A POST 要求是试图从现有的创建新的资源
  一。现有的资源可以是在一个新的一个的父
  数据结构意义上,方式一树的根是所有的父
  它的叶节点。或者现有的资源可以是一个特殊的工厂
  资源的唯一目的是生成其他资源。该
  再以 POST 请求一起发送presentation描述初始
  新资源的状态。至于说,一个 POST 要求并不需要
  包括重新presentation的。


根据上面我们可以看到, 树皮 可以模拟为的子资源狗的说明 (因为树皮包含狗中,也就是说,树皮被咆哮狗)。

从这个推理,我们已经得到了:


  • 的方法 POST

  • 的资源 /树皮,狗的子资源: / V1 /狗/ 1 /树皮,再presenting一个树皮工厂。这URI是每个狗唯一的(因为它是在 / V1 /狗/ {ID} )。

现在您的列表中的每个案件都有特定的行为。

1。树皮只是发送电子邮件至dog.email并记录什么。

首先,乱叫(发送电子邮件)同步或异步任务?其次,树皮请求需要任何文件(电子邮件,也许)或者是空的?

1.1树皮发送一封电子邮件dog.email并记录任何操作(如同步任务)

此情况下,很简单。在皮呼叫工厂资源产生了树皮(发送电子邮件)马上和响应(如OK或不)给出马上

  POST / V1 /狗/ 1 /树皮HTTP / 1.1
主持人:api.animals.com
授权:基本mAUhhuE08u724bh249a2xaP =(实体主体是空的 - 或者,如果您需要** **文件,在这里把它) 200 OK

因为它记录(改变)什么都没有, 200 OK 就足够了。这表明,一切都如预期。

1.2树皮发送一封电子邮件dog.email并记录任何操作(如异步任务)

在此情况下,客户必须有一种方法来跟踪树皮任务。那么树皮任务应该是与它自己的URI的资源:

  POST / V1 /狗/ 1 /树皮HTTP / 1.1
主持人:api.animals.com
授权:基本mAUhhuE08u724bh249a2xaP =(文档正文,如果需要的话) 202接受
位置:http://api.animals.com/v1/dogs/1/bark/a65h44

这样,每个树皮是有迹可寻的。然后,客户机可以发出 GET 树皮 URI知道它的当前状态。甚至使用删除将其取消。

2。树皮1

发送一封电子邮件dog.email和增量dog.barkCount

这可以是棘手,如果你想让客户知道资源得到改变:

  POST / V1 /狗/ 1 /树皮HTTP / 1.1
主持人:api.animals.com
授权:基本mAUhhuE08u724bh249a2xaP =(文档正文,如果需要的话) 303查看其它
位置:http://api.animals.com/v1/dogs/1

在这种情况下,位置头的目的是让客户知道他应该看看 。从 HTTP RFC约 303


  

这主要方法存在允许的输出
   POST 激活的剧本以用户代理重定向到一个选择的资源。


如果任务是异步的,一个树皮子资源需要,就像 1.2 情况和 303 应该在 GET ... /树皮/ Y回复,当任务完成

3。树皮创建了bark.timestamp记录一个新的汪汪记录时树皮发生。它也递增1 dog.barkCount

  POST / V1 /狗/ 1 /树皮HTTP / 1.1
主持人:api.animals.com
授权:基本mAUhhuE08u724bh249a2xaP =(文档正文,如果需要的话) 201创建
位置:http://api.animals.com/v1/dogs/1/bark/a65h44

在这里,树皮是一个创建由于要求,因此状态 201创建适用

如果创作是异步的,一个 202接受要求(的作为HTTP RFC说)来代替。

保存的时间戳记是树皮资源的一部分,可以用 GET 中检索到它。在更新后的狗可以被记录在案 GET狗/ X /树皮/ Y 以及

4。树皮运行系统命令拉最新版本的狗code从GitHub下来。然后它发送短信到dog.owner告诉他们,新的狗code是在生产中。

这一块的措辞是复杂的,但它pretty多少是一个简单的异步任务:

  POST / V1 /狗/ 1 /树皮HTTP / 1.1
主持人:api.animals.com
授权:基本mAUhhuE08u724bh249a2xaP =(文档正文,如果需要的话) 202接受
位置:http://api.animals.com/v1/dogs/1/bark/a65h44

然后,客户端会发出 GET s到 / V1 /狗/ 1 /树皮/ a65h44 来知道当前状态(如果code被拔掉,它电子邮件发送给所有者和等)。每当狗的变化,一个 303 是appliable。

结束语

罗伊菲尔丁:


  

唯一REST要求的方法是,它们均匀
  对于所有的资源(即所定义,使中介不必
  知道资源类型,以理解的含义
  请求)。


在上面的例子中, POST 均匀设计。它会使狗树皮。这是不是安全的(即树皮对资源的影响),也不幂等(每个请求产生一个新的树皮),这适合 POST 动词很好。

一个程序员都知道:一个 POST 产生一个树皮。响应状态codeS(也与实体主体和头在必要时)做解释什么改变,以及如何在客户端能够和应该进行的工作。

<子>注:所用的主要来源是: RESTful Web服务的书,在<一个HREF =htt​​ps://tool​​s.ietf.org/html/rfc2616> HTTP RF C和 Roy Fielding的博客


更新:

原题问一个URI的喜欢设计:

 操作http://api.animals.com/v1/dogs/1/?action=bark

下面是为什么它是不是一个好的选择的解释:

客户端如何告诉服务器的​​主题旅游的数据是的方法的信息

哪一部分数据的 [客户端希望服务器]操作上是范围资讯

作为一个例子,拿谷歌的URI http://www.google.com/search?q=DOG 。在那里,法信息 GET 和范围界定信息 /搜索?Q = DOG

长话短说:

和经验法则:


  

如果HTTP方法不匹配方法的信息,服务不RESTful的。如果作用域信息是不是在URI,该服务没有资源化。


您可以把的汪汪动作的在URL(或实体主体),并使用 POST 。有没有问题,它的工作原理,并且可以做到这一点最简单的方法,但这不是RESTful的

要保持你的服务真REST风格,你可能要退一步,想想你真的想在这里做(这会对资源产生什么影响)。

我不能谈论特定的业务需求,还让我给你举个例子:假设一个RESTful订购服务,其中订单是在诸如 example.com/order/123

现在说,我们要取消订单,如何我们该怎么办呢?有人可能会认为这是一个的注销动作的并设计为 POST example.com/order/123?do=取消

这是不是平安,正如我们上面谈到。相反,我们不妨 PUT 订单取消了一个新的再presentation 发送到真元

  PUT /顺序/ 123 HTTP / 1.1
内容类型:应用程序/ XML&LT;订单id =123&GT;
    &LT;客户ID =89987&GT; ...&LT; /客户&GT;
    &LT;取消&GT;真&LT; /取消&GT;
    ...
&LT; /排序&gt;

就是这样。如果订单不能被取消,具体状态code可以退换。 (子资源的设计,如 POST /顺序/ 123 /注销通过实体主体真正可以,为简单起见,也可。)

在特定的情况下,您可以尝试类似的东西。这样一来,当狗乱叫,例如 GET / V1 /狗/ 1 / 可能包括信息(如&LT;&狂吠GT;真&LT; /乱叫&GT; 。或者......如果这是太复杂了,放松你的REST风格的要求,并与 POST

更新:

我不想让答案太大,但需要一段时间才能得到暴露的算法(一个的动作的)为一组资源的窍门。相反,在行动(的为地图上的地点进行搜索的)思维的,需要考虑该行动的结果方面(的上的位置列表地图匹配的搜索
标准
的)。

您可能会发现自己回来到了这一步,如果你发现你的设计不适合HTTP的统一接口。

查询变量的 范围资讯的,但这样做的不可以表示新的资源( /后?LANG = EN 显然是在相同资源作为 /后?LANG = JP ,不同的只是再presentation)。相反,它们是用来传达客户端状态(如页= 10 ,所以状态没有保存在服务器上; ?LANG = EN 也在这里一个例子)或输入参数算法资源的( /搜索] q =狗 /狗?code = 1 )。再次,不显着的资源。

HTTP动词(方法)属性:

另一个明显的一点,显示 =行动东西中的URI是不是平安,是HTTP动词的属性:?


  • GET HEAD 是安全的(和幂等);

  • PUT 删除是幂而已;

  • POST 两者都不是。

安全:A GET HEAD 请求是请求的一些数据,不改变任何服务器状态的请求。客户端可以使 GET HEAD 要求10倍,这是一样的做了一次,或从来没有使得它在所有

等幂:在一个具有您是否适用过一次或一次以上(在数学,零相乘是幂等)相同的效果幂等操作。如果您删除资源一次,再删除将具有相同的效果(资源 GONE 的话)。

<分> POST 既不安全也不是幂。制作两个相同的 POST 请求到工厂的资源可能会导致两个下属资源包含相同
信息。随着重载(URI中的方法或实体主体) POST ,全盘皆输。

这两个属性是很重要的HTTP协议的成功(在不可靠的网络!):有多少次你更新( GET )的页面,而无需等待,直到它满载?

创建的动作的,并把它放在URL显然打破了HTTP方法的合同。再次,技术允许你,你能做到这一点,但不是REST风格的设计。

Keep in mind I have a rudimentary understanding of REST. Let's say I have this URL:

http://api.animals.com/v1/dogs/1/

And now, I want to make the server make the dog bark. Only the server knows how to do this. Let's say I want to have it run on a CRON job that makes the dog bark every 10 minutes for the rest of eternity. What does that call look like? I kind of want to do this:

URL request:

ACTION http://api.animals.com/v1/dogs/1/

In the request body:

{"action":"bark"}

Before you get mad at me for making up my own HTTP method, help me out and give me a better idea on how I should invoke a server-side method in a RESTful way. :)

EDIT FOR CLARIFICATION

Some more clarification around what the "bark" method does. Here are some options that may result in differently structured API calls:

  1. bark just sends an email to dog.email and records nothing.
  2. bark sends an email to dog.email and the increments dog.barkCount by 1.
  3. bark creates a new "bark" record with bark.timestamp recording when the bark occured. It also increments dog.barkCount by 1.
  4. bark runs a system command to pull the latest version of the dog code down from Github. It then sends a text message to dog.owner telling them that the new dog code is in production.

解决方案

Why aim for a RESTful design?

The RESTful principles bring the features that make web sites easy (for a random human user to "surf" them) to the web services API design, so they are easy for a programmer to use. REST isn't good because it's REST, it's good because it's good. And it is good mostly because it is simple.

The simplicity of plain HTTP (without SOAP envelopes and single-URI overloaded POST services), what some may call "lack of features", is actually its greatest strength. Right off the bat, HTTP asks you to have addressability and statelessness: the two basic design decisions that keep HTTP scalable up to today's mega-sites (and mega-services).

But REST is not the silver bulltet: Sometimes an RPC-style ("Remote Procedure Call" - such as SOAP) may be appropriate, and sometimes other needs take precedence over the virtues of the Web. This is fine. What we don't really like is needless complexity. Too often a programmer or a company brings in RPC-style Services for a job that plain old HTTP could handle just fine. The effect is that HTTP is reduced to a transport protocol for an enormous XML payload that explains what's "really" going on (not the URI or the HTTP method give a clue about it). The resulting service is far too complex, impossible to debug, and won't work unless your clients have the exact setup as the developer intended.

Same way a Java/C# code can be not object-oriented, just using HTTP does not make a design RESTful. One may be caught up in the rush of thinking about his services in terms of actions and remote methods that should be called. No wonder this will mostly end up in a RPC-Style service (or a REST-RPC-hybrid). The first step is to think different. A RESTful design can be achieved in many ways, one way (the simplest, some might say) is to think of your application in terms of resources, not actions:

  • Instead of thinking in terms of actions ("do a search for places on the map"),
  • Think in terms of the results of that action ("the list of places on the map matching a search criteria").

I'll go for examples below. (Other key aspect of REST is the use of HATEOAS - I don't brush it here, but I talk about it quickly at another post.)

About the first design

Let's take a look a the proposed design:

ACTION http://api.animals.com/v1/dogs/1/

First off, we should not consider creating a new HTTP verb (ACTION). Generally speaking, this is undesirable for several reasons:

  • (1) Given only the service URI, how will a "random" programmer know the ACTION verb exists?
  • (2) if the programmer knows it exists, how will he know its semantics? What does that verb mean?
  • (3) what properties (safety, idempotence) should one expect that verb to have?
  • (4) what if the programmer has a very simple client that only handles standard HTTP verbs?
  • (5) ...

Now let's consider using POST (I'll discuss why below, just take my word for it now):

POST /v1/dogs/1/ HTTP/1.1
Host: api.animals.com

{"action":"bark"}

This could be OK... but only if:

  • {"action":"bark"} was a document; and
  • /v1/dogs/1/ was a "document processor" (factory-like) URI. A "document processor" is a URI that you'd just "throw things at" and "forget" about them - the processor may redirect you to a newly created resource after the "throwing". E.g. the URI for posting messages at a message broker service, which, after the posting would redirect you to a URI that shows the status of the message's processing.

I don't know much about your system, but I'd already bet both aren't true:

  • {"action":"bark"} is not a document, it actually is the method you are trying to ninja-sneak into the service; and
  • the /v1/dogs/1/ URI represents a "dog" resource (probably the dog with id==1) and not a document processor.

So all we know now is that the design above is not so RESTful, but what is that exactly? What is so bad about it? Basically, it is bad because that is complex URI with complex meanings. You can't infer anything from it. How would a programmer know a dog have a bark action that can be secretly infused with a POST into it?

Designing your question's API calls

So let's cut to the chase and try to design those barks RESTfully by thinking in terms of resources. Allow me to quote the Restful Web Services book:

A POST request is an attempt to create a new resource from an existing one. The existing resource may be the parent of the new one in a data-structure sense, the way the root of a tree is the parent of all its leaf nodes. Or the existing resource may be a special "factory" resource whose only purpose is to generate other resources. The representation sent along with a POST request describes the initial state of the new resource. As with PUT, a POST request doesn’t need to include a representation at all.

Following the description above we can see that bark can be modeled as a subresource of a dog (since a bark is contained within a dog, that is, a bark is "barked" by a dog).

From that reasoning we already got:

  • The method is POST
  • The resource is /barks, subresource of dog: /v1/dogs/1/barks, representing a bark "factory". That URI is unique for each dog (since it is under /v1/dogs/{id}).

Now each case of your list has a specific behavior.

1. bark just sends an email to dog.email and records nothing.

Firstly, is barking (sending an email) a synchronous or an asynchronous task? Secondly the bark request requires any document (the email, maybe) or is it empty?

1.1 bark sends an email to dog.email and records nothing (as a synchronous task)

This case is simple. A call to the barks factory resource yields a bark (an email sent) right away and the response (if OK or not) is given right away:

POST /v1/dogs/1/barks HTTP/1.1
Host: api.animals.com
Authorization: Basic mAUhhuE08u724bh249a2xaP=

(entity-body is empty - or, if you require a **document**, place it here)

200 OK

As it records (changes) nothing, 200 OK is enough. It shows that everything went as expected.

1.2 bark sends an email to dog.email and records nothing (as an asynchronous task)

In this case, the client must have a way to track the bark task. The bark task then should be a resource with it's own URI.:

POST /v1/dogs/1/barks HTTP/1.1
Host: api.animals.com
Authorization: Basic mAUhhuE08u724bh249a2xaP=

(document body, if needed)

202 Accepted
Location: http://api.animals.com/v1/dogs/1/bark/a65h44

This way, each bark is traceable. The client can then issue a GET to the bark URI to know it's current state. Maybe even use a DELETE to cancel it.

2. bark sends an email to dog.email and the increments dog.barkCount by 1

This one can be trickier, if you want to let the client know the dog resource gets changed:

POST /v1/dogs/1/barks HTTP/1.1
Host: api.animals.com
Authorization: Basic mAUhhuE08u724bh249a2xaP=

(document body, if needed)

303 See Other
Location: http://api.animals.com/v1/dogs/1

In this case, the location header's intent is to let the client know he should take a look at dog. From the HTTP RFC about 303:

This method exists primarily to allow the output of a POST-activated script to redirect the user agent to a selected resource.

If the task is asynchronous, a bark subresource is needed just like the 1.2 situation and the 303 should be returned at a GET .../bark/Y when the task is complete.

3. bark creates a new "bark" record with bark.timestamp recording when the bark occured. It also increments dog.barkCount by 1.

POST /v1/dogs/1/barks HTTP/1.1
Host: api.animals.com
Authorization: Basic mAUhhuE08u724bh249a2xaP=

(document body, if needed)

201 Created
Location: http://api.animals.com/v1/dogs/1/bark/a65h44

In here, the bark is a created due to the request, so the status 201 Created is applied.

If the creation is asynchronous, a 202 Accepted is required (as the HTTP RFC says) instead.

The timestamp saved is a part of bark resource and can be retrieved with a GET to it. The updated dog can be "documented" in that GET dogs/X/bark/Y as well.

4. bark runs a system command to pull the latest version of the dog code down from Github. It then sends a text message to dog.owner telling them that the new dog code is in production.

The wording of this one is complicated, but it pretty much is a simple asynchronous task:

POST /v1/dogs/1/barks HTTP/1.1
Host: api.animals.com
Authorization: Basic mAUhhuE08u724bh249a2xaP=

(document body, if needed)

202 Accepted
Location: http://api.animals.com/v1/dogs/1/bark/a65h44

The client then would issue GETs to /v1/dogs/1/bark/a65h44 to know the current state (if the code was pulled, it the e-mail was sent to the owner and such). Whenever the dog changes, a 303 is appliable.

Wrapping up

Quoting Roy Fielding:

The only thing REST requires of methods is that they be uniformly defined for all resources (i.e., so that intermediaries don’t have to know the resource type in order to understand the meaning of the request).

In the above examples, POST is uniformly designed. It will make the dog "bark". That is not safe (meaning bark has effects on the resources) nor idempotent (each request yields a new bark), which fits the POST verb well.

A programmer would know: a POST to barks yields a bark. The response status codes (also with entity-body and headers when necessary) do the job of explaining what changed and how the client can and should proceed.

Note: The primary sources used were: "Restful Web Services" book, the HTTP RFC and Roy Fielding's blog.


Update:

The original question asked about the design of a URI like:

ACTION http://api.animals.com/v1/dogs/1/?action=bark

Below is the explanation of why it is not a good choice:

How clients tell the server WHAT TO DO with the data is the method information.

  • RESTful web services convey method information in the HTTP method.
  • Typical RPC-Style and SOAP services keep theirs in the entity-body and HTTP header.

WHICH PART of the data [the client wants the server] to operate on is the scoping information.

  • RESTful services use the URI. SOAP/RPC-Style services once again use the entity-body and HTTP headers.

As an example, take Google's URI http://www.google.com/search?q=DOG. There, the method information is GET and the scoping information is /search?q=DOG.

Long story short:

  • In RESTful architectures, the method information goes into the HTTP method.
  • In Resource-Oriented Architectures, the scoping information goes into the URI.

And the rule of thumb:

If the HTTP method doesn’t match the method information, the service isn’t RESTful. If the scoping information isn’t in the URI, the service isn’t resource-oriented.

You can put the "bark" "action" in the URL (or in the entity-body) and use POST. No problem there, it works, and may be the simplest way to do it, but this isn't RESTful.

To keep your service really RESTful, you may have to take a step back and think about what you really want to do here (what effects will it have on the resources).

I can't talk about your specific business needs, but let me give you an example: Consider a RESTful ordering service where orders are at URIs like example.com/order/123.

Now say we want to cancel an order, how are we gonna do it? One may be tempted to think that is a "cancellation" "action" and design it as POST example.com/order/123?do=cancel.

That is not RESTful, as we talked above. Instead, we might PUT a new representation of the order with a canceled element sent to true:

PUT /order/123 HTTP/1.1
Content-Type: application/xml

<order id="123">
    <customer id="89987">...</customer>
    <canceled>true</canceled>
    ...
</order>

And that's it. If the order can't be canceled, a specific status code can be returned. (A subresource design, like POST /order/123/canceled with the entity-body true may, for simplicity, also be available.)

In your specific scenario, you may try something similar. That way, while a dog is barking, for example, a GET at /v1/dogs/1/ could include that information (e.g. <barking>true</barking>). Or... if that's too complicated, loosen up your RESTful requirement and stick with POST.

Update:

I don't want to make the answer too big, but it takes a while to get the hang of exposing an algorithm (an action) as a set of resources. Instead of thinking in terms of actions ("do a search for places on the map"), one needs to think in terms of the results of that action ("the list of places on the map matching a search criteria").

You may find yourself coming back to this step if you find that your design doesn't fit HTTP's uniform interface.

Query variables are scoping information, but do not denote new resources (/post?lang=en is clearly the same resource as /post?lang=jp, just a different representation). Rather, they are used to convey client state (like ?page=10, so that state is not kept in the server; ?lang=en is also an example here) or input parameters to algorithmic resources (/search?q=dogs, /dogs?code=1). Again, not distinct resources.

HTTP verbs' (methods) properties:

Another clear point that shows ?action=something in the URI is not RESTful, are the properties of HTTP verbs:

  • GET and HEAD are safe (and idempotent);
  • PUT and DELETE are idempotent only;
  • POST is neither.

Safety: A GET or HEAD request is a request to read some data, not a request to change any server state. The client can make a GET or HEAD request 10 times and it's the same as making it once, or never making it at all.

Idempotence: An idempotent operation in one that has the same effect whether you apply it once or more than once (in math, multiplying by zero is idempotent). If you DELETE a resource once, deleting again will have the same effect (the resource is GONE already).

POST is neither safe nor idempotent. Making two identical POST requests to a 'factory' resource will probably result in two subordinate resources containing the same information. With overloaded (method in URI or entity-body) POST, all bets are off.

Both these properties were important to the success of the HTTP protocol (over unreliable networks!): how many times have you updated (GET) the page without waiting until it is fully loaded?

Creating an action and placing it in the URL clearly breaks the HTTP methods' contract. Once again, the technology allows you, you can do it, but that is not RESTful design.

这篇关于呼吁资源的服务器端方法REST方式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆