REST Hateoas:如何确保客户端通过简单的固定 URL 进入 REST 应用程序?

REST Hateos: How to make sure that client enters REST application through a simple fixed URL?

我们想在多个客户端上创建一个屏幕,显示“5 种最畅销的产品”、“5 种最近添加的产品”和“5 种提供优惠的产品”。所有这些都将显示为轮播。

我们想为这些创建 Restful API。我们创建了以下 API:

  1. /api/bestsellingproduct/
  2. /api/recentlyaddedproduct/
  3. /api/greatofferproduct/

目前,每个客户端,即桌面、移动、android、ios 都对这些 URI 进行了硬编码。我担心如果我们明天更改这些 URLs,那会很麻烦,而且 REST 建议 "A REST client enters a REST application through a simple fixed URL. (Ref: https://en.wikipedia.org/wiki/HATEOAS)"

在这种情况下,有人可以建议我如何确保所有客户端都通过简单的固定 URL 进入应用程序吗?

在 HATEOAS 中,URI 是可发现的(且未记录),因此可以更改它们。也就是说,除非它们是您系统的入口点(Cool URIs, the only ones that can be hard-coded by clients) - and you shouldn't have too many of those if you want the ability to evolve the rest of your system's URI structure in the future. This is in fact one of the most useful REST 的特性。

对于剩余的非 Cool URI,它们可以随着时间的推移而改变,并且您的 API 文档应该说明它们应该在运行时通过超媒体遍历被发现的事实。

查看 Richardson's Maturity Model (level 3), this would be where links come into play. For example, from the top level, say /api/version(/1), you would discover there's a link to the groups. Here's how this could look in a tool like HAL Browser:

根目录:

{
  "_links": {
    "self": {
      "href": "/api/root"
    },
    "api:bestsellingproduct": {
      "href": "http://apiname:port/api/bestsellingproduct"
    },
    "api:recentlyaddedproduct": {
      "href": "http://apiname:port/api/recentlyaddedproduct"
    },
    "api:greatofferproduct": {
      "href": "http://apiname:port/api/greatofferproduct")
    }
  }
}

这里的优点是客户端只需要知道关系 (link) 名称(显然除了资源 structure/properties 之外),而服务器大部分时间都可以自由更改关系(和资源)url.

您甚至可以将它们嵌入到同一个根 api 调用中返回:

{
  "_embedded": {
    "bestsellingproduct": [
        {               
            "id": "1",
            "name": "prod test"
        },
        {               
            "id": "2",
            "name": "prod test 2"
        }
    ],
    "recentlyaddedproduct": [
        {               
            "id": "3",
            "name": "prod test 3"
        },
        {               
            "id": "5",
            "name": "prod test 5"
        }
    ]
}