【问题标题】:RESTful way of referencing other resources in the request body在请求正文中引用其他资源的 RESTful 方式
【发布时间】:2015-01-28 05:07:46
【问题描述】:

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

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

现在假设我想通过POSTing 到/persons/1 创建一个新的person 实例。我应该为请求正文使用以下哪一项:

使用 ID

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

使用链接

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

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

使用后一种选项,看到服务器控制了URI的结构,我可以从链接中解析出id吗?将链接返回到服务器本身似乎很奇怪,因为此时我们已经可以直接访问信息(我们只需要 id)。

所以总结一下,这些选项中哪个最好?

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

【问题讨论】:

    标签: api rest restful-architecture


    【解决方案1】:

    TL;DR:使用简单的 ID。

    更详细的解释:

    一种简单的方法是通过 POST 到 /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 会导致更易读且不易出错的 url .您认为以下哪项更具可读性?

    • 带有简单 id 的网址:

      GET /groups/42?company=10

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

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

    我不会低估可读性的意义。你需要在各种 curls、logs、postmans 等中调试你的 API 多少次?

    开发 链接需要在后台解析,而简单的id可以直接使用。这与性能无关,而与您必须投入的额外工作/测试有关。

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

    Argumentum ab auctoritate 我知道这不是一个正确的论点,但如果您查看大型玩家的 API,例如Twitter、Github 或 Stripe,它们都使用简单的 id。

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

    总而言之,我会选择简单的 id,因为我还没有听到有利于链接的令人信服的论点,这将击败上述。

    【讨论】:

      【解决方案2】:

      您在这里遗漏了两件重要的事情。

      1. 您需要一种标准的方式来描述响应中的表单,在本例中是您的 POST 表单。
      2. 必须以标准方式在表单中描述有关组 ID/URI 的信息或如何获取它们。

      例如,带有 SELECT INPUT 的 HTML FORM 将是 RESTful。我们在 json 中最接近做同样的事情是 json-ld 和 hydra。但是如果你对 hal 很着迷,那就使用hyperagent forms 或类似的东西。它永远不会成为标准,但如果兼容性不是问题,那就足够了。

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

      【讨论】:

      • 我不太关心 HTML 表单,但是您关于 id 的观点是有道理的,尤其是当您将其与客户端进行比较时。客户端需要了解链接,因为这是它访问资源的方式。服务器不需要知道它们,因为它可以使用 Id。
      【解决方案3】:

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

      生成一个新的 url 并解析它的过程似乎是为了获取资源而过度,而发送你想要的项目的 id 似乎要简单得多。

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

      { “名称”:“蝙蝠侠”, “组”:1 }

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-09-07
        • 1970-01-01
        • 1970-01-01
        • 2011-03-18
        • 1970-01-01
        • 2019-11-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多