RESTful API 设计注意事项
——Unsplash上的奥马尔·拉纳 (Omer Rana)摄
最近在实际生产系统上工作时,我问了自己一个问题:
REST API 是否应该受到当前架构选择的限制?
为了说明这个问题,我举了一个例子。
假设有一个汽车租赁系统,类似于汽车租赁版的Airbnb。小型汽车租赁公司可以在系统中注册,以便接触到更广泛的潜在客户。该系统允许他们管理自己的车辆,但不能管理其他租赁公司的车辆。
假设我们是一家初创公司,正在构建一个系统。我们从小规模做起,使用关系型数据库将所有车辆信息存储在一个表中。每辆车在这个表中都有一个唯一的ID。
我们希望为我们的系统导出RESTful API。
除此之外,我们还需要 API 来浏览某个地点的所有车辆并获取单辆车的详细信息。
用于列出停车位上所有车辆的 API 可能如下所示:
GET /spots/{spotId}/cars
它会返回一个车辆列表,我们可以从中获取车辆的 ID。
通过车辆 ID 获取车辆信息的 API 可能如下所示:
GET /spots/{spotId}/cars/{carId}
或者
GET /cars/{carId}
为了遵循良好的 API 设计实践,我们决定采用更长的路径,因为车辆是一种资源,它们不能独立存在,并且始终属于特定的位置。这条路径/spots/{spotId}/cars清晰地阐明了它们之间的关系。
然而,spotId路径中的 `in` 是多余的。
因为所有车辆都存储在一个表中,而且我们已经知道车辆 ID(通过/spots/{spotId}/cars端点获取),所以我们真正需要的变量只有 `in` carId。
当然,在我们的关系数据库中,我们会建立车辆到位置的关联,并且可以添加 ` spotIdin out` 查询,但这并非至关重要。
例如,我们可以提出如下查询:
select c.* from cars c inner join spots s
on s.id = c.spot_id
where s.id = :spotId and c.id = :carId
但这样做会得到相同的结果:
select * from cars
where id = :carId
那么,我们应该使用/spots/{spotId}/cars/{carId}哪个路径/cars/{carId}作为端点路径呢?
我一直在考虑这个问题,两种方案各有利弊。正如之前提到的,从 API 语义的角度来看,较长的方案似乎更合适,但较短的方案在当前的后端架构下更容易使用和实现。
如果我们考虑服务的演进,可以设想,我们可能需要将车辆表拆分成每个地点对应的独立表。这种情况可能发生在数据量增长时,或者当我们想要分布式部署数据库,并在每个地点附近设置多个实例(以提高性能和扩展性)时。这样,每辆车在单个数据库实例中都是唯一的(如果我们考虑在特定地点为特定地点部署多个实例,则可能是多个实例)。届时,我们只需通过车辆的 IDspotId和路径来区分车辆,carId而更长的 API 路径也更有意义。
最后,我找到了答案:
API 并非一成不变。架构演进的同时,API 也随之发展。
当前看似合理且简单的/cars/{id}API 在未来可能不再适用。例如,未来如果我需要将车辆数据存储为每个租车点的独立表/数据库,新的 API 可能如下所示:/spots/{spotId}/cars/{carId}。另一方面,这种情况也可能永远不会发生,正如唐纳德·克努特所说:“过早优化是万恶之源”。
你对这个问题有什么解答?如果你还有其他想法,请在评论区与我和其他读者分享。
文章来源:https://dev.to/piczmar_0/restful-api-design-concerns-n8j
