RESTful方式引用请求体中的其他资源

时间:2015-01-27 18:32:56

标签: api rest restful-architecture

假设我有一个名为group的资源,其代表如下:

{
    "id": 1,
    "name": "Superheroes"
    "_links": {
        "self": {
            "href": "http://my.api.com/groups/1"
        }
    }
}

现在假设我要通过person POST创建一个新的/persons/1实例。我应该将哪一个用于请求正文:

使用ID

{
    "name": "Batman",
    "groupId": 1
}

使用链接

{
    "name": "Batman",
    "group": "http://my.api.com/groups/1"
}

使用第一种方法,我直接访问id以查找相关资源或最终将id存储在数据库中,当我持久保存person实例时。但是使用其他方法,我要么必须从URI中提取id,要么按照链接加载相关资源,然后找出它的id。我真的不想将URI存储在数据库中。

使用后一个选项,看到服务器控制URI的结构,我可以解析链接的id吗?回到服务器本身的链接看起来很奇怪,看到此时我们已经可以直接访问信息了(我们只需要id)。

总结一下,哪些选项最好?

  • 直接使用id。
  • 使用链接,但解析出来。
  • 使用该链接,但访问该链接以获取资源实例,然后获取ID。

3 个答案:

答案 0 :(得分:2)

TL; DR:使用简单的ID。

更详细的解释:

一种直截了当的方法是通过使用有效负载/groups/1/persons发送到{"name": "Batman"}来创建一个人。

然而,虽然这种方法适用于简单的情况,但如果有2个资源需要引用,情况会变得复杂。让我们假设一个人也需要属于一家公司:

GET /persons/1
{
   "name": "Batman",
   "group": 1,    // Superheros, available at /groups/1
   "company": 5  // Wayne Enterprises, available at /companies/5
}

由于公司和群组之间没有任何关系,因此通过POST /groups/1/companies/5/persons/companies/5/groups/1/persons创建人员在语义上并不正确。

因此,我们假设您要创建一个请求如下的人:

POST /persons
{
    "name": "Batman"
    "group": ???,     // <--- What to put here?
    "company": ???    // <--- What to put here?
}

这使我们回答你的问题:

易于使用。您的API应主要设计为易于使用。如果您设计公共API,则尤其如此。因此,选项2(使用链接,但解析出来的ID)已经用完,因为它会为您的API客户带来额外的工作。

构建搜索查询。如果您希望能够查询属于公司10和组42的人员,那么简单的ID会导致更易读,更少容易出错的网址。您认为以下哪一项更具可读性?

  • 带有简单ID的网址:

    GET /groups/42?company=10

  • 或带有url-encoded链接的网址:

    GET /groups/42?company=http%3A%2F%2Fmy.api.com%2Fcompanies%2F10

我不会低估可读性。您需要在各种卷发,日志,邮递员等中调试API多少次

开发链接需要在后端解析,而简单的ID可以直接使用。它不是关于性能,而是关于你必须投入的额外工作/测试。

端点维护。想象一下,您的API端点正在发展。您决定有一天切换到https或在网址中包含版本控制。如果由于某种原因它们依赖于链接的结构,这可能会破坏API客户端。此外,您可能想要检查后端上的链接解析是否正确完成。

Argumentum ab auctoritate 我知道这不是一个正确的论据,但如果你查看大型播放器的API,例如Twitter,Github或Stripe,他们都使用简单的ID。

HATEOAS。支持链接的一个常见理由是它与HATEOAS对齐。但是,据我所知,这与API响应中的其他链接有关,而不是在POST请求的有效负载中使用链接。

总而言之,我会选择简单的ID,因为我还没有听到过有利于链接的令人信服的论据,这会超过上述内容。

答案 1 :(得分:1)

根据我的经验,最好采用最简单的解决方案来提出请求。

生成新网址并解析它的过程似乎过多来获取资源,而发送所需项目的ID似乎要简单得多。

因此,我会以以下形式发送请求:

{     &#34;姓名&#34;:&#34;蝙蝠侠&#34;,     &#34; group&#34;:1 }

答案 2 :(得分:1)

你在这里缺少两件重要的事情。

  1. 您需要一种标准方式来描述响应中的表单,在本例中为您的POST表单。
  2. 必须以标准方式在表单中描述有关组ID / uris或如何获取它们的信息。
  3. 例如,带有SELECT INPUT的HTML FORM将是RESTful。我们在json中做的最接近的事情是json-ld和hydra。但是,如果你沉迷于hal,那么使用hyperagent forms或类似的东西。它永远不会成为标准,但如果兼容性不是问题,那就足够了。

    要回答您的问题,您应该使用id,因为服务器知道如何解释它。客户端需要资源标识符,服务器只需要请求的uri部分,而不是正文。