一、什么是GraphQL
是一种用于查询数据的查询语言,其特点是支持在一次查询中获取多项数据,并允许多种数据组合。GraphQL 的基本原理是使用类型系统来定义数据的结构,并允许客户端使用查询语言来指定想要获取的数据。GraphQL 服务器根据查询语言来解析查询,并返回一个与查询语言结构相同的结果。
只通过一个暴露的端口即可访问后台所有的gql接口,一般都是:http://ip:port/graphql
说人话:可以通过自定义的查询语句筛选出想要的目标数据
举例:使用gql查询一个接口 (前提是已经定义好接口和graphql schema)
query test01 {
getData{
name
age
salary
birthday
}
}
响应结果:
{
"data": {
"getData": {
"name": "张三",
"age": 18,
"salary": 3000,
"birthday": "2023-12-21T09:27:16.153"
}
}
}
问题来了:假如我只想要name就行了,其他属性我暂不需要,这时候gql的特性就需要展示一下了!只需要把你想要的name属性写出来即可,左边为gql, 右边为执行结果

看到这里后,恭喜你已经掌握graphql的精髓了!
二、在SpringBoot中使用GraphQL
1. 核心依赖准备
<!--Spring Boot 2.7+的版本支持graphql-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--graphql-->
<dependency>
<groupId>org.springframework.graphql</groupId>
<artifactId>spring-graphql</artifactId>
</dependency>
<!--这是一个可视化的graphql接口查询面板,很方便-->
<dependency>
<groupId>com.graphql-java-kickstart</groupId>
<artifactId>playground-spring-boot-starter</artifactId>
<version>${gql.playground.version}</version>
</dependency>
2. 定义graphql Schema
# 定义接口返回值类型,一般命名风格:入参为input结尾,返回值payload结尾
type UserPayload {
name: String
age: Int,
salary: Int,
birthday: String
}
# 定义查询接口Schema
extend type Query {
getData(ageInput: Int): UserPayload
}
3. 编写接口
官方的gql接口都是xxxResolver, 看着很不顺眼,这里就不展示官网写法了。Spring把它封装成注解的形式,大家可以把它看做Spring中的Controller即可
@Controller
public class TestController {
@QueryMapping
public Object getData(@Argument("ageInput") Integer age) {
return User.builder().name("张三").age(age).salary(3000d).birthday(LocalDateTime.now(ZoneId.systemDefault())).build();
}
}
解释说明:
<1> @QueryMapping
表示这是一个query类型的接口,只适用于查询操作,对应的有一个@MutationMapping, 适用于增删改操作。
<2> getData
需要和schema中定义的接口名称保持一致
<3> @Argument("ageInput")
表示这是一个gql参数,参数名称为ageInput,需要和schema中定义的参数保持一致
4. 访问playground


这样就咱们使用 graphql 完成了一个查询操作啦!
三、生产环境中使用GraphQL
1. 定义父schema
这样在其他文件就可以使用extend关键字来继续使用Query和Mutation了,否则schema是不允许定义多个Query和Mutation的,解耦的效果就达不到了
# 查询接口
type Query {
# eg:
# methodName(param: dataType): ResponseType
}
# 增删改接口
type Mutation {
# eg:
# methodName(param: dataType): ResponseType
}
# 在另外一个文件就可以这样写:查询接口
extend type Query {
getData(ageInput: Int): UserPayload
}
2. 定义全局graphql错误控制器
@Slf4j
@Component
public class GraphqlExceptionHandler extends DataFetcherExceptionResolverAdapter {
@Override
protected GraphQLError resolveToSingleError(@NonNull Throwable throwable, @NonNull DataFetchingEnvironment env) {
if (throwable instanceof FeignException) {
return this.processFeignException(throwable, env);
} else if (throwable instanceof Exception) {
return this.processOtherException(throwable, env);
} else {
return this.processOtherException(throwable, env);
}
}
private GraphQLError processOtherException(Throwable throwable, DataFetchingEnvironment env) {
log.error("Service Exception, caused by: {}", throwable.getMessage());
return GraphqlErrorBuilder.newError()
.errorType(ErrorType.INTERNAL_ERROR)
.message(throwable.getMessage())
.path(env.getExecutionStepInfo().getPath())
.location(env.getField().getSourceLocation())
.build();
}
}
这样发生graphql错误时它就会生效, 接口返回一般是这样的:
{
"errors": [
{
"message": "User name has repeated,please change name!",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"createUser"
],
"extensions": {
"classification": "BAD_REQUEST"
}
}
],
"data": {
"createUser": null
}
}
3. 定义schema时的核心思想
以前:之前一个前端渲染一个页面需要请求多个REST接口获取数据,
现在:有了graphql后根据业务定义合适的Schema,就可以一个接口一次性返回所有数据,而且还可以根据前端的需要自定义想要的数据集,减少了后端服务请求的次数
4. gql在微服务架构定位


