什么是GraphQL
GraphQL 是一种用于 API 的查询语言,它提供了比传统 RESTful API 更高效、强大和灵活的方式来获取数据。
定义:GraphQL 是一种声明式的查询语言,允许客户端精确地指定他们需要的数据,而不是返回固定格式的数据。由 Facebook 开发并在 2015 年开源。
工作原理:客户端发送一个 GraphQL 查询到单一的端点,然后后端根据查询返回所需的数据。
主要优势
精准数据获取:客户端可以请求所需的确切数据,减少不必要的数据传输,提高效率。
单一入口点:所有的请求都发送到同一个 URL,使得 API 更加简洁。
版本控制简化:由于客户端可以请求特定的数据字段,API 的更改通常不会影响现有的客户端。
类型安全:GraphQL 提供静态类型系统,有助于捕获错误并增强开发体验。
实时数据订阅:除了查询数据外,GraphQL 还支持实时数据流(使用 subscriptions)。
丰富的工具生态:拥有大量的开发者工具,如 GraphQL Playground 和 Apollo Client,方便开发和调试。
可组合性:GraphQL 数据可以很容易地从多个来源组合而成,支持微服务架构下的数据聚合。
环境准备
我用的JDK版本为21,为了支持record关键字和SpringBoot 3.x,请使用JDK17以上的版本
这里只用到三个jar包,分别是springboot,GQL的starter,lombok
SpringBoot的版本号是3.3.0
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.3.0</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-graphql</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.30</version>
<optional>true</optional>
</dependency>
</dependencies>
编写实体类与GQL Schema
在Java方面,我们事先准备三个实体类,分别是User, UserDetails, Contact
分别代表用户;用户详细信息;用户联系方式
@Builder
public record User(Long id, UserDetails userDetails, List<Contact> contact) {
}
@Builder
public record UserDetails(Long id, String userName, String password, Integer age) {
}
@Builder
public record Contact(Long id,String address, String phone, String email) {
}
在GraphQL方面,我们需要创建一个.graphqls文件,再定义三个Schema,作为实体类的对应。
GraphQL支持基本类型,以及自定义类型,它自带支持的类型如下:
- String: 代表文本字符串。
- Int: 代表整数。
- Float: 代表浮点数。
- Boolean: 代表布尔值,可以是 true 或 false。
- ID: 代表唯一标识符,通常用于数据库记录的主键。
- List:类型后面加方括号 [] 表示该类型可以是数组或列表形式。
- NonNull: 在类型后面加感叹号 ! 表示该类型不能为空。
- Custom Types: 用户自定义的类型,可以用来描述更复杂的对象结构。
除此之外,通过自定义Starter,也可以做到GQL支持文件类型,但是那样做会比较复杂,通常可以通过把文件转化为bytes来传输,或是直接用RestAPI
以下是根据Record编写的Schema
type User{
id: Float
userDetails: UserDetails
contact: [Contact]
}
type UserDetails{
id: Float
userName: String
password: String
age: Int
}
type Contact{
id: Float
phone: String
address: String
email: String
}
此处建议在IDEA中安装gql插件,可以有高亮提示和跳转
编写接口与gql查询
在Java方面,可以先定义出Controller以及对应的Request和Response(当然也可以直接用之前的实体类作为输入与输出,但是对于稍微复杂一些的业务,都需要封装)
Controller
@Controller
public class UserController {
@QueryMapping
public final GetUserResponse getUserById(@Argument final GetUserInput request) {
Contact contact1 = Contact.builder().id(1L).phone("123456789").address("address1").email("email1").build();
Contact contact2 = Contact.builder().id(2L).phone("987654321").address("address2").email("email2").build();
User user=User.builder()
.id(request.userId())
.userDetails(UserDetails.builder().id(request.userId()).userName("username").age(11).build())
.contact(List.of(contact1,contact2))
.build();
return GetUserResponse.builder()
.user(user)
.timestamp(Timestamp.valueOf(LocalDateTime.now()).toString())
.build();
}
}
Request
public record GetUserInput(SessionInput sessionInput, Long userId) {
}
public record SessionInput(
String requestId,
String token
) {
}
Response
@Builder
public record GetUserResponse(User user, String timestamp) {
}
接下来在GraphQL中我们同样需要为request, response编写schema,并写出query接口
type Query {
getUserById(request: GetUserInput): GetUserResponse
}
input GetUserInput{
sessionInput: SessionInput
userId: Float
}
input SessionInput{
requestId: String
token: String
}
type GetUserResponse{
user: User
timeStamp: String
}
需要注意的是,这些GraphQL语句都写在之前的.graphqls文件中
Postman调用GQL接口
接下来, 写好启动类,直接启动
在postman中,输入GQL查询语句,把id:1234作为参数传入(这里为了模拟真实场景,加入了参数token)
需要注意请求方式为POST,在GQL中可以自由定义需要查询的字段,比如这里我就没有查询userDetails和contact的id。
GraphQL语句:
query {
getUserById(request: {
sessionInput: {
requestId: "23c81c56-c633-4ac3-9620-b45bf2f78233",
token: "token"
},
userId: 1234,
}) {
user {
id
userDetails {
userName
password
age
}
contact{
address
phone
email
}
}
}
}
请求参数
查询结果
一个GraphQL查询接口就结束了。它还支持Mutation(增删改)操作,不过需要和ORM配合,由于篇幅关系不做介绍。