RESTful API做同一件事的不同方式

时间:2019-01-22 16:49:10

标签: rest api-design restful-url

RESTful API设计似乎有些主观,但我希望对以下方法以及它们的优缺点提供一些反馈。是对的吗?都错了吗可以同时提供(即使它会提供部分重复的功能)?

GET被多个ID过滤...

以下是一些看起来很正常的方法(?f =只是说明过滤器/搜索参数的可选用法):

GET /supplier/{supplierId}/products?f=...
GET /oem/{oemId}/products?f=...

要获得产品,URL是否应该超过1个?另外,如果我想同时过滤供应商和OEM?我应该只拥有一个/ products端点,并且所有内容都是一个过滤器,还是只能从供应商/ OEM中的一个而不是从两个供应商/ OEM中访问产品,或者将它们全部在一起??

GET /products?supplier={supplierId}&oem={oemId}&f=...
GET /supplier/{supplierId}/products?oem={oemId}&f=...
GET /oem/{oemId}/products?supplier={supplierId}&f=...

获取子集合而不用父ID过滤...

这是一种看起来很正常的方法:

GET /customers/{customerId}/addresses?f=...

但是,如果我需要所有客户的订单怎么办。这两个都合理吗?

GET /customers/addresses?f=...
GET /addresses?f=...

/ customers / addresses URL(没有{customerId})似乎具有概念意义,但我看不到我一直在寻找的RESTful设计文档中使用的方案(始终存在{id}) 。 / addresses URL很简单,但是破坏了客户地址层次结构。

我想只要它对使用API​​的每个人都有意义并且是一致的,那么它并不真正重要,但是我想知道其他人是如何处理这些类型的以“行业标准”方式解决问题。谢谢。

4 个答案:

答案 0 :(得分:1)

我在这方面没有丰富的经验,因为我只写过一些服务。但是,在开发它们时,我总是发现最好考虑到消费者。消费者对什么感兴趣?在您的第一个示例中,它看起来像是产品,我将供应商和OEM视为特定的过滤器。就我个人而言,我可能会遵循以下原则:

  • 获取:/产品?过滤器(包括供应商和/或OEM)

关于第二部分,我再次建议与消费者合作,以了解什么是重要的,什么对他们有用。他们是对订单特别感兴趣,还是对客户更感兴趣并且需要获取订单的详细信息以及特定客户的地址?

假设是后者,那么我可能会选择类似的东西:

  • 获取:/ customers-获取所有客户的基本信息(id,姓名等)
  • GET:/ customers / {customerId}-获取特定客户的基本信息(ID,姓名等)
  • 获取:/ customers / {customerId} / orders-获取基本的订单信息(订单号,创建日期可能是?)
  • GET:/ customers / {customerId} / orders / {orderId}-获取有关特定订单的详细信息。
  • 获取:/ customers / {customerId} / addresses-获取与客户关联的所有地址。
  • 获取:/ customers / {customerId} / addresses / {addressId}-获取与客户关联的特定地址。

不过,根据上下文,您始终可以具有到同一资源的多个路由:

  • 获取:/ customers / {customerId} / addresses / 123-返回ID为123的地址
  • GET:/ addresses / 123-返回ID为123的地址

归根结底,这取决于API的消费者如何获取信息以及对他们有意义的信息。

答案 1 :(得分:0)

正如您正确地提到的那样,实现这一目标不一定有正确或错误的方式。

个人而言,我喜欢从资源的角度考虑端点,并在GET上应用相关的过滤器以过滤结果。有时候,在有意义的情况下,我会加入GET /search/<sub-resource>以便于在更广泛的上下文中搜索子资源。

关于第一个示例,如果您的主要资源是product,而oemsupplier只是产品的属性(仅与产品有关),则使用/product?supplier=..&oem=...可以对基于oem和/或supplier的产品进行过滤。您可以使用GET /supplierGET /oem分别返回供应商和OEM的详细信息,但不一定返回产品本身。

或者,如果您仅将两者都视为子资源,则可以使用GET /search/oem?product_id=...&customer_id=..基于根资源(例如oemproduct)来搜索customer

关于为客户检索ordersGET /customers/{customerId}/orders?f=...对于单个客户来说是有意义的。要退回所有客户的订单,您可以使用/orders?customerId=...

再次,如果GET /search/orders?customerId=..仅被视为客户的子资源,则可以使用order

同样,以上仅仅是建议。您提出的建议也可以使用。

答案 2 :(得分:0)

对于REST没有严格的规则,因此从某种意义上说,解决方案是主观的。 我将研究如何通过一些大型API REST提供程序解决此问题。 我相信探索Etsy或Fitbit的REST API会带您一些见识。

GET被多个ID过滤

对于您的第一种情况,我将研究创建一个聚合服务,该服务对/supplier/{supplierId}/products?f=/oem/{oemId}/products?f=进行2个并行调用,并合并结果集。它基于Etsy对他们的concept of "bundles"所做的事情。

您可以使它接受filters=[key=value,key=value]形式的过滤器列表,但这自然仅支持过滤器的结合。

获取子集合而无需按父ID进行过滤

Google和其他公司正在使用“-”作为所有概念。

例如:

/customers/{customerId}/addresses是单个客户的所有地址

/customers/-/addresses是所有客户的所有地址

如果您要保留某种层次结构(例如,在您的域中有员工和客户,并且两个组都有地址),这很有用。 然后您可能会说:

/customers/-/addresses
/employees/-/addresses

如果不需要层次特征,则可以仅公开所有地址的专用端点(简单地为/addresses)。

答案 3 :(得分:0)

在这方面,我也将给出一个稍微不同的观点。

您主要是在谈论资源集合,而不是在此集合中的单个资源。

通常,我想确保每个单独的资源(例如产品)都有自己的唯一网址。例如/products/1234

但是,产品可能会出现在多个馆藏中。集合实际上并不是“拥有”或“包含”集合中的项目,它只是链接到它。因此,可以考虑的一种方法是可以有很多包含相同产品的集合。

您怎么知道它是否出现在多个收藏集中?随函附上您要嵌入的产品的uri,因此,始终非常清楚这些集合实际上都链接到同一事物。

这确实类似于文件系统。许多目录可以包含相同(硬链接或软链接)文件。

来源: