据我所知,每个单独的资源应该只有一个规范路径。那么在下面的例子中,好的URL模式是什么呢?

以公司的rest表示为例。在这个假设的例子中,每个公司拥有0个或多个部门,每个部门拥有0个或多个员工。

没有关联公司,一个部门就不能存在。

一个员工的存在离不开一个相关的部门。

现在我发现资源模式的自然表示是。

公司的集合-接受新公司的POST。获取整个集合。 /companies/{companyId}单个公司。接受GET, PUT和DELETE /companies/{companyId}/departments接受新项的POST。(在公司内部创建一个部门。) /公司/ {companyId} / {departmentId} / /部门 /公司/ / {departmentId} / {companyId} /部门员工 /公司/ {companyId} /部门/ {departmentId} /员工/ {empId}

考虑到每个部分的限制,我认为这是有意义的,如果嵌套有点深的话。

然而,如果我想列出(GET)所有公司的所有员工,我的困难就来了。

它的资源模式将最紧密地映射到/employees(所有员工的集合)

这是否意味着我应该有/employees/{empId},因为如果是这样,那么就有两个URI来获得相同的资源?

或者可能整个模式应该是扁平的,但这意味着雇员是一个嵌套的顶级对象。

在基本层面/员工/?company={companyId}&department={deptId}返回与嵌套最深的模式完全相同的员工视图。

对于资源属于其他资源,但应该可以单独查询的URL模式,最佳实践是什么?


当前回答

我读了上面所有的答案,但似乎他们没有共同的策略。我从Microsoft Documents找到了一篇关于Design API最佳实践的好文章。我认为你应该推荐。

In more complex systems, it can be tempting to provide URIs that enable a client to navigate through several levels of relationships, such as /customers/1/orders/99/products. However, this level of complexity can be difficult to maintain and is inflexible if the relationships between resources change in the future. Instead, try to keep URIs relatively simple. Once an application has a reference to a resource, it should be possible to use this reference to find items related to that resource. The preceding query can be replaced with the URI /customers/1/orders to find all the orders for customer 1, and then /orders/99/products to find the products in this order.

.

提示 避免要求资源uri比 收集/项目/集合。

其他回答

你所做的是正确的。一般来说,同一个资源可以有多个uri——没有规则说你不应该这样做。

通常,您可能需要直接访问项目或作为其他内容的子集-所以您的结构对我来说是有意义的。

仅仅因为员工在部门下面是可访问的:

公司/ / {departmentid} / {companyid} /部门员工

这并不意味着他们不能在陪伴下访问:

公司/ {companyid} /员工

这将为该公司带回员工。这取决于你的消费客户需要什么——这就是你应该为之设计的。

但我希望所有url处理程序都使用相同的支持代码来满足请求,这样就不会重复代码。

我已经把我所做的事情从问题转移到更多人可能看到的答案。

我所做的是在嵌套端点上创建端点,用于修改或查询项的规范端点不在嵌套资源上。

在这个例子中(只列出改变资源的端点)

POST /companies/创建一个新公司返回一个到已创建公司的链接。 POST /companies/{companyId}/departments当一个部门被放置时,会创建一个新的部门返回到/departments/{departmentId}的链接 PUT /departments/{departmentId}用于修改部门 POST /departments/{deparmentId}/employees创建一个新的员工,返回到/employees/{employeeId}的链接。

因此,每个集合都有根级资源。但是,create是在所属对象中。

我不同意这种方式

GET /companies/{companyId}/departments

如果您想获取部门,我认为最好使用/departments资源

GET /departments?companyId=123

我假设你有一个公司表和一个部门表,然后用你所使用的编程语言来映射它们。我还假设部门可以附加到其他实体,而不是公司,因此/departments资源是直接的,将资源映射到表很方便,而且由于可以重用,您不需要那么多端点

GET /departments?companyId=123

例如,任何类型的搜索

