跳到主要内容
版本:3.5.10

Spring for GraphQL

QWen Max 中英对照 Spring for GraphQL

如果你想构建 GraphQL 应用程序,可以利用 Spring Boot 为 Spring for GraphQL 提供的自动配置功能。Spring for GraphQL 项目基于 GraphQL Java 构建。你至少需要引入 spring-boot-starter-graphql starter。由于 GraphQL 与传输协议无关,因此你还需要在应用程序中添加一个或多个额外的 starter,以便通过 Web 暴露你的 GraphQL API:

Starter传输协议实现方式
spring-boot-starter-webHTTPSpring MVC
spring-boot-starter-websocketWebSocket用于 Servlet 应用的 WebSocket
spring-boot-starter-webfluxHTTP, WebSocketSpring WebFlux
spring-boot-starter-rsocketTCP, WebSocket基于 Reactor Netty 的 Spring WebFlux

GraphQL Schema

Spring GraphQL 应用程序在启动时需要一个已定义的 schema。默认情况下,你可以在 src/main/resources/graphql/** 目录下编写 ".graphqls" 或 ".gqls" schema 文件,Spring Boot 会自动加载它们。你可以通过 spring.graphql.schema.locations 自定义文件位置,并通过 spring.graphql.schema.file-extensions 自定义文件扩展名。

备注

如果你想让 Spring Boot 在所有应用程序模块和依赖项中检测该位置下的 schema 文件,可以将 spring.graphql.schema.locations 设置为 "classpath*:graphql/**/"(注意前缀 classpath*:)。

在接下来的章节中,我们将考虑以下示例 GraphQL schema,它定义了两个类型和两个查询:

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
}
备注

默认情况下,字段自省(field introspection) 在 schema 上是允许的,因为 GraphiQL 等工具需要它。如果你不希望暴露 schema 的相关信息,可以通过将 spring.graphql.schema.introspection.enabled 设置为 false 来禁用自省功能。

GraphQL RuntimeWiring

GraphQL Java 的 RuntimeWiring.Builder 可用于注册自定义标量类型、指令、类型解析器、DataFetcher 等。你可以在 Spring 配置中声明 RuntimeWiringConfigurer Bean,以获取对 RuntimeWiring.Builder 的访问权限。Spring Boot 会自动检测这些 Bean,并将它们添加到 GraphQlSource builder 中。

然而,通常情况下,应用程序不会直接实现 DataFetcher,而是会创建 带注解的控制器(annotated controllers)。Spring Boot 会自动检测带有注解处理方法的 @Controller 类,并将这些方法注册为 DataFetcher。以下是我们 greeting 查询的一个使用 @Controller 类的示例实现:

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 + "!";
}

}

Querydsl 和 QueryByExample 仓库支持

Spring Data 提供了对 Querydsl 和 QueryByExample 仓库的支持。Spring GraphQL 可以将 Querydsl 和 QueryByExample 仓库配置为 DataFetcher

使用 @GraphQlRepository 注解的 Spring Data 仓库,并继承以下之一:

会被 Spring Boot 检测到,并被视为匹配的顶层查询的 DataFetcher 候选。

Transports

HTTP 和 WebSocket

GraphQL HTTP 端点默认位于 HTTP POST /graphql。它还仅针对订阅(subscriptions)支持通过 Server Sent Events 的 "text/event-stream" 媒体类型。该路径可以通过 spring.graphql.http.path 进行自定义。

提示

Spring MVC 和 Spring WebFlux 的 HTTP 端点均由一个 RouterFunction Bean 提供,其 @Order 值为 0。如果你定义了自己的 RouterFunction Bean,可能需要添加适当的 @Order 注解,以确保它们被正确排序。

GraphQL WebSocket 端点默认是关闭的。要启用它:

  • 对于 Servlet 应用,添加 WebSocket starter spring-boot-starter-websocket

  • 对于 WebFlux 应用,无需额外依赖

  • 对于两者,都必须设置 spring.graphql.websocket.path 应用属性

Spring GraphQL 提供了一种 Web 拦截(Web Interception) 模型。这对于从 HTTP 请求头中获取信息并将其设置到 GraphQL 上下文中,或者从同一上下文中获取信息并将其写入响应头非常有用。在 Spring Boot 中,你可以声明一个 WebGraphQlInterceptor Bean,以将其注册到 Web 传输层中。

Spring MVCSpring WebFlux 支持 CORS(Cross-Origin Resource Sharing,跨域资源共享)请求。对于通过浏览器从不同域名访问的 GraphQL 应用程序来说,CORS 是 Web 配置中的关键部分。

Spring Boot 在 spring.graphql.cors.* 命名空间下支持许多配置属性;以下是一个简短的配置示例:

spring.graphql.cors.allowed-origins=https://example.org
spring.graphql.cors.allowed-methods=GET,POST
spring.graphql.cors.max-age=1800s

RSocket

RSocket 也支持作为传输层,可基于 WebSocket 或 TCP。一旦 RSocket 服务器配置完成,我们就可以使用 spring.graphql.rsocket.mapping 在特定路由上配置 GraphQL 处理器。例如,将该映射配置为 "graphql",意味着在使用 RSocketGraphQlClient 发送请求时,可以将该值用作路由。

Spring Boot 会自动配置一个 RSocketGraphQlClient.Builder<?> Bean,你可以将其注入到你的组件中:

@Component
public class RSocketGraphQlClientExample {

private final RSocketGraphQlClient graphQlClient;

public RSocketGraphQlClientExample(RSocketGraphQlClient.Builder<?> builder) {
this.graphQlClient = builder.tcp("example.spring.io", 8181).route("graphql").build();
}

然后发送一个请求:include-code::RSocketGraphQlClientExample[tag=request]

异常处理

Spring GraphQL 允许应用程序注册一个或多个 Spring DataFetcherExceptionResolver 组件,这些组件将按顺序被调用。异常必须被解析为一个 GraphQLError 对象列表,详见 Spring GraphQL 异常处理文档。Spring Boot 会自动检测 DataFetcherExceptionResolver Bean 并将其注册到 GraphQlSource.Builder 中。

GraphiQL 与 Schema Printer

Spring GraphQL 提供了基础设施,以帮助开发者在使用或开发 GraphQL API 时更加便捷。

Spring GraphQL 自带一个默认的 GraphiQL 页面,默认暴露在 "/graphiql" 路径下。该页面默认是禁用的,可以通过 spring.graphql.graphiql.enabled 属性启用。许多暴露此类页面的应用程序会更倾向于使用自定义构建。默认实现在开发过程中非常有用,因此在开发期间会通过 spring-boot-devtools 自动暴露该页面。

当启用 spring.graphql.schema.printer.enabled 属性时,你也可以选择在 /graphql/schema 路径以文本格式暴露 GraphQL schema。