REST 操作和 URL API 设计注意事项

Posted

技术标签:

【中文标题】REST 操作和 URL API 设计注意事项【英文标题】:REST actions and URL API design considerations 【发布时间】:2014-10-06 21:44:11 【问题描述】:

我正在构建一个库存管理系统,并且忙于设计(思考)API 和我的 REST 实现。

我有以下资源,您可以在该资源上执行许多操作/操作。 每个操作都会修改资源,在某些情况下会创建新资源,还会创建历史记录或事务。

我正在寻找有关 URL 和资源设计的可用性和可接受性的专家意见。陷阱和现实世界的例子,欢迎任何意见或批评。

我担心整个应用程序可能是围绕这一大资源开发的? 我的后端堆栈将是 C# 和 servicestack 框架,而对于前端我将使用 html 和 AngularJS。并不是说它有什么不同。

场景 1。 典型的操作是:

POST /inventory/id/move
POST /inventory/id/scrap
PUT  /inventory/id/takeon
POST /inventory/id/pick
PUT  /inventory/id/receive
POST /inventory/id/hold
POST /inventory/id/release
POST /inventory/id/transfer
POST /inventory/id/return
POST /inventory/id/adjustment



  "userID": "",       //who is doing the actions (all)
  "tolocationID": "", //new location for inventory (move/takeon/pick/receive/transfer/return)
  "qty": "",          //qty (pick/receive/takeon/transfer/return)
  "comment": "",      //optional for transaction (all)
  "serial": "",       //(takeon/receive)
  "batch": "",        //(takeon/receive)
  "expirydate": "",   //(takeon/receive)
  "itemCode": "",     //(takeon/receive)
  "documentID": "",   //(pick/receive/return/transfer)
  "reference" :"",    //(all)
  "UOM" :"",          //(all)
  "reference" :"",    //(all)

这在标准方面是否可以接受。 另一种方法可能是。

场景 2。

POST /inventory/id/move
POST /inventory/id/scrap
PUT  /inventory/id/takeon
POST /document/id/pick     //**document**
PUT  /document/id/receive  //**document**
POST /inventory/id/hold
POST /inventory/id/release
POST /document/id/transfer  //**document**
POST /document/id/return    //**document**
POST /inventory/id/adjustment

然后去改变资源。

场景 3. 在我看来是错误的

POST /transaction/move/...
POST /transaction/scrap/...
PUT  /transaction/takeon/...
POST /transaction/pick/...  
PUT  /transaction/receive/... 
POST /transaction/hold/...
POST /transaction/release/...
POST /transaction/transfer/...  
POST /transaction/return/...
POST /transaction/adjustment/...

欢迎任何 cmets,不是在寻找答案,而是在设计考虑方面提供更多建议?

感谢您花时间阅读这篇文章!

【问题讨论】:

这听起来更像是 RPC 而不是 REST。像/inventory/id/move 这样的 URL 可以识别哪些资源?如果这是一个过程调用的 URL 而不是资源的 URL,那么你没有做 REST。 我不认为“不做 REST”是一件坏事,因为 REST 天生适合 CRUD 操作,而这组操作显然更丰富。我相信,在这种情况下,选择 RPC 范式而不完全遵循 REST 并没有错。当然,这取决于领域的哪些方面需要模型。 @VictorSergienko 我同意这种观点,但如果他标记问题 [rest],他必须期待 REST 答案。 @EricStein 这很有帮助我认为我最大的困难之一是 RPC 在技术方面不符合我的要求,这就是我探索替代方案的原因。但同时出于对 REST 的尊重,我认为我正在尝试以正确的方式来做这件事,但正确的方式再次将我置于感觉错误的位置,但不是在技术意义上,而是在业务领域。我想我在找人说:嗨,您不必对此深信不疑:-)然后我是否应该离开 REST 和 ServiceStack 框架并重新回到 Microsoft Web 服务的床上? @Francois,您不必更改技术堆栈。我相信 Eric 说的是意识形态问题,我也是。你仍然可以使用 RPC 风格的 HTTP+JSON,或者 REST 风格的 Web 服务。 【参考方案1】:

我对以下示例的考虑:

POST /inventory/id/move
    “move”一词可以看作是“move-request”的缩写。 在这种情况下,用户发布请求以移动库存。 请求被接受后,会触发相应的服务器动作。 请求是某种资源,它甚至可以被服务器持久化以用于历史记录或如果不立即执行则触发异步任务。

这些是我认为动词可以用在 URI 末尾而不违反任何 REST 准则的主要原因。

其他注意事项:

    确保仅在没有可发布或放置的简单资源的情况下使用此“请求抽象”。 PUT inventory/id/manager 是比 POST inventory/id/set-manager 更好的方法,除非您的请求需要一些不是经理属性的参数。 如果您的参数不适合实体/值对象属性,建议使用POST inventory/id/manager-update,这显然是一种资源。

最后...大多数 REST 指南示例仅涵盖 CRUD 应用程序。更丰富的领域需要更具表现力的抽象,而不仅仅是使用来自领域实体或值对象的简单名词。

【讨论】:

【参考方案2】:

简答

使用 URL 末尾的动作来改变状态。

Github 这样做是为了给要点加星标: PUT /gists/:gist_id/star

在这里解释 https://developer.github.com/v3/gists/#star-a-gist

长答案

