【问题标题】:RESTful API URI DesignRESTful API URI 设计
【发布时间】:2012-10-23 20:45:03
【问题描述】:

我正在寻找有关 RESTful API 的 URI 设计的方向。我将有几个嵌套的链接资源,目前我设计的 URI 类似于这篇文章:Hierarchical RESTful URL design

以下示例不是我正在构建的示例,但我认为很好地说明了我的情况。 (假设一个节目只能属于一个网络)。

/networks [GET,POST]
/networks/{network_id} [GET,PUT]
/networks/{network_id}/shows [GET,POST]
/networks/{network_id}/shows/{show_id} [GET,PUT]
/networks/{network_id}/shows/{show_id}/episodes [GET,POST]
/networks/{network_id}/shows/{show_id}/episodes/{episode_id} [GET,PUT]

我的情况将通过关联进一步发展两个层次,但所有关联都是一对多的。我正在考虑将其切换为类似于以下内容:

/networks [GET,POST]
/networks/{network_id} [GET,PUT]
/networks/{network_id}/shows [GET,POST]

/shows [GET]
/shows/{id} [GET,PUT]
/shows/{id}/episodes [GET,POST]

/episodes [GET]
/episodes/{id} [GET,PUT]

我的问题是:

  1. 第二个示例是有效的 REST 设计吗?
  2. 我应该考虑同时实现这两条路径吗?

【问题讨论】:

  • 请记住,您最终决定了 RESTful API 的结构。将使用它的是您的客户。我认为两者都很好,尽管显然第一个更擅长说明网络、节目和剧集之间的层次结构。但是,如果 URI 变得异常长,那么将这些实体分离到 / 下也不是很疯狂。我会问自己,实际上哪些资源会被使用得最多。如果是剧集和节目,那么将它们放在基础之下很有意义。

标签: rest uri restful-url restful-architecture


【解决方案1】:

第二个例子对我来说很好。 URL 描述了资源,并且使用了正确的 HTTP 动词。

如果有意义的话,让多个 URL 指向同一个资源是完全可以的。但更重要的是,确保资源包含 <link /> 元素,这些元素将节目与网络、剧集与节目等联系起来。

【讨论】:

  • +1:我自己更喜欢xlink:href 属性,但<link> 元素也不错。
  • 属性在 XML/XHTML 中运行良好,但像 JSON 这样的一些表示不支持它们。无论如何,重要的是利用超媒体让服务真正实现 RESTful。
【解决方案2】:

真正的问题是:您的第二个示例是否满足 URI 标准? URI 标准规定,路径包含分层部分,查询包含非分层部分,但是 afaik。它没有说明如何在您的情况下设计 URI 结构。 REST 统一接口约束有一个 HATEOAS 部分,这意味着您应该在您的情况下发回指向上层和下层资源的链接。您应该使用元数据注释这些链接,这些元数据可以由客户端处理,因此它会知道链接是关于什么的。所以在实践中,URI 结构并不重要......

GET /shows/123

{
    "label": "The actual show",
    "_embedded": {
        "episodes": [
            {
                "label":  "The first episode of the actual show",
                "_embedded": {
                    "associations": [
                        //...
                    ]
                },
                "_links": {
                    "self": {
                        "label": "Link to the first episode of the actual show",
                        "href": "/episodes/12345"
                    },
                    "first": {
                        "href": "/episodes/12345"
                    },
                    "duplicate": {
                        "href": "/networks/3/shows/123/episodes/12345"
                    },
                    "up": {
                        "label": "Link to the actual show",
                        "href": "/shows/123"
                    },
                    "next": {
                        "label": "Link to the next episode of the actual show"
                        "href": "/episodes/12346"
                    },
                    "previous": null,
                    "last": {
                        "href": "/episodes/12350"
                    }
                }
            }//,
            //...
        ]
    },
    "_links": {
        "self": {
            "label": "Link to the actual show",
            "href": "/shows/123"
        },
        "duplicate": {
            "href": "/networks/3/shows/123"
        },
        "up": {
            "label": "Link to the actual network",
            "href": "/networks/3"
        },
        "collection": {
            "label": "Link to the network tree",
            "href": "/networks"
        },
        "next": {
            "label": "Link to the next show in the actual network",
            "href": "/shows/124"
        },
        "previous": {
            "label": "Link to the previous show in the actual network",
            "href": "/shows/122"
        }
    }
}

