我不清楚,如果我有一个微服务来提供一些派生数据,那么应该如何为此设计其余的api。例如: -
如果我有客户并且我想访问客户,我会将API定义为:
/客户/ 1234
这将返回我们了解客户的所有信息
但是,如果我想提供一个微服务,它只是告诉我客户之前是否知道系统有另一个帐号,我该怎么做。我希望这个逻辑在微服务中,但我如何定义API
客户/ 1234 / previouslyKnow
customerPreviouslyKnown / 1234
两者似乎都不正确。在第一种情况下,它意味着
客户/ 1234
可用于获取所有客户信息,但微服务不提供此信息。
困惑!
添加一些额外的细节以便澄清。
我想我的问题是,我真的不想要一个处理客户相关问题的大规模服务。如果有更轻量级的服务来处理客户订单,客户信息,客户历史,客户状态(现场,丢失,死亡......)会更好。
我觉得所有这些都是从
开始的/客户/ XXXX
如果在路径中没有额外的客户/ XXXX,例如/ orders
,那么预期所有服务都会提供客户对象上面提到的一些数据实际上并没有在它派生的任何地方持久化,我希望这个逻辑隐藏在服务中而不是在调用代码中。那么如何请求并返回。
答案 0 :(得分:0)
执行微服务并不意味着每个方法都有一个单独的工件。耦合和内聚的规则也适用于微服务世界。因此,如果您可以查询与客户相关的多个数据,则相关资源应该属于同一服务。
因此,您的资源将是/customers/{id}/previous-customer-numbers
,而/customers
(复数!)是客户列表,/customers/{id}
是单个客户,/customers/{id}/previous-customer-numbers
客户编号列表客户以前有过。
尝试考虑资源,而不是操作。因此,返回先前使用的客户编号列表比返回一个布尔值更好。我认为/customer/{id}/previous-accounts
会更好......
返回主题:如果previous-accounts
的值直接来自相同的数据,即您不需要查询第二个数据库等,我甚至建议只将值添加到客户表示中:
{
"id": "1234",
"firstName": "John",
"lastName": "Doe",
"previouslyKnown": true,
"previousAccounts": [
{
"id": "987",
...
}
]
}
数据是存储还是导出无关紧要,因此服务客户端不应该在边界上可见。
从长远来看,添加其他资源甚至是其他服务是不必要的复杂性和复杂性。
你提到其他例子:
客户订单,客户信息,客户历史,客户状态(实时,丢失,死亡......)
订单明显不同于客户数据,因此它应位于单独的服务中。订单通常还具有全球唯一的订单ID。所以有资源/orders/{orderId}
。按客户ID检索订单也是可能的:
/orders;customer={customerId}
读取的内容为我提供了由给定客户ID识别客户的订单列表。
这些过滤类似列表的休息资源的参数称为matrix parameters。您还可以使用查询参数:/orders?customer={customerId}
这也很常见,但矩阵参数的优势在于它明显属于URL的特定部分。请考虑以下事项:
/orders;customer=1234/notifications
这将返回属于ID为1234的客户订单的通知列表。
使用查询参数,它看起来像这样:
/orders/notifications?customer=1234
网址中不清楚订单是否已过滤,而不是通知。
缺点是对矩阵参数的框架支持是变化的。有些人支持他们,有些则不支持。
我最喜欢矩阵参数,但查询参数也可以。
回到你的清单:
客户订单,客户信息,客户历史,客户状态(实时,丢失,死亡......)
客户信息和客户状态很可能属于同一服务(客户核心数据等)甚至是同一资源。客户历史也可以去那里。只要没有理由单独考虑它,我会把它放在那里。也许客户历史是一个如此复杂的领域(当然可以),它值得一个单独的服务:/customer-history/{id}
或者只是/customer/{id}
。
不同的服务使用相同的路径提供有关一个客户的不同信息是没有问题的。它们是不同的服务,它们具有不同的端点,因此不会发生任何冲突。理想情况下,您甚至可以使用指向相应服务的DNS别名:
https://customer-core-data.service.lan/customers/1234
https://customer-history.service.lan/customers/1234
答案 1 :(得分:0)
我不确定我是否真的理解你的问题。但是,让我展示一下如何检查服务器中是否存在某个资源。
考虑服务器提供定位某个资源的URL(在这种情况下,URL定位标识为1
的客户):http://example.org/api/customers/1
。
当客户端对此URL执行GET
请求时,客户端可能会遇到以下结果(可能还有其他情况,例如身份验证/授权问题,但让我们保持简单):< / p>
1
的客户,则客户端应接收状态代码为200
的响应和资源的表示(例如,代表客户的JSON或XML) )在响应有效载荷中。1
的客户不存在,客户应该收到状态代码为404
的回复。要检查资源是否存在,客户端不需要资源表示(代表客户的JSON或XML)。这里的相关内容是状态代码:资源存在时为200
,资源不存在时为404
。除GET
个请求外,定位客户(http://example.org/api/customers/1
)的URL也可以处理HEAD
个请求。 HEAD
方法与GET
方法相同,但服务器不会在HEAD
个请求中发送资源表示。因此,检查资源是否存在是有用的。
查看有关HEAD
方法的更多详细信息:
HEAD
方法与GET
相同,只是服务器不能 在响应中发送消息体(即,响应终止于 标题部分的结尾)。服务器应该发送相同的内容 响应HEAD
请求的标头字段,如果它将发送 请求是GET
,除了可以省略有效负载头字段。该方法可用于获得 关于所选表示的元数据而不转移 表示数据,通常用于测试超文本链接 有效性,可访问性和最近的修改。 [...]
如果资源和资源代表之间的差异不明确,请检查此answer。
答案 2 :(得分:0)
我想在已经很好的答案中添加一件事:如果你正确地做REST,URLS设计并不重要。
REST的一个重要原则是网址被发现。已经拥有客户信息并且想要找出“先前已知”信息的客户应该能够在主要客户资源上发现该URL。如果它从那里链接到“以前已知”的信息,那么url是否在不同的域,路径甚至协议上都无关紧要。
因此,如果你的应用程序自然更有意义,如果“previousKnown”在一个单独的基本路径上,那么也许你应该去那。