表示REST URI中的动作(动词)


16

我要为客户文件执行打印操作。我还需要执行其他标准操作,例如添加,更新,删除。因此,我有以下内容:

  • 对于创建新客户:
    URI = / customer / {id},键入= POST,方法名= CreateCustomer()
  • 要更新:
    URI:/ customer / {id},类型= PUT,方法= UpdateCstomer()
  • 对于删除客户:
    URI = / customer / {id},键入= DELETE,方法名= DeleteCustomer()
  • 对于视图:
    URI:/ customer / {id},键入= GET,方法= GetCustomer()

现在,如果需要为该客户打印文档,则需要打印功能。我的URI可能看起来像这样:/ customer / {id},类型= POST,方法= PrintCustomer()。但是我已经将URI和POST类型用于CreateCustomer。我希望URI看起来像这样:/ customer / Print / {id},键入= POST,方法= PrintCustomer()。

但是我的URI中不能包含“ Print”动词。最好的方法是什么?我考虑将/ customer / document / {id}作为URI ...,但是我将遇到相同的问题。我将在“文档”上进行CRUD操作。因此,我再次用尽了用于“打印”的内容。请指教。


2
打印通常是一个客户端操作,所以我很好奇-您的设置如何要求您将命令发送到REST服务器?
Shauna 2013年

2
@Shauna不一定,URI可以是向服务器请求资源的打印友好版本(即,不同的视图)。
Evan Plaice

1
@EvanPlaice -很公平,尽管这仍然让行为打印到客户端(其中,甚至获取服务器端打印的版本后,会再决定要输出的设备和发送打印命令本身,即使命令转到打印服务器)。从逻辑上来说,获取资源的打印友好版本的请求将是……好……得到。
Shauna 2013年

@Shauna由于浏览器的安全性,仅通过HTTP请求触发打印作业将是不可能的。对打印友好版本的请求只是一个GET请求,但是您仍然需要一种方法来指定浏览器应呈现可打印版本。您可以指定一个不同的URL,但这会违反REST的原则,因为您实际上并不是在请求其他资源,而只是请求对同一资源进行不同的转换。因此,通过查询参数和/或内容类型指定转换的原因。
Evan Plaice 2015年

我没有足够的代表作为答复发布,但tyk.io/rest-never-crud认为这样做POST /customers/123/print是一件很有意义的事,这使我感到很有趣。
jlh

Answers:


9

POST不代表“创建”,而是“过程”。您可以通过将适当的请求发布到现有资源/customers来创建新资源(即发布以创建新客户)。但是,您也可以使用POST来填充所有其他与整齐的CRUD范例不对应的动作。

在打印的情况下,您应该将打印操作视为资源本身。您要系统为您创建一个“打印作业”。这意味着您可以拥有一个prints/资源,用作所有请求的打印的容器。当您要打印某些POST内容时,请向该资源发送文档,其中包含有关要创建的打印输出的所有信息,并通过指向它们的链接来标识要打印的资源。

作为JSON文档,它可能如下所示:

{
   contents: ["http://site/customers/12345"],
   paper-size: "A4",
   duplex: "true"
}

显然,您需要对此进行自定义以使其与您要执行的操作相关。关键是要通过指定其他资源的URL来标识要打印的其他资源。

响应请求,您可以简单地返回a 200 OK或a 204 No-Content并将其视为即发即弃过程。但是,如果要增强它,可以返回201 Created并指定新创建的打印作业的URL,例如/prints/12345

然后,用户可以GET在资源上执行,以查看其打印作业的状态(待处理,进行中等),或可以通过发出来要求取消该作业DELETE

一旦用资源重新表述了问题,RESTful设计就应该自然而然地出现,并为您提供机会,以您可能没有立即考虑的方式进行扩展和增强。


2
POST通常表示创建/插入,而put通常表示更新保存/更新。即使不是在HTML中通常使用的方式,也是如此在REST中定义的方式。
Evan Plaice

2
@EvanPlaice HTTP规范将PUT命名为create / update动词(它使用create + update模型而不是更熟悉的create + retrieve + update),而POST是“数据处理”动词以及“ append”动词。Roy Fielding在他的博客中将POST描述为不想标准化操作时要使用的动词。考虑到POST将新项目追加到项目集合中时,它具有“创建”语义。在这种情况下,Tragedian使用POST来处理或添加打印作业打在了头上。
罗布

