据我所知,每个单独的资源应该只有一个规范路径。那么在下面的例子中,好的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比
收集/项目/集合。
我不同意这种方式
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的成熟度模型”的第三级)。