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-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 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
}
默认情况下,schema 上允许进行字段自省(introspection),因为 GraphiQL 等工具需要它。如果你不想暴露 schema 的信息,可以通过将 spring.graphql.schema.introspection.enabled 设置为 false 来禁用自省。

GraphQL RuntimeWiring

GraphQL Java 的 RuntimeWiring.Builder 可用于注册自定义标量类型、指令、类型解析器、DataFetcher 等。你可以在 Spring 配置中声明 RuntimeWiringConfigurer bean 来获取 RuntimeWiring.Builder。Spring Boot 会检测这些 bean 并将其添加到 GraphQlSource 构建器中。

通常,应用不会直接实现 DataFetcher,而是创建注解控制器。Spring Boot 会自动检测带有注解处理方法的 @Controller 类,并将它们注册为 DataFetcher。以下是使用 @Controller 类实现的 greeting 查询示例

  • 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 Repository 支持

Spring Data 支持 Querydsl 和 QueryByExample Repository。Spring GraphQL 可以将 Querydsl 和 QueryByExample Repository 配置为 DataFetcher

@GraphQlRepository 注解并继承以下接口之一的 Spring Data Repository

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

传输方式

HTTP 和 WebSocket

GraphQL HTTP 端点默认为 HTTP POST /graphql。它也支持通过 Server Sent Events(SSE)使用 "text/event-stream" 媒体类型,但仅限于订阅。路径可以通过 spring.graphql.path 定制。

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

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

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

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

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

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

Spring MVCSpring 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 handler。例如,将该映射配置为 "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 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。