您的目标是让您的应用程序使用起来毫不费力。您的用户应该以最简单的方式使用您的应用程序。您的用户不应受到您使用的技术的限制或硬性指导。

所以操作和操作本质上不是资源,而是对资源的操作。所以他们不会像 REST 那样响应“资源到 URI 映射”。

但是您可以使用最好的 REST,并且仍然可以使用最好的 URI,将两者结合起来。

记住:

技术应该为你工作,而不是你为技术工作。

如果你成为技术的奴隶,你最终会创建无法使用的应用程序或使用 XML 或 Java Home 和 Remote 接口等丑陋技术,因此你最终会编写 5 个文件来创建一个 hello world 应用程序。

当心“闪亮物体综合症”。去谷歌上查询。

并不是因为一项技术是新的或者是“新的做事方式”,而是意味着这是一项很好的技术,或者你需要分心并抛开所有其他技术来屈服于 REST。

从技术中获取你需要的东西,然后让技术为你工作。

使用 REST api 并不意味着您需要放弃 URL 和 URI 技术的能力。

参考资料: https://www.vinaysahni.com/best-practices-for-a-pragmatic-restful-api#restful

【讨论】:

我认为的最佳答案。 @LunicLynx 谢谢...我们不能让像 REST 这样的技术覆盖和丢弃 HTTP 或 URI 技术。幸运的是,GraphQL 和其他新兴技术将帮助人们了解 REST 不是灵丹妙药,它有很多缺点,也有一些优点。干杯。 6 年后,这仍然是一个很好的问题(我认为),6 年后,我仍然发现回复的人很有价值。感谢您的回答,在 URL 末尾使用 action 有点小,但我喜欢它。 @FrancoisTaljaard 很高兴你喜欢它。 6 年前我的英语更差?。尽管如此,我还是设法向主流提出了另一种想法。当我们说“没有正确答案”时,并不意味着所有答案都是错误的。有些方法在某些空间/时间条件下是好的。就像在给定的市场时间里在给定的公司里一样。我们没有持久的朋友,没有持久的敌人,只有持久的利益/丘吉尔 Github 的 PUT /gists/:gist_id/star 不是一个动作。这里的动词是 PUT,star 是宾语。 Github 在要点上放了一颗星(对象)。 PUT 是合理的,因为它是幂等请求。 POST /something/:id/move 不会是 RESTful,因为 move 不是对象。【参考方案3】:

“Restful Objects”,它定义了一个 RESTful API,声明动作是有效的。

可以发现、启用/禁用可用操作,并且可以给出“禁用原因”反馈。

使用 GET(查询)、PUT(幂等)或 POST(非幂等)“调用”操作

Restful Object Spec(C-125 页)

【讨论】:

这是一个很好的详尽规范,即使你不完全同意它,它也有很多好的概念,比如将域服务建模为具有动作的对象【参考方案4】:

我有以下资源和你可以执行的资源 许多动作/操作。每个操作都会修改资源和 在某些情况下,创建新资源并创建历史或 交易。

REST 架构模式的基础是使用 HTTP 动词作为唯一动词,而不是在 URL 中包含动词。在您的情况下,我会考虑重新设计您的系统以删除动词。如果不知道任何动词的含义,就很难提出设计建议,但也许更接近:

GET /inventory/id
PUT /inventory/id -- update with new location 
PUT /inventory/id -- update with new status (scrapped)

etc .. 这是一种更 RESTful 的方法。其中许多操作看起来实际上只是更新资源的多个属性的 PUT,例如位置、数量、评论字段等。也许 scrap 是 DELETE?很难说。

另一种选择是使用 POST,其中正文包含有关如何操作库存项目的说明:

POST /inventory-transactions/id

    "action": "takeon",
    "newLocationId": 12345,
    ...

这为您提供了很多可追溯性,因为现在每个操作都可以作为资源进行跟踪。缺点是端点周围有很多复杂性。

您还可以将一些“动词”操作分解为资源:

POST /returned-inventory

    "inventoryId": 12345,
    "documentId": 67890,
    "comment": "Busted up",
    ...

这让您可以轻松地按状态查看库存项目,这可能有用,也可能没有帮助。例如,您可以调用 GET /returned-inventory?documentId=67890 以从同一个文档中取回所有返回的项目。

希望里面有一些值得深思的地方。如果不更详细地了解您的业务需求,任何人都不可能告诉您“正确”的做法。

【讨论】:

可以同意这个答案,Stein 你能推荐任何有更多论坛基础或有关该主题的有趣读物的好网站。 现在,如果您只是更新资源的一部分(例如更改位置或状态),最好使用 PATCH。应该使用 PUT 来更新整个资源。 “REST 架构模式的基础是使用 HTTP 动词作为唯一动词,而不包括 URL 中的动词”。这个人restfulapi.net/resource-naming 和其他人反驳了这一点。他们推荐“控制器”,也称为资源上的“动作”动词。我认为这是个好建议。它只是解决了大量令人尴尬的语义/美学边缘案例,试图将所有内容扭曲为对象上的 HTTP 动词,并且仍然与 rest 保持一致。 欢迎您化妆,为所欲为。不过,这不是 REST。如果 restfulapi.net 另有说明,那就错了。

以上是关于REST 操作和 URL API 设计注意事项的主要内容,如果未能解决你的问题,请参考以下文章

REST API注意事项

restful架构风格设计准则资源识别的注意事项

2架构设计

.net 调用java rest ful api 实例

REST 接口学习

什么是REST API