@RobY好的,这很有道理。例如,PUT可以用来表示设计为将数据输入数据库的SPROC。POST可以组成收集/准备数据所需的中间步骤和变异。POST操作的设计可以随着设计的发展而更改或替换,但是PUT操作代表的模型(理想情况下)不应更改。我会更新我的答案,但是这个答案已经可以很好地解释差异。
Evan Plaice 2015年

4

我以前做过 要打印文档,我只返回资源的pdf版本。客户端只需要使用Accept标头application / pdf发送对资源的GET请求。

这也避免了为临时资源(如打印作业)创建新的URI。使用HTTP标头也是REST的一部分,它可以使URI保持整洁。


3

只需在当前URI的GET中添加一个参数

使用URI进行多个操作是非常典型的。

如果您在谈论相同的资源,但动作不同,则可以将其定义为参数。

/ customer / {id}?print = true

然后,在定义GET方法的位置检测到print参数的存在,并以不同的方式处理它。

REST是通过以下方式定义的:

  • POST-创建记录,资产或资源
  • PUT-更新,记录,资产或资源
  • 删除-删除记录,资产或资源

另一方面,GET打算以多种方式使用,因为通常可以以多种不同形式检索资源。这就是为什么GET请求表示为查询字符串的原因。如果您使用的是数据库资源,则实际上是通过查询来检索视图,但是REST被故意抽象到更高的级别,因为REST被设计为处理许多不同类型的资源。

REST规范是相当有远见的,即使API只是最近才开始大量使用它。

如果您有兴趣了解有关REST协议的更多信息,强烈建议您阅读“ Haters Gonna Hate HATEOAS ”。


更新:

@Shauna指出了我推理中的一个有趣的漏洞。没有真正正确的方法,许多形式都可以接受。我考虑了一下,由于您的预期用途是将数据转换为其他表示形式,因此将转换定义为新的MIME类型是有意义的。

例如,您可以将URI表示为:

/customer/{id}+print

您可以在其中将响应的Content-Type设置为text / html + print。这样,将来您还可以选择定义更多的转换。

例如:

// for application/json
/customer/{id}+json

// for application/atom+xml
/customer/{id}+atom

无论哪种方式,所有形式都是可以接受的。您决定的实现方式更多地取决于个人喜好和服务器的功能。

旁白:让我澄清一下,因为似乎有些混乱。“打印”查询参数和/或内容类型用于指定如何转换资源。不是如何触发物理打印作业。出于安全原因,硬件级别的访问始终留给用户/客户端/浏览器。


要添加-作为使用查询字符串(?print=true)的替代方法,您还可以使用URI参数(即- /customer/{id}/printable)。您使用哪一种将在很大程度上取决于系统要设置的标准(CMS,框架,一般代码)。两者均被视为有效且可以接受
Shauna 2013年

@Shauna从技术上讲,最好的方法是采用URI'/ customer / {id} + print'特定于打印的MIME类型,以及text / html + print的响应MIME类型。这种方法的优点是,您可以为同一URI创建许多MIME类型(例如text / html,text / x-markdown,application / json等)的转换。您提出的解决方案的缺点是,您需要为每个不同的MIME类型创建一个额外的URI(并定义另一个路由)。这有点违反了使用REST的目的。
Evan Plaice

(续)我认为URI hacks是主要由ROR社区引入的反模式,但这并不意味着它们没有用。随着更好的底层HTTPd服务器的出现,以充分利用其潜力的方式实施REST变得越来越容易。自从Apache和通过index.html路由所有内容的唯一选择以来,事情就已经走了很长一段路。
Evan Plaice

2
GET不应更改状态或产生副作用。考虑到GET是幂等的,这意味着如果中间件没有看到请求,中间件可以重试该请求。在这种情况下,每次重试都会得到新的,新打印的文档副本。;)
Rob

@RobY我以为'print'操作不会处理物理打印文档的过程,因为浏览器和打印驱动程序会更好地处理该过程。而是,媒体/打印输出将返回文档的“打印友好”表示。因此,保持了幂等性。很好,以无状态方式通过Internet发送打印作业将是一个糟糕的时机。
Evan Plaice 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.