Spring for GraphQL
如果你想构建 GraphQL 应用程序,可以利用 Spring Boot 对 Spring for GraphQL 的自动配置功能。Spring for GraphQL 项目基于 GraphQL Java 实现。你至少需要 spring-boot-starter-graphql
这个启动器。由于 GraphQL 是与传输层无关的,你还需要在应用程序中添加一个或多个额外的启动器,以便通过网络暴露你的 GraphQL API:
启动器 | 传输方式 | 实现方式 |
---|---|---|
spring-boot-starter-web | HTTP | Spring MVC |
spring-boot-starter-websocket | WebSocket | 用于 Servlet 应用程序的 WebSocket |
spring-boot-starter-webflux | HTTP, WebSocket | Spring WebFlux |
spring-boot-starter-rsocket | TCP, WebSocket | 基于 Reactor Netty 的 Spring WebFlux |
GraphQL 模式
一个 Spring GraphQL 应用在启动时需要定义模式。默认情况下,你可以在 src/main/resources/graphql/**
目录下编写 ".graphqls" 或 ".gqls" 模式文件,Spring Boot 会自动识别它们。你可以通过 spring.graphql.schema.locations
自定义模式文件的位置,并通过 spring.graphql.schema.file-extensions
自定义文件扩展名。
如果你希望 Spring Boot 在所有的应用模块和依赖中检测该位置的 schema 文件,你可以将 spring.graphql.schema.locations
设置为 "classpath*:graphql/**/"
(注意 classpath*:
前缀)。
在接下来的部分中,我们将考虑这个示例 GraphQL 模式,它定义了两个类型和两个查询:
type Query {
greeting(name: String! = "Spring"): String!
project(slug: ID!): Project
}
""" A Project in the Spring portfolio """
type Project {
""" Unique string id used in URLs """
slug: ID!
""" Project name """
name: String!
""" URL of the git repository """
repositoryUrl: String!
""" Current support status """
status: ProjectStatus!
}
enum ProjectStatus {
""" Actively supported by the Spring team """
ACTIVE
""" Supported by the community """
COMMUNITY
""" Prototype, not officially supported yet """
INCUBATING
""" Project being retired, in maintenance mode """
ATTIC
""" End-Of-Lifed """
EOL
}
默认情况下,字段内省 将在模式上被允许,因为它是诸如 GraphiQL 等工具所必需的。如果你不希望暴露模式的相关信息,可以通过将 spring.graphql.schema.introspection.enabled
设置为 false
来禁用内省功能。
GraphQL 运行时装配
GraphQL Java 的 RuntimeWiring.Builder 可用于注册自定义标量类型、指令、类型解析器、DataFetcher 等。你可以在 Spring 配置中声明 RuntimeWiringConfigurer bean,以获取对 RuntimeWiring.Builder 的访问权限。Spring Boot 会自动检测这些 bean 并将它们添加到 GraphQlSource builder 中。
然而,通常情况下,应用程序不会直接实现 DataFetcher,而是会创建带注解的控制器。Spring Boot 会自动检测带有注解处理方法的 @Controller 类,并将它们注册为 DataFetcher
。以下是一个使用 @Controller 类实现的问候查询示例:
- Java
- Kotlin
import org.springframework.graphql.data.method.annotation.Argument;
import org.springframework.graphql.data.method.annotation.QueryMapping;
import org.springframework.stereotype.Controller;
@Controller
public class GreetingController {
@QueryMapping
public String greeting(@Argument String name) {
return "Hello, " + name + "!";
}
}
import org.springframework.graphql.data.method.annotation.Argument
import org.springframework.graphql.data.method.annotation.QueryMapping
import org.springframework.stereotype.Controller
@Controller
class GreetingController {
@QueryMapping
fun greeting(@Argument name: String): String {
return "Hello, $name!"
}
}
Querydsl 和 QueryByExample 仓库支持
Spring Data 提供了对 Querydsl 和 QueryByExample 仓库的支持。Spring GraphQL 可以将 Querydsl 和 QueryByExample 仓库配置为 DataFetcher。
使用 @GraphQlRepository 注解的 Spring Data 仓库,并扩展以下之一:
会被 Spring Boot 检测到,并被视为 DataFetcher 的候选对象,用于匹配顶级查询。
传输方式
HTTP 和 WebSocket
GraphQL 的 HTTP 端点默认位于 HTTP POST /graphql
。它还支持通过 Server Sent Events 使用 "text/event-stream"
媒体类型,但仅适用于订阅。可以通过 spring.graphql.path
自定义路径。
GraphQL WebSocket 端点默认是关闭的。要启用它:
-
对于 Servlet 应用程序,需要添加 WebSocket 启动器
spring-boot-starter-websocket
-
对于 WebFlux 应用程序,无需额外依赖
-
对于两者,必须设置
spring.graphql.websocket.path
应用程序属性
Spring GraphQL 提供了一个 Web Interception 模型。这对于从 HTTP 请求头中检索信息并将其设置在 GraphQL 上下文中,或者从同一上下文中获取信息并将其写入响应头非常有用。通过 Spring Boot,你可以声明一个 WebGraphQlInterceptor bean,以便将其注册到 Web 传输层。
Spring MVC 和 Spring WebFlux 支持 CORS(跨域资源共享)请求。CORS 是从不同域访问的 GraphQL 应用程序的 Web 配置中的关键部分。
Spring Boot 在 spring.graphql.cors.*
命名空间下支持许多配置属性;以下是一个简短的配置示例:
- Properties
- YAML
spring.graphql.cors.allowed-origins=https://example.org
spring.graphql.cors.allowed-methods=GET,POST
spring.graphql.cors.max-age=1800s
spring:
graphql:
cors:
allowed-origins: "https://example.org"
allowed-methods: GET,POST
max-age: 1800s
RSocket
RSocket 也被支持作为一种传输方式,可以在 WebSocket 或 TCP 之上运行。一旦 RSocket 服务器配置完成,我们可以使用 spring.graphql.rsocket.mapping
在特定路由上配置 GraphQL 处理器。例如,将该映射配置为 "graphql"
意味着我们可以在使用 RSocketGraphQlClient 发送请求时将其作为路由。
Spring Boot 会自动配置一个 RSocketGraphQlClient.Builder<?>
bean,你可以将其注入到你的组件中:
- Java
- Kotlin
@Component
public class RSocketGraphQlClientExample {
private final RSocketGraphQlClient graphQlClient;
public RSocketGraphQlClientExample(RSocketGraphQlClient.Builder<?> builder) {
this.graphQlClient = builder.tcp("example.spring.io", 8181).route("graphql").build();
}
@Component
class RSocketGraphQlClientExample(private val builder: RSocketGraphQlClient.Builder<*>) {
然后发送一个请求:include-code::RSocketGraphQlClientExample[tag=request]
异常处理
Spring GraphQL 允许应用程序注册一个或多个 Spring DataFetcherExceptionResolver 组件,这些组件会被依次调用。异常必须被解析为一系列 GraphQLError 对象,详见 Spring GraphQL 异常处理文档。Spring Boot 会自动检测 DataFetcherExceptionResolver Bean,并将它们注册到 GraphQlSource.Builder 中。
GraphiQL 和 Schema 打印机
Spring GraphQL 提供了基础设施,帮助开发者在消费或开发 GraphQL API 时更加高效。
Spring GraphQL 附带了一个默认的 GraphiQL 页面,该页面默认暴露在 "/graphiql"
路径下。此页面默认是禁用的,可以通过 spring.graphql.graphiql.enabled
属性来启用。许多暴露此类页面的应用程序可能更倾向于使用自定义构建。默认实现在开发过程中非常有用,这就是为什么在开发过程中它会通过 spring-boot-devtools 自动暴露。
你还可以选择在 spring.graphql.schema.printer.enabled
属性启用时,以文本格式在 /graphql/schema
路径下暴露 GraphQL 模式。