现在这只是 HAL+JSON 中带有 IANA 链接关系的测试版,但您也可以将 JSON-LD 与 RDF 词汇表(例如 schema.org+hydra)一起使用。这个例子只是关于层次结构(上,第一个,下一个,上一个,最后一个,集合,项目等......),但您应该添加更多元数据,例如哪个链接指向一个网络,哪个指向一个节目,哪个指向一集,等等……所以您的客户将从元数据中知道内容是关于什么的,例如,他们可以使用这些链接自动导航。这就是 REST 的工作方式。所以 URI 结构对客户端来说并不重要。 (如果您想让响应更紧凑,也可以使用紧凑 URI 和 URI 模板。)

【讨论】:

    【解决方案3】:

    URI 是“任何可以命名的信息”

    您的问题是与域相关的问题,只有知道您使用 URI 命名的资源的人才能真正回答。

    在尝试猜测您的域时想到的问题是,“节目”真的依赖于“网络”吗?

    您的域中的网络是什么?节目和网络是什么关系?只是单纯的播过节目的人吗?还是更多地与生产信息有关?

    我相信您的示例 2 更合适。

    【讨论】:

      【解决方案4】:

      考虑到您在以下层次结构中有一对多关系:

      network --> shows --> episodes
      

      我认为第二种设计没有向服务器端提供足够的信息来处理您的请求。例如,如果您有以下数据:

      Network id  show_id episode_id
          1         1        1
          1         2        1
          1         1        2
      

      第一个详细的设计将在 HTTP 请求中提供足够的信息来获取数据:/networks/1/shows/1/episodes/1

      相反的第二种设计将有:

      /episodes/1 
      

      在第二种设计中,服务器端无法知道您是指数据中的第 1 行还是第 2 行

      回答你的问题:

      1. 恕我直言,第二个设计对于您的示例可能不是有效的 REST 设计。一种 解决方法可能是传递查询参数

      2. 我认为设计 1 是自给自足的

      更新:请忽略我上面的回答

      1. 第二个设计是您的示例的有效 REST 设计
      2. 只有设计 2 就足够了

      另外:

      /networks
      /networks/{id}
      
      /shows
      /shows/{id}
      
      /episodes
      /episodes/{id}
      

      应该有足够数量的 REST URL

      或者换句话说,以下 URL 将是多余的:

      /networks/{network_id} [GET,PUT]
      /networks/{network_id}/shows [GET,POST]
      
      /shows/{id}/episodes [GET,POST]
      

      【讨论】:

      • 亲爱的 Vikram,如果我误解了,请纠正我,您是否建议剧集正确设计需要 3 列复合主键?
      • @AlessandroOliveira 感谢您的评论。你的评论帮助我理解了问题中的第二个设计也是一个有效的设计!!回答您的问题:3 列复合主键只是理解这 3 个分层实体之间关系的一种表示。我不是要推荐它...
      • 我非常关心的另一件事是将主键暴露为对象 ID,我认为即使系统具有身份验证和授权措施,这些实施决策也不应该暴露在任何大大地。但由于我是 UUID 的拥护者,我的立场也算是有点偏颇了。
      • @AlessandroOliveira 我同意你的看法
      【解决方案5】:

      我认为我们应该使 REST API URL 尽可能简单。

      例如https://www.yoursite.com/api/xml/1.0/

      这里我以 1.0 版的 XML API 为例。请记住使用 API 版本以供将来更新。

      您可以查看客户端请求的方法。

      e.g. tag
      
      <method>getEpisodes</method>
      

      【讨论】:

      • 这看起来不是特别 RESTful,而是非常 SOAPy(如果您正在这样做,这没关系,但是 SOAP 和 REST 是构建应用程序的非常不同的方法......)
      • 我主要关心的是 API 的版本。例如我的稳定 API 版本是 1.2,我的客户在他们的应用程序中使用相同的版本。现在我们增强了我们的 API(1.4 版)并弃用了 1.2 版支持的 API 的一些功能。我使用 1.2 版的客户将收到有关已弃用功能的错误。请告诉我你的想法。
      【解决方案6】:

      我认为第二个选项还可以,但如果您想验证关系,我会考虑第一个选项。例如,当您使用不同的网络获得一集时,这可能意味着该集在您的请求之前已被修改,因此您可能需要使用 422 响应,对于其他服务也是如此。有了这个,您可以确定您要处理的实体涉及其父级。

      PD:对不起我的英语。

      【讨论】:

        猜你喜欢
        • 2013-10-30
        • 1970-01-01
        • 2011-07-14
        • 1970-01-01
        • 2021-09-30
        • 2021-10-20
        • 1970-01-01
        • 1970-01-01
        • 2018-02-11
        相关资源
        最近更新 更多