我正在为一个私人项目开发一个API(以及一个SPA),我不能在两个路由命名约定之间做出决定。
假设我的数据库中有三个表:Users
,Products
和Orders
。如果我希望用户能订购产品,我应该遵循以下哪个约定?
POST /orders
与正文{ "product": 1 }
POST /products/{id}/order
注意:在这两种情况下,都会根据提供的访问令牌推断出user
。
对我而言,上述两种解决方案之间的主要区别在于要向前端开发人员公开的接口类型:我是否将路由暴露给资源(解决方案1)或动作要执行(解决方案2)?
是否有实际(dis)优势使用一种方法而不是另一种方法或仅仅是个人品味的问题?
如果我错了,请纠正我,但从我的理解解决方案1是REST("创建此资源"),而解决方案2不是("执行此操作" 34。)
此外,使用解决方案1,每条路径都会直接映射到我的数据库中的一个表,有些人说这是一个坏主意,因为外部开发人员可以根据API路由推断出数据库的架构但是老实说我不知道这是怎么回事。
答案 0 :(得分:3)
根据我的研究以及GitHub和Instagram API的终端,对于用户订购产品最有意义的是公开POST /users/123/orders {"product": 456}
而不是POST /orders {"product": 456, "user": 123}
。 这里的想法是考虑资源的上下文(如果有的话)。
请注意,我们不需要在网址中使用'update'动词短语 因为我们可以依靠HTTP动词来通知该操作。只为了 澄清一下,以下资源URL是多余的:
PUT http://api.example.com/customers/12345/update
在请求中同时使用PUT和'update',我们提出要混淆 我们的服务消费者“更新”资源吗?
<强> 4。使用子资源进行关系
如果资源与其他资源相关,则使用子资源。
GET /cars/711/drivers/ Returns a list of drivers for car 711 GET /cars/711/drivers/4 Returns driver #4 for car 711
GitHub和Instagram API似乎也是这样运作的,即在资源相关时使用资源的上下文。
例如,如果您想使用GitHub的API获取list of a user's organizations,则可以使用GET /users/flawyte/orgs
而不是GET /orgs {"username": "flawyte"}
。
如果您想要媒体,请使用Instagram的API:POST /media/{media_id}/likes
。
答案 1 :(得分:1)
是否有实际(dis)优势使用一种方法而不是另一种方法或仅仅是个人品味的问题?
拼写选择主要是品味和惯例。从客户端的角度来看,这两者都是不透明的URI,可用于遵循您的协议。拼写约定适用于人类读者,并使您更容易实现端点。
如果我错了,请纠正我,但从我的理解解决方案1是REST(“创建此资源”)而解决方案2不是(“执行此操作”)。
不,但这是一种常见的误解。
REST架构风格对诸如“客户端如何知道应遵循哪个uri”以及“客户端如何知道有效载荷中应使用哪种媒体类型”等问题更感兴趣。> p>
您可能需要注意的是,URI标识您的资源,而不是您的资源恰好与之通信的域模型实体。
另外,对于解决方案1,每条路径都会直接映射到我的数据库中的一个表,有些人说这是一个坏主意,因为外部开发人员可以根据API路由推断出数据库的模式,但老实说我看不出它是怎么回事一个问题。
其他方式 - 当您想要修改架构时,您是否打算重写所有客户端?或者您是否打算将客户端与域的实现细节分离?
思考Gang of Four中的适配器模式 - 您为客户提供了一个设计良好,稳定,可以与之通信的API,以及您的资源实现,您可以根据模型的当前实现调整请求。
REST是数十年的软件设计:每个细节都旨在促进软件的使用寿命和独立的发展。
请记住:如果这些属性对您不重要,如果它们不支持您当前的价值主张,那么您需要在这些约束中交换更合适的内容。