在 HATEOAS 中向消费者建议行动

Suggesting an action to consumer in HATEOAS

我正在使用 HATEOAS REST 表示法开发 Web 服务 API。

我的客户可以创建一个项目(例如博客存根post):

POST /item
204 Created
Content-Type: application/vnd.foo.item+json
{
   "id": 42,
   "title": "Lorem Ipsum",
   "status": "STUB",
   "body": "Very long text."
   "_links": {
     "self": {
       "href": "/item/42"
     },
     "activate": {
       "href": "/item/42/activate"
      },
   }
}

之后,客户可以激活 activate link 之后的项目(例如使用 post 上线)。所以它再次调用 API:

POST /item/42/activate
200 Ok
Content-Type: application/vnd.foo.item+json
{
   "id": 42,
   "title": "Lorem Ipsum",
   "status": "ACTIVE",
   "body": "Very long text."
   "_links": {
     "self": {
       "href": "/item/42"
     },
     "permalink": {
       "href": "/item/42/permalink"
     }
   }
}

到这里为止还好。但问题是我正在寻找一种方法来告诉客户关于下一步操作的建议(这是后端业务逻辑)。

在我的情况下可能是:

我不知道如何将这些信息封装在 HATEOAS 中。 我在想类似的东西:

POST /item/42/activate
200 Ok
Content-Type: application/json
{
   "suggested-action": "check-censure-panel",
   "censure-reason": "censored (gambling)",
   "_embedded": {
      "foo.item": {
         "id": 42,
         "title": "Lorem Ipsum",
         "status": "ACTIVE",
         "body": "Very long text."
         "_links": {
         "self": {
            "href": "/item/42"
         },
         "permalink": {
            "href": "/item/42/permalink"
         }
      }
   }
}

但问题是每个建议的操作对于额外的属性都是异构的,另一个例子可能是:

   "suggested-action": "go-to-checkout",
   "product-order": 424242100,

它们没有通用接口,所以我无法制作 vnd.foo.suggestedAction+json 类型。

设计此响应的最佳方式是什么?

下一个动作是状态转换,您似乎在使用 HAL,因此任何状态转换都应显示为 HAL。

您应用的客户端需要对您的应用提供的状态转换做出反应。因此,您可以做的一件非常简单的事情就是将 Location header 发送到应用程序应该呈现的下一个资源。您甚至可以将它们 302 重定向到那里,而不是使用更新后的资源对它们进行 200 重定向。

您可以将下一个操作提供为 link...而不一定是 HAL link。您可以将其作为 Link header (https://www.rfc-editor.org/rfc/rfc5988),但我认为这很奇怪,我只是提出它来说明您的应用需要告诉您的客户关于link.

您似乎想使用自定义媒体类型,但您可以使用配置文件 links (https://www.rfc-editor.org/rfc/rfc6906) 并将配置文件混合到您的 vnd.foo 类型中。您可以坚持您的 vnd.foo 类型,只定义它有一个可选的 suggested-action link 关系。你的例子中的问题是你用数据字段定义它,但是使用 link:

{
     "id": 42,
     "title": "Lorem Ipsum",
     "status": "ACTIVE",
     "body": "Very long text."
     "_links": {
         "self": {
            "href": "/item/42"
         },
         "permalink": {
            "href": "/item/42/permalink"
         },
         "x:suggested-action" : {
            "href" : "/path/to/best/action"
         }
      }

客户端可以关注 link,向用户提供选择关注 link 或忽略它的选项。在中间情况下,如果您的应用程序为用户提供一些上下文,例如标题字段,那就太好了:

"x:suggested-action" : {
  "href" : "http://path/to/check/censure/panel",
  "title" : "Check Censure Panel"
}

您还可以提示应用可以期待的资源:

"x:suggested-action" : {
  "href" : "http://path/to/check/censure/panel",
  "title" : "Check Censure Panel",
  "type" : "vnd.censure.panel/json"
}

我个人不喜欢这样做,因为我喜欢我的客户对我发送给他们的任何内容做出反应,但是当您提供多项建议操作时,这很有用:

"x:suggested-action" : [
  {
    "href" : "http://path/to/check/censure/panel",
    "title" : "Check Censure Panel",
    "type" : "vnd.censure.panel/json"
  },
  {
    "href" : "http://path/to/checkout",
    "title" : "Start Checkout",
    "type" : "vnd.checkout/json"
  }
]

现在应用程序可以根据明确定义的媒体类型来决定要执行、呈现或忽略哪些建议操作。