请记住,我对REST有基本的了解。假设我有以下网址:

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

现在,我想让服务器将狗叫起来。只有服务器知道如何执行此操作。假设我想让它运行在CRON作业上,该作业将使狗每10分钟吠叫一次,直到永恒。这个电话看起来像什么?我有点想这样做:

网址请求:
ACTION http://api.animals.com/v1/dogs/1/

在请求正文中:
{"action":"bark"}

在为构造自己的HTTP方法而生我的气之前,请帮助我,让我更好地了解如何以RESTful方式调用服务器端方法。 :)

编辑说明

有关“树皮”方法功能的更多说明。以下是一些可能导致结构不同的API调用的选项:
  • 吠声只是向dog.email发送电子邮件,什么也没记录。
  • bark向dog.email发送电子邮件,并将dog.barkCount递增1。
  • 发生树皮时,
  • bark使用bark.timestamp记录创建一个新的“树皮”记录。还将dog.barkCount递增1。
  • bark运行系统命令以从Github中提取最新版本的狗码。然后,它将一条文本消息发送到dog.owner,告诉他们新的狗代码正在生产中。
  • 最佳答案

    为什么要针对RESTful设计?

    RESTful原则将使Web站点易于使用的(对于随机的人类用户“浏览”它们)引入Web服务API设计中,以便程序员易于使用。 REST isn't good because it's REST, it's good because it's good.很好,主要是因为它是简单

    普通HTTP的简单性(没有SOAP信封和单个URI重载的POST服务),可以称为,有些人称之为“功能不足”,实际上是其最大的优势。 HTTP立即要求您具有可寻址性和无状态性:这两个基本设计决策使HTTP可以扩展到当今的大型站点(和大型服务)。

    但是REST并不是灵丹妙药:有时,RPC风格的(“远程过程调用”,例如SOAP)可能是合适的,并且有时其他需求优先于Web的优点。这可以。我们真正不喜欢的是不必要的复杂性。程序员或公司通常会引入RPC样式的服务来完成普通的旧HTTP可以很好处理的工作。这样做的结果是,HTTP简化为用于巨大XML有效负载的传输协议(protocol),该XML有效负载解释了“真正”发生的事情(不是URI或HTTP方法提供了线索)。最终的服务太复杂了,无法调试,并且除非您的客户具有开发人员想要的精确设置,否则它将无法正常工作。

    Java / C#代码不能以面向对象的方式相同,仅使用HTTP不能使设计成为RESTful。 急于考虑关于其服务的服务,其中包括应该采取的措施和远程方法。难怪这最终会以RPC样式服务(或REST-RPC混合)结尾。第一步是要有不同的想法。 RESTful设计可以通过多种方式来实现,一种方式是根据资源而不是操作来考虑应用程序:



    我将在下面举例。
    (REST的其他关键方面是HATEOAS的使用-我在这里没有刷过,但是我很快就谈到了at another post。)

    第一个设计的问题

    让我们看一下建议的设计:

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

    首先,我们不应该考虑创建一个新的HTTP动词(ACTION)。一般来说,由于以下几个原因,这是不希望的:
  • (1)仅给出服务URI,“随机”程序员将如何知道ACTION动词存在?
  • (2)如果程序员知道它的存在,他将如何知道它的语义?这个动词是什么意思?
  • (3)人们应该期望该动词具有哪些属性(安全性,幂等性)?
  • (4)如果程序员拥有一个仅处理标准HTTP动词的非常简单的客户端,该怎么办?
  • (5) ...

  • 现在让考虑使用POST (我将在下面讨论原因,现在就说吧):
    POST /v1/dogs/1/ HTTP/1.1
    Host: api.animals.com
    
    {"action":"bark"}
    

    可以...但是只有时才是:
  • {"action":"bark"}是一个文档;和
  • /v1/dogs/1/是一个“文档处理器”(类似于工厂)的URI。 “文档处理器”是一个URI,您只需将其“扔给”并“忘记”它们-在“扔”之后,处理器可能会将您重定向到新创建的资源。例如。用于在消息代理服务中发布消息的URI,该服务在发布后会将您重定向到显示消息处理状态的URI。

  • 我对您的系统了解不多,但我敢打赌,两者都不对:
  • {"action":"bark"} 不是文件,实际上是您尝试对服务进行忍者访问的方法;和
  • /v1/dogs/1/ URI表示“狗”资源(可能是带有id==1的狗),而不是文档处理器。

  • 因此,我们现在所知道的是,上面的设计并不是那么RESTful,但这到底是什么? 有什么不好的呢? 基本上,这很糟糕,因为那是具有复杂含义的复杂URI。您无法从中推断任何内容。程序员如何知道狗的bark Action 可以 secret 地将POST注入(inject)其中?

    设计问题的API调用

    因此,让我们开始追赶,并尝试通过在资源
    方面考虑来REST式设计那些树皮。请允许我引用Restful Web Services书:



    根据上面的描述,我们可以看到 bark 可以建模为dog 的子资源(因为狗中包含bark,也就是说,
    将狗的吠叫为ok)。

    通过这种推理,我们已经得到:
  • 方法是POST
  • 资源是/barks,它是dog的子资源:/v1/dogs/1/barks,代表一个bark“factory”。该URI对于每条狗都是唯一的(因为它在/v1/dogs/{id}下)。

  • 现在,列表中的每种情况都有特定的行为。

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

    首先,吠叫(发送电子邮件)是同步任务还是异步任务?其次,bark请求是否需要任何文档(可能是电子邮件),还是空的?

    1.1树皮向dog.email发送电子邮件,但不记录任何内容(作为同步任务)

    这种情况很简单。调用barks工厂资源会立即产生一个树皮(发送电子邮件),并立即给出响应(如果确定):
    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
    

    由于它没有记录(更改)任何内容,因此200 OK就足够了。它表明一切都按预期进行。

    1.2树皮向dog.email发送电子邮件,不记录任何内容(作为异步任务)

    在这种情况下,客户端必须有一种跟踪bark任务的方法。然后,bark任务应该是具有自己的URI的资源:
    POST /v1/dogs/1/barks HTTP/1.1
    Host: api.animals.com
    Authorization: Basic mAUhhuE08u724bh249a2xaP=
    
    {document body, if needed;
    NOTE: when possible, the response SHOULD contain a short hypertext note with a hyperlink
    to the newly created resource (bark) URI, the same returned in the Location header
    (also notice that, for the 202 status code, the Location header meaning is not
    standardized, thus the importance of a hipertext/hyperlink response)}
    
    202 Accepted
    Location: http://api.animals.com/v1/dogs/1/barks/a65h44
    

    这样,每个bark都是可追溯的。然后,客户端可以向GET URI发出bark,以了解其当前状态。甚至可以使用DELETE取消它。

    2.树皮向dog.email发送一封电子邮件,然后将dog.barkCount递增1

    如果您想让客户端知道dog资源已更改,那么这可能会比较棘手:
    POST /v1/dogs/1/barks HTTP/1.1
    Host: api.animals.com
    Authorization: Basic mAUhhuE08u724bh249a2xaP=
    
    {document body, if needed; when possible, containing a hipertext/hyperlink with the address
    in the Location header -- says the standard}
    
    303 See Other
    Location: http://api.animals.com/v1/dogs/1
    

    在这种情况下,location header 的目的是让客户端知道他应该看看dog。从HTTP RFC about 303 :



    如果任务是异步的,则需要bark子资源,就像1.2情况一样,并且在任务完成时应在303处返回GET .../barks/Y

    3.树皮发生时,树皮会创建一个带有bark记录的新“bark.timestamp”记录。也会使dog.barkCount增加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/barks/a65h44
    

    在这里,bark是根据请求创建的,因此将应用201 Created状态。

    如果创建是异步的,则需要202 Accepted(as the HTTP RFC says)。

    保存的时间戳是bark资源的一部分,可以使用GET对其进行检索。更新的狗也可以在该GET dogs/X/barks/Y中“记录”。

    4. bark运行系统命令以从Github中提取最新版本的狗码。然后,它向dog.owner发送一条文本消息,告诉他们新的狗代码正在生产中。

    这句话的措词很复杂,但这几乎是一个简单的异步任务:
    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/barks/a65h44
    

    然后,客户端将向GET发出/v1/dogs/1/barks/a65h44,以了解当前状态(如果将代码拉出,则将电子邮件发送给所有者等)。每当狗变时,就可以使用303

    包起来

    引用Roy Fielding:



    在以上示例中,POST是统一设计的。它将使狗成为“bark”。这是不安全的(意味着树皮会对资源产生影响),也不是幂等的(每个请求都产生一个新的bark),这很适合POST动词。

    程序员会知道:从POSTbarks会产生bark。响应状态代码(必要时还包含实体正文和 header )可以解释哪些更改以及客户端可以并且应该如何进行。

    注意:所使用的主要来源是:“Restful Web Services”书,HTTP RFCRoy Fielding's blog



    编辑:

    自问世以来,问题及其答案已经发生了很大变化。 原始问题询问了有关URI的设计,例如:
    ACTION http://api.animals.com/v1/dogs/1/?action=bark
    

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

    客户端如何告诉服务器使用数据做什么是方法信息。
  • RESTful Web服务通过HTTP方法传达方法信息。
  • 典型的RPC样式和SOAP服务将它们保留在实体正文和HTTP header 中。

  • [范围(客户端希望服务器)操作的数据的哪个部分”是作用域信息。
  • RESTful服务使用URI。 SOAP / RPC样式服务再次使用实体主体和HTTP header 。

  • 以Google的URI http://www.google.com/search?q=DOG为例。那里,方法信息是GET,作用域信息是/search?q=DOG

    长话短说:
  • RESTful体系结构中,方法信息进入HTTP方法。
  • 面向资源的体系结构中,作用域信息进入URI。

  • 经验法则:



    您可以将“树皮”“操作”放在URL中(或在实体正文中),并使用POST。那里没问题,它可以工作,并且可能是最简单的方法,它是,但这不是RESTful的

    为了使您的服务真正保持RESTful,您可能必须退后一步,考虑一下您真正想在这里做什么(它将对资源产生什么影响)。

    我无法谈谈您的特定业务需求,但让我举一个例子:考虑一个RESTful订购服务,其中的订单位于URI上,例如example.com/order/123

    现在说我们要取消订单,我们该怎么做?可能有人会认为这是“取消”“ Action ”,并将其设计为POST example.com/order/123?do=cancel

    如上所述,这不是RESTful的。相反,我们可以使用发送到PUTorder元素canceled来表示true的新表示形式:
    PUT /order/123 HTTP/1.1
    Content-Type: application/xml
    
    <order id="123">
        <customer id="89987">...</customer>
        <canceled>true</canceled>
        ...
    </order>
    

    就是这样。如果无法取消订单,则可以返回特定的状态代码。 (为简单起见,也可以使用子资源设计,例如带有实体主体POST /order/123/canceledtrue。)

    在您的特定情况下,您可以尝试类似的操作。这样,例如,当狗吠叫时,位于GET/v1/dogs/1/可能包含该信息(例如<barking>true</barking>)。或者...如果过于复杂,则放松您的RESTful要求,并坚持使用POST

    更新:

    我不想将答案做得太大,但是要花一些时间才能掌握将算法(一个 Action )作为一组资源公开的窍门。与其根据 Action (“搜索 map 上的地点”)进行思考,不如根据 Action 的结果(“与搜索匹配的 map 上的地点列表”)进行思考
    条件”)。

    如果发现您的设计不适合HTTP的统一接口(interface),您可能会回到这一步。

    查询变量范围信息,但并不表示表示新资源(/post?lang=en显然是/post?lang=jp相同的资源,只是一种表示形式)。相反,它们用于将客户端状态(类似于?page=10,以便不将其保留在服务器中;这里?lang=en也是一个示例)或输入参数传达给算法资源(/search?q=dogs/dogs?code=1)。同样,不是不同的资源。

    HTTP动词的(方法)属性:

    HTTP动词的属性是另一个没有在RESTful中显示?action=something的要点:
  • GETHEAD是安全的(幂等);
  • PUTDELETE仅是幂等的;
  • POST都不是。

  • 安全:GETHEAD请求是对读取一些数据的请求,而不是更改任何服务器状态的请求。客户端可以发出GETHEAD请求10次,这与发出一次或完全不发出相同。

    等幂:一个幂等运算,无论您一次或多次应用它都具有相同的效果(在数学中,乘以零就是幂等)。如果您对资源进行DELETE一次,则再次删除将具有相同的效果(该资源已为GONE)。
    POST既不安全也不幂等。对“工厂”资源进行两个相同的POST请求可能会导致两个包含相同资源的下级资源
    信息。使用重载(URI或实体正文中的方法)POST,所有选择均关闭。

    这两个属性对于HTTP协议(protocol)(通过不可靠的网络!)的成功非常重要:您已经更新了页面几次(GET)而没有等待页面完全加载?

    创建 Action 并将其放置在URL中显然会破坏HTTP方法的约定。再一次,该技术允许您执行此操作,但这不是RESTful设计。

    关于api - 以RESTful方式在资源上调用服务器端方法,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/16877968/

    10-10 18:17