使用 Spring Boot 创建 GraphQL API
GraphQL 是啥?
根据其 官方文档,“GraphQL 是一种用于 API 的查询语言,也是一种服务器端运行时,可使用你为数据定义的类型系统来执行查询”。该语言由 Meta 公司开发并开源,目前由众多公司和个人社区共同维护。
GraphQL 包括 2 个主要部分:
- Schema Definition Language(Schema 定义语言) - 使用 GraphQL SDL(Schema 定义语言)指定服务的 GraphQL Schema,有时也称为 GraphQL Schema 语言。
- Query Language(查询语言) - 查询语言由Query、Mutation 和 Subscription 三部分组成
本文稍后会进行介绍。
GraphQL 有很多出色的功能,例如:
- 它实现了声明式数据获取,并提供了一个单一的端点,客户端可以准确地指定所需的信息,不再需要过度获取信息。
- 它提供开箱即用的验证和类型检查功能,你可以在执行前在 GraphQL 强类型系统中验证查询。
- GraphQL 可以使 API 文档与 API 的更改保持同步。这对开发人员非常有益,因为他们无需花费太多时间来编写 API 文档。
- GraphQL 通过在字段级别废除 API,消除了对版本控制的需求。旧字段可以在不影响现有查询的情况下从 Schema 中删除。
也有一些缺点:
- GraphQL 需要客户端和服务器端更多的工具支持。这需要大量的前期付出。对于非常简单的 API 用例来说,这不是一个合适的替代方案。
- GrpahQL 只有一个入口,默认使用 HTTP POST。这就妨碍了客户端 HTTP 缓存的充分使用,并使得实现缓存成为一项相对复杂的任务。
GraphQL Schema
GraphQL 服务必须使用 Schema。GraphQL Schema 定义了如何从服务器请求和返回数据,并由 GraphQL SDL 控制。
让我们通过一个示例 Schema 来了解一些最重要的概念:
# root Query Type
type Query {
fetchBooks: [Book]
}
# Book type
type Book {
id : ID
name : String
author: String
ratings: [Rating]
}
# Rating type
type Rating {
id: ID
rating: Int
comment: String
user: String
}
对象类型:对象类型是 GraphQL 服务特有的,使用 type
关键字定义。它们定义了类型名称和该类型下的字段。对象类型中的每个字段都可以解析为标量类型或其他对象类型,例如,Book
类型有 String
类型的标量字段和 Rating
类型的另一个对象字段。
内置标量类型:raphQL 中有 5 种内置标量类型: Int
、Float
、String
、Boolean
和 ID
。ID
类型解析为字符串,但期望值是唯一的。
类型修饰符:修饰符可通过使用 [...]
等字符用于字段解析的类型,例如,root Query 的类型修饰符为 [Book]
,它表示由不可为 null 的字符串值组成的可为空列表。整个值可以为 null,或者特定的列表元素可以为 null。
操作:GraphQL 服务可支持以下操作:
- Queries:Queries 表示 READ 操作。
- Mutation:Mutation 包括先写入(WRITE)然后读取(READ)的操作。
- Subscription:Subscription 用于连续读取(如通过 WebSocket)。
开始
在本文中,我们使用 Spring Boot GraphQL 构建一个 book catalog(图书目录)服务。该服务支持一个名为 fetchBooks
的查询,用于返回所有时间中排名前 5 的书籍(book)、作者(author)和评分(rating)。
使用 Spring for GraphQL 构建这项服务。它基于 GraphQL Java 构建,支持通过 HTTP 和 WebSocket 处理 GraphQL 请求。GraphQL 规范与任何传输层协议无关。我使用 GraphQL over HTTP 规范构建此 API。
在深入研究代码之前,让我们先花点时间了解一下 Spring GraphQL。
它有 3 个主要组件:Transport、GraphQL Java 引擎和 Data fetcher(数据获取器)。
Transport:GraphQL Java 默认不提供任何传输机制。你可以使用 Spring 框架提供的任何传输机制,例如 Spring MVC、Spring WebFlux 和 WebSocket 等。这些处理器会将所有请求传送到 GraphQL Java 引擎。
GraphQL Java Engine:它支持从头开始引导服务,并支持从 Web 层到数据层的上下文传播。异常也在这一层进行处理。
Data Fetchers:它提供注解 Controller(@Controller
)、Query Domain Specific Language(DSL)和 Repository。
实现服务
1、创建 Spring Boot 项目
你可以使用 Spring Initializer 创建一个空的 Spring Boot 项目,并包含以下依赖:
spring-boot-starter-graphql
:主要的依赖spring-boot-starter-web
:构建传输层(transport )
2、为 books catalog 服务创建 Schema 文件
type Query {
fetchBooks: [Book]
}
type Book {
id : ID
name : String
author: String
ratings: [Rating]
}
type Rating {
id: ID
rating: Int
comment: String
user: String
}
3、创建 data fetcher
Data fetcher 是一个回调函数,它获取的数据包括查询结果。当收到传入的 GraphQL 查询时,库将调用已注册的查询 DataFetcher。每个查询都必须有一个关联的 DataFetcher,例如,在第 2 步中定义的 schema 中,我们 为 “fetchBooks” 查询创建一个 data fetcher。
4、和 RunTimewiring 进行关联
GraphQL Java 使用 RuntimeWiring
builder 来注册 data fetcher、type resolver(类型解析器)等。我们在 Spring 配置中创建 RuntimeWiringConfigurer
Bean,以便访问 RuntimeWiring.Builder
。下面的代码片段展示了用于 “fetchBooks” 查询的 data fetcher,并将其与 RuntimeWiring
builder 进行关联。
@Configuration
public class GraphQLServiceConfiguration {
@Bean
public RuntimeWiringConfigurer runtimeWiringConfigurer(BooksCatalogService bookCatalogService) {
return builder -> {
builder.type(
"Query",
wiring ->
wiring
.dataFetcher("fetchBooks", environment -> bookCatalogService.fetchBooks()));
builder.type(
"Book",
wiring ->
wiring.dataFetcher("ratings", env -> bookCatalogService.fetchRatings(env.getSource())));
};
}
}
在上述代码中,字段 fetchBooks
的 Data Fetcher 通过调用 books catalog 服务的 fetchBooks()
和 fetchRatings()
方法获取所有书籍和评分(rating)。
5、运行和测试
你可以通过运行 BooksCatalogServiceApplication
类的 main
方法,在 IDE 中启动 GraphQL 服务:
你可以使用 Insomnia 客户端测试你的 API。
POST:http://localhost:8080/graphql
也可以通过 http://localhost:8080/graphiql?path=/graphql
在浏览器中使用 GraphiQL 编辑器。
要启用 GraphiQL 编辑器,必须在 application.properties
中设置 spring.graphql.graphiql.enabled=true
。
完整的示例代码托管在 GitHub,你可以 clone 到本地,在IDE 中导入 books-catalog-service
Maven
项目。
参考:https://dev.to/aparoha/how-to-write-graphql-apis-in-spring-boot-a-beginners-guide-2bc3