[英]Springboot Rest(ful) Api and lookup values
我想用 Spring Boot 和 Spring Data JPA 编写一些 Rest(ful) 应用程序。
假设出于业务原因,我有一个包含下表的数据库:
customer(id number, first_name text, last_name text, type text);
customer_type(type text, description text);
在哪里:
id
由数据库在插入时生成customer_type
表中的type
列是customer
表中type
列的外键,从微服务的角度来看它是不可变的,只是一个查找表。假设我想为客户的 CRUD 操作创建 API,但希望在阅读时尽量减少 api 调用,我想我需要以下操作:
身体应该如何构造? 对于 GET 操作,响应应该是
{
"id":123,
"firstName":"John",
"lastName":"Doe",
"customerType":{
"type":"P",
"description":"Premium Customer"
}
}
但是对于 POST,我想我需要避免发送 id 而只发送客户类型,因为描述是不可变的,并且客户只需要描述来在屏幕上可视化信息,但这会导致请求正文与返回的请求正文不同获取操作。
对于 PUT 操作是一样的但也应该发送id
字段吗? 发送时API路径中的id与请求体中的id不一致如何处理?
DELETE 应该不是问题,因为它只是删除customer
表中的行。
谢谢
身体应该如何构造?
让我们先退后一步,让我们快速讨论在遵循 REST 体系结构时您基本上会尝试什么,以及 REST 为什么以及如何安装这些机制。
REST 是一种架构风格,它通过引入间接机制帮助将客户端与服务器解耦,这起初看起来很奇怪,但最终允许您达到所需的解耦级别,允许客户端引入客户端自然会适应的更改。 这种间接机制包括将 URI 附加到链接关系名称、使用基于形式的表示格式来告诉客户端如何创建请求、内容类型协商以返回其他人支持和理解的表示等。 如果您不需要这样的属性,即客户端和服务器始终 go 在更改方面手拉手并根据预定义消息进行通信,则 REST 可能不是最好的样式。 如果您有一个由不受您控制的各种客户端联系的服务器,或者有一个客户端必须联系各种服务器,但也不受您的直接控制,那么如果所有各方都遵守这些概念,这就是 REST 真正开始发光的地方。
REST 的前提之一是服务器将向客户传授他们构建请求所需知道的一切。 如果您查看 Web,其中 HTML 基本上无处不在,您可能会看到 HTML 定义了HTML forms ,它基本上允许服务器向客户端解释服务器期望作为输入的资源的哪些属性。 最重要的是,该表单还告诉您客户端使用哪个 HTTP 操作,将请求发送到哪个目标 URI 以及代表 state 的媒体类型。在 HTML 中,这通常隐式给出为application/x-www-form-urlencoded
将属性链接在一起,如下所示:
firstName=Roman&lastName=Vottner&role=Dev
等等。 这本质上就是 HATEOAS 或hypertext as the engine of application state
全部内容。 您使用交换的媒体类型的内置控件来允许您的客户端推进其任务,而不必查阅外部文档来查找某些服务的“API”。 即一个表单可以 state 输入只允许数值,表单的子部分表示客户端可以相应地呈现给用户的日期/时间选择器小部件,或者元素表示 slider 具有给定的可接受范围价值观之类的。
您必须发送到服务器的实际表示格式如何取决于指示的媒体类型。 即HAL forms默认使用application/json
,还指定需要支持application/x-www-form-urlencoded
。 其他媒体类型已在客户端和服务器之间明确协商。 Ion指出application/json
或application/ion+json
必须通过Content-Type
请求 header 进行协商。
在普通的application/json
中,上面的 url 编码有效负载可以简单地表示为:
{
"firstName": "Roman",
"lastName": "Vottner",
"role": "Dev"
}
这没关系,因为服务器基本上指示您以该格式发送此数据。
还有更多可用的媒体类型,无论它们是否满足您的需要,都值得仔细研究。 即Hydra通过将关联数据连接到 REST 及其称为操作的可供性,并允许通过 LD 类描述资源及其属性,对此事采取了一些不同的看法。 因此,某个资源的可供性的存在告诉你你可以用那个资源做什么,比如更新它的 state,因此还有它属于哪个 class 以及它有哪些属性。
这只是应该说明协商的媒体类型如何最终决定实际表示需要如何看起来必须发送到服务器。
至于是否在有效负载中放入资源标识符,这取决于它。 通常资源由 URI/IRI 标识,作为一个整体,这是资源的标识符。 在您的应用程序中,虽然您将通过它们的 ID 引用相关的域对象,但这些 ID 不一定需要并且可能也不应该是 IRI 本身的一部分。 即让我们假设我们检索代表订单的资源。 该订单包含用户姓名和地址,订购的各种物品,包括一些描述这些物品的元数据和其他物品。 在这种情况下,添加您在应用程序中使用的 orderId 通常是有意义的,即使 URI 可能已经包含该信息。 该 API 的用户通常对这些 URI 不感兴趣,而是对实际内容感兴趣,如果这些 URI 隐藏在自动化流程或用户界面后面,他们也可能永远看不到这些 URI。 如果用户现在想打印出该订单,他/她拥有稍后通过电话提出投诉所需的所有信息,即在其他情况下,即如果您将资源设计为通用剪贴板,例如复制和粘贴位置,ID没有任何意义,除非您授予用户直接明确引用其中一个状态。
ID 不应该是 URI 本身的一部分的原因是,如果实际资源不改变,URI 不应该改变。 也就是说,我们有一位客户在几年前经历了一次合并。 他们过去常常通过自己的 URI 公开所有产品,这些 URI 将 productId 作为 URI 的一部分公开。 在合并期间,他们试图结合各种不同的数据模型以减少他们必须运行的系统数量,同时为他们的每个客户提供与以前相同的数据,因为基础产品没有改变。 当他们试图保持“向后”兼容以支持其客户的遗留系统时,他们很快注意到将这些产品 ID 作为 URI 的一部分公开给他们带来了一些麻烦。 如果他们早些时候使用了一个映射表,即暴露的 UUID 到内部 productId(再次引入间接),他们可以减少他们的整个数据 model,从而减少复杂性,同时能够改变从内部 prodcutId 到 UUID 的映射飞行,同时允许他们的客户查找产品信息。
长话短说,希望可以看出表示的结构取决于交换的媒体类型。 有许多不同的 媒体类型可用。 使用允许您向客户端描述资源的资源,例如 HAL/HAL forms、Ion、Hydra……关于 URI,不要过度设计 URI。 它们作为一个整体只是指向资源的指针,客户通常对内容感兴趣,而不是 URI。因此,使用链接关系名称等间接功能。 内容类型协商等有助于消除客户端与服务的直接耦合,而是更多地依赖于交换的文档类型。 这里的媒体类型基本上成为消息的契约。 通过在客户端和服务器端的映射,各种表示形式的资源可以“转换”为 object,您可以在您的应用程序中使用它。
当您用spring-boot和spring-data-jpa标记您的问题时,您可能想查看spring-hateoas 。 它支持开箱即用的 HAL,HAL forms 可以通过 affordances 使用,但需要为其显式启用媒体类型,否则您可能会错过响应中的表单模板。 似乎通过实现 Spring HATEOAS SPI 的hydra-java添加了spring-hateoas
中的 Hydra 支持。 虽然Amazon为各种编程语言(包括 Java)提供了 Ion 的实现,但它通常还不支持 Spring HATEOAS 或 Spring。 这里可能需要自定义 SPI 实现。
对于 PUT 操作,您需要发送要更新的实体的 ID。
如果您想生成与在 GET 中获得的响应相同的响应,则需要相应地编写 DTO 和 map 详细信息。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.