代码之家  ›  专栏  ›  技术社区  ›  devlop

restful api做同样事情的不同方式

  •  1
  • devlop  · 技术社区  · 6 年前

    restful api设计似乎有点主观,但我想对下面的方法以及它们的优缺点给出一些反馈。一个对吗?都错了吗?两者都可以提供(即使它会提供部分重复的功能)?

    按多个ID筛选…

    以下是一些看起来相当正常的方法。f=只是说明筛选/搜索参数的可选使用:

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

    应该有一个以上的url来获取产品吗?另外,如果我想过滤供应商和原始设备制造商呢?我应该仅仅有一个/产品端点,所有的东西都是一个过滤器,或者只有一个供应商/原始设备制造商可以访问产品,但不能同时访问这两个,或者将它们全部放在一起?:

    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 回复  |  直到 6 年前
        1
  •  1
  •   Ben    6 年前

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

    • 获取/产品?过滤器(包括供应商和/或原始设备制造商)

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

    假设是后者,那么我可能会说:

    • get:/customers-获取所有客户的基本信息(id、姓名等)
    • get:/customers/{customer id}-获取特定客户的基本信息(id、名称等)
    • get:/customers/{customerid}/orders-获取基本订单信息(订单号,创建日期?)
    • get:/customers/{customerid}/orders/{orderid}-获取有关特定订单的详细信息。
    • get:/customers/{customerid}/addresses-获取与客户关联的所有地址。
    • get:/customers/{customerid}/addresses/{addressid}-获取与客户关联的特定地址。

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

    • get:/customers/{customerid}/addresses/123-返回ID为123的地址
    • get:/addresses/123-返回ID为123的地址

    归根结底,这一切都取决于api的消费者希望如何获取信息,以及他们认为什么是有意义的。

        2
  •  0
  •   Mo A    6 年前

    正如你正确地提到的,实现这一目标不一定有对或错的方法。

    就我个人而言,我喜欢从资源的角度考虑端点,并在 GET 过滤结果。有时,当它有意义的时候,我会包括 GET /search/<sub-resource> 以便于在更广泛的上下文中搜索子资源。

    关于第一个例子,如果您的主要资源是 product 同时 oem supplier 只是产品的一个属性(仅存在于产品中),然后使用 /product?supplier=..&oem=... 基于产品筛选 贴牌生产 和/或 供应商 会起作用。你可以使用 GET /supplier GET /oem 返回供应商和原始设备制造商的详细信息,但不一定是产品本身。

    或者,如果您将两者都视为子资源,则可以使用 GET /search/oem?product_id=...&customer_id=.. 寻找 贴牌生产 基于根资源,例如 产品 customer .

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

    同样,作为替代方案,您可以使用 GET /search/orders?customerId=.. 如果 order 仅被视为客户的子资源。

    同样,以上只是建议。你的提议也能奏效。

        3
  •  0
  •   Evert    6 年前

    我也会给出一个稍微不同的观点。

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

    一般来说,我喜欢确保每个资源(例如一个产品)都有自己独特的url。例如 /products/1234

    但是,一个产品可能出现在多个集合中。集合并不真正“拥有”或“包含”集合中的项,它只是链接到该项。因此,一种思考的方式是,可以有许多包含相同产品的集合。

    你怎么知道是同一个产品出现在多个收藏中?将要嵌入的产品的uri括起来,这样就可以非常清楚地看到,这些集合实际上都链接到同一个东西。

    这与文件系统非常相似。许多目录可以包含相同的(硬链接或软链接)文件。

    资料来源:

        4
  •  0
  •   hovanessyan    6 年前

    休息没有严格的规则,所以解决方案在某种意义上是主观的。 我将看看如何通过一些大型的API rest提供者来解决这个问题。 我相信探索etsy或fitbit的rest api会给你带来一些启示。

    按多个ID筛选

    在您的第一个案例中,我将研究创建一个聚合服务,它对 /supplier/{supplierId}/products?f= /oem/{oemId}/products?f= 合并结果集。这是基于Etsy对他们的 concept of "bundles" .

    你可以让它接受一个过滤器列表 filters=[key=value,key=value] 但这自然只支持过滤器的连接。

    不按父ID筛选而获取子集合

    谷歌和其他公司正在使用“-”作为所有人的概念。

    例如:

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

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

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

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

    如果您不需要层次结构特征,那么您可以为所有地址公开一个专用端点(简单地说 /addresses )