GET /departments?name=xxx
GET /departments?companyId=123&name=xxx
etc.

如果要创建一个部门,可以使用

POST /departments

资源,请求体应该包含公司ID(如果部门只能链接到一个公司)。

url的外观与REST无关。任何事情都可能发生。它实际上是一个“实现细节”。就像给变量命名一样。它们所需要的是独特和耐用。

不要在这上面浪费太多时间,只要做出选择并坚持下去。例如,如果你采用层次结构,那么你对所有资源都这样做。如果你使用查询参数…等等,就像代码中的命名约定一样。

为什么?据我所知,“RESTful”API是可浏览的(你知道…“超媒体作为应用程序状态的引擎”),因此API客户端并不关心你的url是什么样的,只要它们是有效的(没有SEO,没有人需要阅读这些“友好的url”,除了可能是为了调试…)

REST API中的URL有多好/易懂,只对作为API开发人员的你感兴趣,而不是API客户端,就像代码中的变量名一样。

最重要的是你的API客户端知道如何解释你的媒体类型。 例如,它知道:

您的媒体类型有一个links属性,它列出了可用的/相关的链接。 每个链接都由一个关系来标识(就像浏览器知道link[rel="stylesheet"]意味着它是一个样式表,或者rel=favico是一个指向favicon的链接…) 它知道这些关系的含义(“公司”指的是公司列表,“搜索”指的是在资源列表上进行搜索的模板url,“部门”指的是当前资源的部门)

下面是一个HTTP交换的示例(正文在yaml中,因为它更容易编写):

请求

GET / HTTP/1.1
Host: api.acme.io
Accept: text/yaml, text/acme-mediatype+yaml

响应:主要资源的链接列表(公司,人,等等…)

HTTP/1.1 200 OK
Date: Tue, 05 Apr 2016 15:04:00 GMT
Last-Modified: Tue, 05 Apr 2016 00:00:00 GMT
Content-Type: text/acme-mediatype+yaml

# body: this is your API's entrypoint (like a homepage)  
links:
  # could be some random path https://api.acme.local/modskmklmkdsml
  # the only thing the API client cares about is the key (or rel) "companies"
  companies: https://api.acme.local/companies
  people: https://api.acme.local/people

请求:链接到公司(使用之前的响应的body.links.companies)

GET /companies HTTP/1.1
Host: api.acme.local
Accept: text/yaml, text/acme-mediatype+yaml

Response:一个公司的部分列表(在项目下),资源包含相关链接,如链接得到下一对公司(body.links.next)的另一个(模板)链接搜索(body.links.search)

HTTP/1.1 200 OK
Date: Tue, 05 Apr 2016 15:06:00 GMT
Last-Modified: Tue, 05 Apr 2016 00:00:00 GMT
Content-Type: text/acme-mediatype+yaml

# body: representation of a list of companies
links:
  # link to the next page
  next: https://api.acme.local/companies?page=2
  # templated link for search
  search: https://api.acme.local/companies?query={query} 
# you could provide available actions related to this resource
actions:
  add:
    href: https://api.acme.local/companies
    method: POST
items:
  - name: company1
    links:
      self: https://api.acme.local/companies/8er13eo
      # and here is the link to departments
      # again the client only cares about the key department
      department: https://api.acme.local/companies/8er13eo/departments
  - name: company2
    links:
      self: https://api.acme.local/companies/9r13d4l
      # or could be in some other location ! 
      department: https://api2.acme.local/departments?company=8er13eo

你可以看到,如果你用链接/关系的方式构造url的路径部分对API客户端没有任何价值。如果你把你的url结构作为文档传达给你的客户端,那么你就不是在使用REST(或者至少不是按照“Richardson的成熟度模型”的第三级)。

Rails为此提供了一个解决方案:浅嵌套。

我认为这很好,因为当您直接处理已知资源时,不需要使用嵌套路由,正如在这里的其他回答中所讨论的那样。