如何正确使用HAL(超媒体应用语言)_embedded?

How to correctly use HAL (Hypermedia Application Language) _embedded?

我正在构建一个 REST API,用于向用户公开有关在线课程的信息。这是课程的一般结构:

课程 > 单元 > 课程 > 活动

我正在尝试使我的 JSON 响应结构符合 HAL,但我不确定我是否正确地做到了。

下列哪项是正确的:

{
  “kind”: “clms#course”,
  “id”: long,
  “course-name”: string,
  “course-icon”: string,
  “product-name”: string,
  “product-icon”: string,
  “_links”: {
    “self”: {“href” : string}, 
    “unitlist”: {“href” : string} // This is a link to list of units for the course.
  }
}

或者单位列表中的 link 是 _embedded 资源吗?

{
      “kind”: “clms#course”,
      “id”: long,
      “course-name”: string,
      “course-icon”: string,
      “product-name”: string,
      “product-icon”: string,
      “_links”: {
        “self”: {“href” : string}, 
      }
      "_embedded": {
        “unitlist”: {“href” : string} // This is a link to list of units for the course.
      }
    }

或者都错了!?任何帮助表示赞赏。

干杯, 奥利

几件事。让我带您完成整个过程,这可能会有所帮助。

仅从 link 及其关系开始。有一门课程,它有单位。因此,每个单元都作为一个单元与课程相关。将其用作您的关系名称。所以:

{
  “kind”: “clms#course”,
  “id”: long,
  “course-name”: string,
  “course-icon”: string,
  “product-name”: string,
  “product-icon”: string,
  “_links”: {
    “self”: {“href” : string}, 
    “unit”: [
       {“href” : url-of-first-unit},
       {“href” : url-of-second-unit},
       {“href” : url-of-third-unit},
       ...
    ]
  }
}

但单元不是 IANA 注册的 link 关系,所以它实际上应该是一个 URI,或者柯里化到一个 URI:

“_links”: {
    “self”: {“href” : string},
    "curies" : [
       {"href" : "http://youndomain/rels/{rel}", name : "x" }
    ],
    “x:unit”: [
       {“href” : url-of-first-unit},
       {“href” : url-of-second-unit},
       {“href” : url-of-third-unit},
       ...
    ]
  }

这有点令人困惑,但它使您的单元具有“命名空间”并且它自己的东西很好。

现在意识到单独取回所有这些单元会很痛苦。我假设在您的 UI 中您希望将单元与课程一起显示,所以 HAL 让您嵌入这些关系:

{
  “kind”: “clms#course”,
  “id”: long,
  “course-name”: string,
  “course-icon”: string,
  “product-name”: string,
  “product-icon”: string,
  “_links”: {
    “self”: {“href” : string}, 
    "curies" : [
       {"href" : "http://youndomain/rels/{rel}", name : "x" }
    ],
    “x:unit”: [
       {“href” : url-of-first-unit},
       {“href” : url-of-second-unit},
       {“href” : url-of-third-unit},
       ...
    ]
  },
  "_embedded" : {
    “x:unit”: [
       { some json representing the unit located at url-of-first-unit},
       { some json representing the unit located at url-of-second-unit},
       { some json representing the unit located at url-of-third-unit},
       ...
    ]
  }
}

现在客户可以嵌入设备的我的检查而不是检查 links。事实上,因为它是嵌入式的,所以真的没有理由再包含 links(除非你知道客户端依赖于它们):

{
  “kind”: “clms#course”,
  “id”: long,
  “course-name”: string,
  “course-icon”: string,
  “product-name”: string,
  “product-icon”: string,
  “_links”: {
    “self”: {“href” : string}, 
    "curies" : [
       {"href" : "http://youndomain/rels/{rel}", name : "x" }
    ],
  },
  "_embedded" : {
    “x:unit”: [
       { some json representing the unit located at url-of-first-unit},
       { some json representing the unit located at url-of-second-unit},
       { some json representing the unit located at url-of-third-unit},
       ...
    ]
  }
}

所以现在客户端将它们作为嵌入式资源提供,不需要使用 http 请求检索资源。

总的来说,我建议从 links 开始,并通过嵌入式资源优化您的用例。

一些额外的注意事项:

  • 如果您确实需要将所有单元收集在一起 单个资源,也许可以将其视为具有嵌入式的页面 item[s] 这将是单位。从课程到的关系 单位 [s] 的页面可能是 x:units.
  • 避免在您的资源中使用 id 字段,除非该 id 为外界所知。 self link 是一个更好的外部 id,因为它是 URL 并且更容易变成实际资源。
  • 我更喜欢配置文件 links 而不是“种类”字段,尤其是当它看起来像枚举时。查看 https://www.rfc-editor.org/rfc/rfc6906