当相关资源属于不同的微服务时,如何处理 REST API 路径?

Posted

技术标签:

【中文标题】当相关资源属于不同的微服务时,如何处理 REST API 路径?【英文标题】:How to handle REST API paths when related resources belong to different microservices? 【发布时间】:2016-12-16 06:32:06 【问题描述】:

我有两个微服务:

UserService,定义了/users、/users/:id等路径; MessageService,定义了/messages、/messages/:id等路径。

此外,MessageService 中的每条消息都有一个属性 user_id,它引用 UserService 中的用户。

现在,假设我想列出给定用户的所有消息。目前我可以想到以下几种方法:

    如果我想遵循最佳 REST API 实践,像 /users/:id/messages 这样的路径似乎是最好的方法。但是,在我看来,我无法在 MessageService 中定义这样的路径,因为我会将它紧密耦合到 UserService。我相信以 /users 开头的路径应该只属于 UserService。 /messages?user_id=:id 所以我可以使用现有的 /messages 路径并按属性 (user_id) 添加过滤器。不确定是否是一个好的做法。 在微服务前面放置一个 API 网关,并创建一个从 /users/:id/messages/messages?user_id=:id 的代理。这允许客户端使用对 REST 最友好的路径,同时保持微服务松散耦合。

以下哪种方法最合适?

【问题讨论】:

【参考方案1】:

这个问题没有正确或错误的答案。 IMO,这取决于消息是独立资源还是域逻辑中用户资源的一部分。

如果消息始终属于单个用户,那么您可以将用户的消息视为消息集合中的子资源或分层划分,我可能更喜欢第一个 URI 方案。在这种情况下,我可能会选择像/user/:id/messages 这样的路径,而不是复数“用户”。或者将用户 ID 放在消息后面,例如:/messages/user/:id

如果消息本身是您域中的一个实体,或者可以属于多个用户(如电子邮件),则使用查询字符串方案过滤消息会更有意义。

【讨论】:

是的,消息始终属于单个用户。在不存储用户的微服务中设置以 /user 开头的路径是否是一种好习惯,只是对它们的引用? 我认为在这种情况下没问题。如果您的服务公开了一个名为“用户”(复数)的资源,我希望能够对其进行 CRUD 操作。在这种情况下,我将其视为消息集合的分层划分。但是如果你不喜欢它,你也可以把用户放在消息集合后面,像这样:/messages/user/:id【参考方案2】:

如果您已经设计了用户和消息是两个不同的域/微服务的微服务,那么您最好的选择是设计一个结合这两种服务并提供客户需求的边缘服务。例如,服务可以是

/messages_by_user/:id

请记住,微服务将主要在域资源上提供 CRUD 操作,但客户端需要的不仅仅是对资源的 CRUD 操作,在这种情况下,您应该始终考虑创建边缘服务以满足客户的需求。

如果您还没有实现这些服务,那么我建议将用户和消息放在同一个微服务中,并将用户视为消息的子资源。在这种情况下,所有波纹管路径都是有效的。

/messages
/messages/:id
/message/:id/users
/messages/user/:id

当您设计一个微服务时,您需要在更有意义的方面取得平衡。虽然理论上每个资源及其CRUD 操作都应该有一个单独的微服务,但实际上你可以将很少的相关资源组合成一个子资源,只要不影响服务的可扩展性和性能。

【讨论】:

以上是关于当相关资源属于不同的微服务时,如何处理 REST API 路径?的主要内容,如果未能解决你的问题,请参考以下文章

如何处理 REST api 中的关系

在 REST 中,我们如何处理返回资源集合的多种方式?

Spring Data REST CORS - 如何处理预检选项请求?

发生管道损坏时如何处理 AJAX 响应?

如何处理Zuul中的hystrix后备?

您如何处理 REST API 服务器中的高吞吐量函数?