REST API 设计:如何分解 API 对象以使其更具可扩展性和健壮性 API

REST API Design: How to break down the API object to make more scalable and robust API

我们有移动 phone 的电子商务网站。我们正在构建 restful api 到 POST,PUT,DELETE,UPDATE mobile phones.

每个手机 phone 都将具有基本特征,例如:- 价格、制造商、制造年份、颜色、折扣。

除此之外,大多数手机也会有图像。

此外,其中很少有制造商保修。比方说其中的 50%。

而且很少有手机会提供可用的融资选项,例如我们已与某些银行合作以促进为这些手机提供贷款。将近 80% 的人将拥有此设施。

我们正在决定为此设计 api 的两种方法:

方法 1. 所有这些都在同一个 JSON 对象中。只有一个 API 喜欢:

  {   
    "basicInfo": {
      "price": "",
      "mfgYear": "",
      "manufacturer": ""
    ...
  }, 
    "images":{...},  
    "warranty":{...},    
    "finance":{...}    
   }

方法 2. 将所有这些 JSON 对象分开。例如:

   First Api for "basicInfo".
   Second Api for "images".
   Third Api for "warranty".
   Fourth Api for "finance"

我可以找出每个的优点和缺点:

方法 1: 优点: 我们在服务器上收集所有库存信息。这意味着更少的 API 命中,更少的服务器负载。此外,如果将来我们实施一些队列处理以将这些股票信息保存到数据库中,那么在将股票插入数据库之前就不会出现 image/warranty/finance 的情况,因为我们在这里拥有所有信息。所以我们首先将股票插入数据库,然后将记录插入其他具有外键关系的表。 缺点: 这个 API/resource 有多重责任。会越来越大,以后这个API的字段可能会太多。另外,这对我来说似乎违反了单一责任原则。

方法 2: 优点: 这看起来更干净、更有条理。看起来每个 API 都有自己定义的职责。对我来说看起来可扩展。如果在一个 API 中进行更改,则影响其他 API 的可能性较小。 缺点: 服务器上 API 的点击次数更多。在过帐库存之前过帐依赖资源的库存的可能性更大。例如,我们可能会在插入库存之前将图像出列。

Approach3. 给出两个选项。允许发送包含基本信息的其他信息以及为这些资源创建单独的 APIs 的示例。

哪个是最好的方法,即更多 restful、可扩展性和更好的性能?

仅根据您提供的信息,以下是我对设计此系统的看法。为 phones、保修和融资信息提供单独的端点。积极缓存保证,因为它们很少会改变。在 phone 的 JSON 表示中将 link 包含在保修和融资信息中。让 /phones/{phoneId} 端点支持一个名为 "expand" 的查询参数。如果服务器看到 expand=warrantyexpand=financingexpand=warranty, financing,除了提供 link 之外,还将相关的 JSON 嵌入到 phone 资源中.现在客户可以选择他们需要的信息并获取它。

对于图像,如果可能的话使用 CDN 来处理它们并且只包含一个 link。如果您需要在 API 中管理它们,那么我会将它们与上述保修和融资一样对待。确保它们被非常积极地缓存,因为 phone 看起来不会经常改变。如果您需要更改图像,请使用新文件名。

可以在 JSON API 的规范中看到这种方法的示例,其中相关的 属性 称为 "included"。 JSON API 对您来说可能太重了,但它有一些好主意,值得浏览规范。

最后,请注意 open-ended 这样的问题更适合 https://softwareengineering.stackexchange.com/。 Stack Overflow 适用于有正确答案的问题。

我不是 JSON 的专家,但据我所知,可以堆叠这些对象,因此您可以对 inserts/updates 进行分层(完整)推送,也可以完成(或预期不完整)获取- 通话。

这样您就不必破坏每个 push/pull 操作,并且在扩展方面仍然很灵活。 您还可以 - 或者很可能想要 - 为每个子对象的 insert/update 调用专门的例程,以便您也可以提供和使用它们作为 REST API 的一部分。

对于拉动,您可以将缺失的节点标记为 undecided,或者已经检查数据库并标记为 unloadednot available

请记住,如果您为所有子对象(APP.1 或 3)提供 API,则始终由调用者决定对这些调用进行排序 - 特别是涉及到通常以相反顺序完成的删除时。

如果您决定使用复杂的 API(1 或 3),您仍然可以使用队列和超时。因此,您会将请求(主要是写入)存储在队列中,并且 - 在短暂的超时后 - 在将数据转发到 insert/update(/deletion) 例程之前检查队列的完整性。

APPROACH1: Pros: [...] we will first insert stock into the database and then insert record into other tables which will have Foreign Key relationship.

如果你想建立一个稳健API,那么你可以安全地执行交易。

Cons: This API/resource has multiple responsibilities. It would become bigger and bigger and there may be too many fields in this API in future.

您可以减少此检索的负面影响 required fields only