如何为RESTful JSON集合实现HATEOAS风格的链接?

时间:2013-07-26 09:04:45

标签: json rest hateoas

为了简单起见并避免命名冲突,我一直在我的记录资源中捆绑链接......

{
    id: 211,
    first_name: 'John',
    last_name: 'Lock',
    _links: [
        { rel: 'self', href: 'htttp://example.com/people/211' }
    ]
}

但是,我无法弄清楚如何在集合中实现链接。我花了很长时间在网上搜寻一些例子,而不是使用不那么精简HAL我无法调和我的问题。

[
    {id:1,first_name:.....},
    {id:2,first_name:.....},
    {id:3,first_name:.....}, 
    "_links": "Cant put a key value pair here because its an-array" 
]

这意味着我必须将数组包装在容器对象中。

[
    people: [ {id:1,first_name:.....} ],
    links: [ { rel:parent, href:.... ]
]

但是它与单数资源不同,所以我要使记录像集合一样运行并将其包装在一个容器中....

{
    person: {
        id: 211,
        first_name: 'John',
        last_name: 'Lock',
        _links: 
    },
    links:[
        { rel: 'self', href: 'htttp://example.com/people/211' }
    ] 
}

从表面上看,这似乎是一个非常简洁的解决方案。由此产生的JSON更深一层,但HATEOAS已经实现,所以这一切都很好吗?一点也不。当我回到收藏品时,真正的刺痛来了。既然单个资源已经包装在容器中以便与集合保持一致,那么现在必须更改集合以反映更改。这就是丑陋的地方。十分难看。现在这个集合看起来像这样......

{
    "people": [
        {
            "person": {
                ....
            },
            "links" : [
                {
                    "rel": "self",
                    "href": "http://example.com/people/1"
                }
            ]
        },
        {
            "person": {
                ....
            },
            "links" : [
                {
                    "rel": "self",
                    "href": "http://example.com/people/2"
                }
            ]
        }
    ],
    "links" : [
        {
            "rel": "self",
            "href": "http://example.com/people"
        }
    ]
}

为集合实施HATEOAS是否有更简单的解决方案?或者我应该亲吻HATEOAS再见,迫使我过度复杂化数据结构?

4 个答案:

答案 0 :(得分:34)

请不要因为它看起来有点臃肿而快速解散HAL(以JSON形式,它很小)。

HAL是JSON HTML是纯文本的。

它添加了超链接。您需要REST的超链接和通常理解的表示格式(例如HAL或Collection + JSON)。你还需要HATEOAS for REST,没有HATEOAS它不是REST! HATEOAS当然需要超链接。

在您的情况下,您正在尝试构建集合资源。 IANA-registered relation为“item”(反向关系为“collection”)。以下是HAL中People集合的表示形式:

{
    "_links": {
        "self": { "href": "http://example.com/people" },
        "item": [
            { "href": "http://example.com/people/1", "title": "John Smith" },
            { "href": "http://example.com/people/2", "title": "Jane Smith" }
        ]
    },
    "_embedded": {
        "http://example.com/rels#person": [
            {
                "first_name": "John",
                "last_name": "Smith",
                "_links": {
                    "self": { "href": "http://example.com/people/1" },
                    "http://example.com/rels#spouse": { "href": "http://example.com/people/2" }
                }
            },
            {
                "first_name": "Jane",
                "last_name": "Smith",
                "_links": {
                    "self": { "href": "http://example.com/people/2" },
                    "http://example.com/rels#spouse": { "href": "http://example.com/people/1" }
                }
            }
        ]
    }
}

注意:

  • 此集合的主要数据来自_links.item[]。这些是集合中的项目。 _embedded数组中提供了每个项目的完整(或至少一些其他)数据。如果客户需要这些额外数据,则必须通过_embedded[n]._links.self.href搜索每个n来查找这些数据。这是HAL的设计约束。其他超媒体表示格式具有类似的约束(尽管可能在另一个方向)。

  • 我为title数组的每个成员添加了item值。如果呈现为HTML,则可以在开始和结束锚标记之间出现,或者在客户端中显示为菜单项的文本,而无需客户端进一步处理该表示。

  • 没有ID参数。对其他资源的所有引用都作为超链接公开。客户端不应该通过在某个预定义的位置将ID粘贴到URL中来“构建”URL。这构成了禁止对客户端和服务器进行独立更改的带外信息。

  • 您的所有超链接都应该是绝对的,因为相对URL可能会导致问题。您的所有关系都应列在该IANA页面上,或使用URI来定义它们。理想情况下,该URI应该是一个可解除引用的HTTP URL,其中包含有关另一端关系的文档。

答案 1 :(得分:15)

答案 2 :(得分:3)

首先,我不认为具有返回集合(JSON数组)的端点的API是真正的REST。但是,大多数“REST”API都在这里修改规则。

我最近为名为NextBus XML feedrestbus开发了一个REST API,它在使用HATEOAS样式的超文本链接时从某些端点返回集合。以下是我使用的结构示例:

{
  // ... SF-Muni resource from restbus API ...

  _links: {
    self: {
      href: "http://localhost:3535/agencies/sf-muni",
      type: "application/json",
      rel: "self",
      rt: "agency",
      title: "Transit agency 'sf-muni'."
    },
    to: [
      {
        href: "http://localhost:3535/agencies/sf-muni/routes",
        type: "application/json",
        rel: "describedby",
        rt: "route",
        title: "A collection of routes for transit agency 'sf-muni'."
      },
      {
        href: "http://localhost:3535/agencies/sf-muni/vehicles",
        type: "application/json",
        rel: "describedby",
        rt: "vehicle",
        title: "A collection of vehicles for transit agency 'sf-muni'."
      }
    ],
    from: [
      {
        href: "http://localhost:3535/agencies",
        type: "application/json",
        rel: "bookmark",
        rt: "agency",
        title: "A collection of transit agencies. This is the API root!"
      }
    ]
  }

}

它不会尝试遵循任何流行的JSON链接策略(或其关联的媒体类型),例如HAL et al。因为它们似乎不在IETF Standards Track(尚未)。相反,链接对象目标属性链接关系值会尽可能地满足RFC 5988 Web Linking specifications

您可以查看有关restbus hypertext link structure

的更多详细信息

答案 3 :(得分:1)

您可以尝试查看Restful object specification。那家伙创建具体的API。由于我不喜欢整个想法,因此您可以从中获取许多实用的解决方案。