Spring Boot + GraphQL 才是 API 的未来!
Posted Java技术栈
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring Boot + GraphQL 才是 API 的未来!相关的知识,希望对你有一定的参考价值。
来源:www.toutiao.com/i6929867921162273292
前言
在浅尝GraphQL一文描述了GraphQL及基本使用,本文提供一个基本示例,描述如何基于spring boot的web项目快速应用。
graphql-java的官方文档:Getting started with GraphQL Java and Spring Boot,提供了相关依赖用以快速配置,但是个人真心不建议使用这个库及相关配置方式来搭建脚手架,在实际开发中,业务比较复杂的时候,会导致需要配置的业务代码比较多也比较繁琐,相对下面这种方式,代码复杂性比较高。
本文提供一种更灵活快捷的方式,在spring boot项目中快速应用开发。使用的依赖也和上面官方提供的都不一样,请注意区分。
快速开始
创建spring boot工程
通过Spring Initializr快速搭建,我选的jdk版本及spring boot版本,如下所示,其它版本未做兼容性测试。
点击下方的Generate按钮:
打开工程结构如下,我将application.properties删除了替换成applicaiton.yml,因为我个人比较喜欢yaml的配置方式:
引入相关依赖
pom.xml配置如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.6</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.xuxd</groupId>
<artifactId>graphql.demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>graphql.demo</name>
<description>GraphQL Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<lombok.version>1.18.20</lombok.version>
<graphql-java-tools.version>11.0.1</graphql-java-tools.version>
<gson.version>2.8.7</gson.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.graphql-java-kickstart</groupId>
<artifactId>graphql-java-tools</artifactId>
<version>${graphql-java-tools.version}</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>${gson.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
初始化GraphQL实例
我们将创建一个GraphQL实例并将其注册到spring容器中,代码如下:
创建一个GraphQLProvider类:
@Component
public class GraphQLProvider {
private GraphQL graphQL;
@Autowired
private IItemService itemService;
@Bean
public GraphQL graphQL() {
return graphQL;
}
@PostConstruct
public void init() throws IOException {
GraphQLSchema graphQLSchema = SchemaParser.newParser()
.file("graphql/base.graphqls")
.resolvers(new Query(), new Mutation())
.file("graphql/item.graphqls")
.resolvers(new ItemResolver(itemService))
// .file("book.graphqls")
// .resolvers(new BookResolver()) //其它定义照上面的示例,继续增加
.build().makeExecutableSchema();
this.graphQL = graphQL.newGraphQL(graphQLSchema).build();
}
}
关于*.graphqls
或者对应的Resolver如ItemResolver,可以参看浅尝GraphQL相关描述,这里只是作了微调整,相关代码如下:
base.grqphqls
schema {
# 查询
query: Query
# 更新
mutation: Mutation
}
type Query {
version: String
}
type Mutation {
version: String
}
item.graphqls
# 定义一个查询类型
extend type Query {
queryItemList: ItemList # 定义查询项目列表
queryById(id: ID): Item
}
extend type Mutation {
updateName(param: Param): Item
}
# 定义项目字段
type Item {
id: ID!
code: String!
name: String!
}
type ItemList {
itemList: [Item!]! #获取项目列表
total: Int! # 获取项目总数
}
input Param {
id: ID!
name: String!
}
ItemResolver
public class ItemResolver implements GraphQLQueryResolver, GraphQLMutationResolver {
private IItemService itemService;
public ItemResolver(IItemService itemService) {
this.itemService = itemService;
}
// 对应item.graphqls里的queryItemList
public ItemList queryItemList() {
return itemService.queryItemList();
}
public Item queryById(Long id) {
return itemService.queryById(id);
}
public Item updateName(Param param) {
return itemService.updateName(param);
}
}
相关业务代码比较多,就不一一贴了。
提供API
我们需要暴露一个接口来接收请求,并作相关处理,也只需提供一个接口即可。因此我们创建一个Controller:GraphqlController.
@RestController
@RequestMapping("/graphql")
@Log
public class GraphqlController {
@Autowired
private GraphQL graphQL;
@PostMapping
public Object execute(@RequestBody GraphqlRequest request) {
ExecutionInput executionInput = ExecutionInput.newExecutionInput()
.query(request.getQuery())
.variables(request.getVariables())
.build();
Map<String, Object> result = new HashMap<>();
ExecutionResult executionResult = graphQL.execute(executionInput);
List<GraphQLError> errors = executionResult.getErrors();
if (errors != null && !errors.isEmpty()) {
result.put("errors", errors);
return result;
}
return executionResult.getData();
}
}
到这一步,其实基本功能都已配置完成,可以启动项目进行相关测试了。
整个项目的代码结构如下,我尽量用了一个比较常规的web项目结构(controller,service,dao等):
测试
示例中总共提供了3个接口,两个查询一个更新,分别进行测试:
ItemList queryItemList();
Item queryById(Long id);
Item updateName(Param param);
查询所有项目列表(只获取每个项目的编码和名称,以及列表总数):
根据ID查询,获取项目的id和名称
更新指定ID的项目名称
我们项目Id为1编码为test的项目修改为“java项目”
再查询一下,可以看到结果更新了:
结束语
这样整个项目的GraphQL相关的基本配置已经完成,可以进行业务开发了。
近期热文推荐:
1.1,000+ 道 Java面试题及答案整理(2021最新版)
2.别在再满屏的 if/ else 了,试试策略模式,真香!!
3.卧槽!Java 中的 xx ≠ null 是什么新语法?
4.Spring Boot 2.5 重磅发布,黑暗模式太炸了!
觉得不错,别忘了随手点赞+转发哦!
如何使用 graphql-spring-boot 向 GraphQL Java 添加检测?
【中文标题】如何使用 graphql-spring-boot 向 GraphQL Java 添加检测?【英文标题】:How to add instrumentation to GraphQL Java with graphql-spring-boot? 【发布时间】:2020-05-16 04:49:40 【问题描述】:有人知道在使用 graphql-spring-boot
(https://github.com/graphql-java-kickstart/graphql-spring-boot) 时如何将检测添加到 GraphQL 执行吗?我知道使用普通的 graphql-java 是如何实现的:https://www.graphql-java.com/documentation/v13/instrumentation/
但是,当使用 graphql-spring-boot 并控制执行时,我不知道该怎么做。由于缺乏文档,我只是这样尝试:
@Service
public class GraphQLInstrumentationProvider implements InstrumentationProvider
@Override
public Instrumentation getInstrumentation()
return SimpleInstrumentation.INSTANCE;
但我的 InstrumentationProvider bean 上的 getInstrumentation 方法(如预期的那样)从未被调用过。任何帮助表示赞赏。
【问题讨论】:
【参考方案1】:有一种更简单的方法可以通过 spring boot 添加检测:
@Configuration
public class InstrumentationConfiguration
@Bean
public Instrumentation someFieldCheckingInstrumentation()
return new FieldValidationInstrumentation(env ->
// ...
);
Spring boot 将收集所有实现 Instrumentation
的 bean(参见 GraphQLWebAutoConfiguration
)。
【讨论】:
【参考方案2】:回答我自己的问题。与此同时,我设法做到了:
final class RequestLoggingInstrumentation extends SimpleInstrumentation
private static final Logger logger = LoggerFactory.getLogger(RequestLoggingInstrumentation.class);
@Override
public InstrumentationContext<ExecutionResult> beginExecution(InstrumentationExecutionParameters parameters)
long startMillis = System.currentTimeMillis();
var executionId = parameters.getExecutionInput().getExecutionId();
if (logger.isInfoEnabled())
logger.info("GraphQL execution started", executionId);
var query = parameters.getQuery();
logger.info("[] query: ", executionId, query);
if (parameters.getVariables() != null && !parameters.getVariables().isEmpty())
logger.info("[] variables: ", executionId, parameters.getVariables());
return new SimpleInstrumentationContext<>()
@Override
public void onCompleted(ExecutionResult executionResult, Throwable t)
if (logger.isInfoEnabled())
long endMillis = System.currentTimeMillis();
if (t != null)
logger.info("GraphQL execution failed: ", executionId, t.getMessage(), t);
else
var resultMap = executionResult.toSpecification();
var resultJSON = ObjectMapper.pojoToJSON(resultMap).replace("\n", "\\n");
logger.info("[] completed in ms", executionId, endMillis - startMillis);
logger.info("[] result: ", executionId, resultJSON);
;
@Service
class InstrumentationService
private final ContextFactory contextFactory;
InstrumentationService(ContextFactory contextFactory)
this.contextFactory = contextFactory;
/**
* Return all instrumentations as a bean.
* The result will be used in class @link com.oembedler.moon.graphql.boot.GraphQLWebAutoConfiguration.
*/
@Bean
List<Instrumentation> instrumentations()
// Note: Due to a bug in GraphQLWebAutoConfiguration, the returned list has to be modifiable (it will be sorted)
return new ArrayList<>(
List.of(new RequestLoggingInstrumentation()));
它帮助我了解了GraphQLWebAutoConfiguration
课程。在那里我发现框架需要一个 List<Instrumentation>
类型的 bean,其中包含将添加到 GraphQL 执行的所有工具。
【讨论】:
以上是关于Spring Boot + GraphQL 才是 API 的未来!的主要内容,如果未能解决你的问题,请参考以下文章
Spring Boot + GraphQL 才是 API 的未来!
如何使用 graphql-spring-boot 向 GraphQL Java 添加检测?
有没有办法使用spring boot starter app graphql-spring-boot-starter公开2个graphql端点?
graphql-spring-boot-starter 只有 websockets 的应用程序