四、总结
1. 优点
1) **提高性能**
GraphQL 允许客户端一次查询获取多项数据,这可以减少与服务器的通信次数,从而提高性能。 *
2) **更灵活的数据查询**
GraphQL 查询语言允许客户端指定想要获取的数据的具体字段,这使数据查询更加灵活。
3) **简化前端开发**
GraphQL 使前端开发人员能够更轻松地构建数据驱动的应用程序,因为他们只需要关注如何查询数据,而无需关心数据的底层结构。
4) **减少数据传输量**
GraphQL 仅返回客户端请求的数据,这可以减少数据传输量,从而节省带宽和提高性能。
5) **增强安全性**
GraphQL 允许服务器端对数据访问进行细粒度的控制,这可以增强应用程序的安全性。
6) **更好的开发人员体验**
GraphQL 提供了统一的数据查询接口,这可以简化开发人员的工作,并提高开发效率。
2. 缺点
1) **学习曲线较陡**
GraphQL 的查询语言和类型系统都需要一定的学习时间,这可能会增加开发人员的入门难度。
2) **需要服务器端支持**
GraphQL 需要前后端同时支持,这可能会增加开发工作量。
3) **可能增加服务器端的负载**
如果 GraphQL 查询过于复杂或数据量过大,可能会增加服务器端的负载。
4) **工具支持有限**
与其他流行的数据查询语言相比,GraphQL 的工具支持还相对有限。 此外,GraphQL 并不是适用于所有场景。如果应用程序的数据模型简单,或者数据查询需求相对固定,那么使用 GraphQL 可能并不是最好的选择。
3. 个人认为优秀的地方
1)支持接口定义
和Java一样支持Interface的定义,但是注意接口入参是复杂对象类型时,必须使用input关键字定义
# 查询接口
extend type Query {
getData(ageInput: AgeInput): UserPayload
}
input AgeInput {
age: Int
}
type UserPayload implements IBaseEntity{
name: String
age: Int,
salary: Int,
birthday: String
creatorId: ID
createTime: String
modifyTime: String
}
2)Spring的支持, 而且支持多种语法糖
可以像定义REST Controller一样定义接口
@Controller
public class TestController {
@QueryMapping
public Object getData(@Argument("ageInput") Integer age) {
return User.builder().name("张三").age(age).salary(3000d).birthday(LocalDateTime.now(ZoneId.systemDefault())).build();
}
}
详见:使用 Spring Boot 创建 GraphQL API - spring 中文网
官网: GraphQL | A query language for your API
3)知名大平台都在使用
Netflix
GitHub
Shopify
PayPal
4. 个人认为坑爹的地方
1)无法实现递归查询
当查询的结果是一个嵌套的结果时,比如树结构,gql查询无法使用递归,只能通过fragment关键字简化查询语句。还有一种解决办法就是后端先返回树结构的嵌套深度,前台再构造gql语句来进行查询,这样会额外增加一次请求而且有一定的开发工作量
2)增删改操作无法聚合
查询操作可以通过gql进行聚合,但是增删改只能一次请求一个操作和传统REST没啥区别
3)数据类型不完整
官方仅有Int, String, ID等属性类型,没有Long, Date等类型,有一些三方库提供额外的其他类型
4)文件操作复杂
使用gql进行文件上传下载很麻烦,而且官网没有详细说明
5) 需要重复定义实体
比如复杂对象类型作为入参时,需要定义Java对象, 同时也需要定义一个graphql schema obj
本文介绍了GraphQL的基本原理,展示了如何在SpringBoot中配置和使用GraphQL,包括核心依赖、Schema定义、接口编写以及如何访问Playground。在生产环境中,文章讨论了如何定义父Schema、全局错误控制器以及GraphQL在微服务架构中的定位。最后,总结了GraphQL的优点如性能提升、灵活性高,同时也指出其学习曲线陡峭、服务器端负载增加等缺点,以及作者认为的优缺点。
1158

被折叠的 条评论
为什么被折叠?



