此版本仍在开发中,尚未被视为稳定版本。对于最新的稳定版本,请使用 Spring GraphQL 1.4.1spring-doc.cadn.net.cn

带注释的控制器

Spring for GraphQL 提供了一个基于注释的编程模型,其中@Controller组件使用注解来声明具有灵活方法签名的处理程序方法,以获取特定 GraphQL 字段的数据。 例如:spring-doc.cadn.net.cn

@Controller
public class GreetingController {

		@QueryMapping (1)
		public String hello() { (2)
			return "Hello, world!";
		}

}
1 将此方法绑定到查询,即查询类型下的字段。
2 如果未在注释上声明,则从方法名称确定查询。

Spring for GraphQL 用途RuntimeWiring.Builder将上述处理程序方法注册为graphql.schema.DataFetcher对于名为“hello”的查询。spring-doc.cadn.net.cn

声明

您可以定义@Controllerbean 作为标准 Spring bean 定义。 这@Controllerstereotype 允许自动检测,与 Spring general 保持一致支持检测@Controller@Component类路径上的类和自动注册它们的 bean 定义。它还充当带注释的类的构造型,表明它在 GraphQL 应用程序中作为数据获取组件的角色。spring-doc.cadn.net.cn

AnnotatedControllerConfigurer检测@Controllerbean 并将它们的带注释的处理程序方法注册为DataFetcher通过RuntimeWiring.Builder. 这是一个实现RuntimeWiringConfigurer可以添加到GraphQlSource.Builder. Boot Starter 自动声明AnnotatedControllerConfigurer作为 bean并将所有RuntimeWiringConfigurerbeans 到GraphQlSource.Builder并且使支持 CommenttedDataFetchers,请参阅 Boot 入门文档中的 GraphQL RuntimeWiring 部分。spring-doc.cadn.net.cn

@SchemaMapping

@SchemaMapping注释将处理程序方法映射到 GraphQL 架构中的字段并将其声明为DataFetcher。注释可以指定父类型名称,以及字段名称:spring-doc.cadn.net.cn

@Controller
public class BookController {

	@SchemaMapping(typeName="Book", field="author")
	public Author getAuthor(Book book) {
		// ...
	}
}

@SchemaMapping注释也可以省略这些属性,在这种情况下,字段名称默认为方法名称,而类型名称默认为简单类注入到方法中的源/父对象的名称。例如,下面的默认为键入“Book”和字段“author”:spring-doc.cadn.net.cn

@Controller
public class BookController {

	@SchemaMapping
	public Author author(Book book) {
		// ...
	}
}

@SchemaMapping可以在类级别声明注释,以指定类中所有处理程序方法的默认类型名称。spring-doc.cadn.net.cn

@Controller
@SchemaMapping(typeName="Book")
public class BookController {

	// @SchemaMapping methods for fields of the "Book" type

}

@QueryMapping,@MutationMapping@SubscriptionMapping是元注释,这些本身被注释为@SchemaMapping并将 typeName 预设为Query,MutationSubscription分别。 实际上,这些是快捷方式注释分别用于 Query、Mutation 和 Subscription 类型下的字段。 例如:spring-doc.cadn.net.cn

@Controller
public class BookController {

	@QueryMapping
	public Book bookById(@Argument Long id) {
		// ...
	}

	@MutationMapping
	public Book addBook(@Argument BookInput bookInput) {
		// ...
	}

	@SubscriptionMapping
	public Flux<Book> newPublications() {
		// ...
	}
}

@SchemaMapping处理程序方法具有灵活的签名,可以从一系列method 参数和返回值中进行选择。spring-doc.cadn.net.cn

方法参数

架构映射处理程序方法可以具有以下任何方法参数:spring-doc.cadn.net.cn

方法参数 描述

@Argumentspring-doc.cadn.net.cn

用于访问绑定到更高级别的类型化对象的命名字段参数。spring-doc.cadn.net.cn

@Argument.spring-doc.cadn.net.cn

@Argument Map<String, Object>spring-doc.cadn.net.cn

用于访问原始参数值。spring-doc.cadn.net.cn

@Argument.spring-doc.cadn.net.cn

ArgumentValuespring-doc.cadn.net.cn

用于访问绑定到更高级别的类型化对象的命名字段参数以及带有一个标志,以指示输入参数是省略还是设置为null.spring-doc.cadn.net.cn

ArgumentValue.spring-doc.cadn.net.cn

@Argumentsspring-doc.cadn.net.cn

用于访问绑定到更高级别类型 Object 的所有字段参数。spring-doc.cadn.net.cn

@Arguments.spring-doc.cadn.net.cn

@Arguments Map<String, Object>spring-doc.cadn.net.cn

用于访问参数的原始映射。spring-doc.cadn.net.cn

@ProjectedPayload接口spring-doc.cadn.net.cn

用于通过项目接口访问字段参数。spring-doc.cadn.net.cn

@ProjectedPayload接口.spring-doc.cadn.net.cn

“来源”spring-doc.cadn.net.cn

用于访问字段的源(即父/容器)实例。spring-doc.cadn.net.cn

参见来源spring-doc.cadn.net.cn

SubrangeScrollSubrangespring-doc.cadn.net.cn

用于访问分页参数。spring-doc.cadn.net.cn

参见分滚动Subrange.spring-doc.cadn.net.cn

Sortspring-doc.cadn.net.cn

用于访问排序详细信息。spring-doc.cadn.net.cn

参见分页Sort.spring-doc.cadn.net.cn

DataLoaderspring-doc.cadn.net.cn

要访问DataLoaderDataLoaderRegistry.spring-doc.cadn.net.cn

DataLoader.spring-doc.cadn.net.cn

@ContextValuespring-doc.cadn.net.cn

用于从 mainGraphQLContextDataFetchingEnvironment.spring-doc.cadn.net.cn

@LocalContextValuespring-doc.cadn.net.cn

用于从本地访问属性GraphQLContextDataFetchingEnvironment.spring-doc.cadn.net.cn

GraphQLContextspring-doc.cadn.net.cn

要从DataFetchingEnvironment.spring-doc.cadn.net.cn

java.security.Principalspring-doc.cadn.net.cn

从 Spring Security 上下文(如果可用)获取。spring-doc.cadn.net.cn

@AuthenticationPrincipalspring-doc.cadn.net.cn

用于访问Authentication#getPrincipal()来自 Spring Security 上下文。spring-doc.cadn.net.cn

DataFetchingFieldSelectionSetspring-doc.cadn.net.cn

要通过DataFetchingEnvironment.spring-doc.cadn.net.cn

Locale,Optional<Locale>spring-doc.cadn.net.cn

要访问LocaleDataFetchingEnvironment.spring-doc.cadn.net.cn

DataFetchingEnvironmentspring-doc.cadn.net.cn

用于直接访问基础DataFetchingEnvironment.spring-doc.cadn.net.cn

返回值

架构映射处理程序方法可以返回:spring-doc.cadn.net.cn

在 Java 21+ 上,当AnnotatedControllerConfigurer配置了Executor控制器 具有阻塞方法签名的方法将异步调用。默认情况下,控制器如果方法不返回异步类型(例如Flux,Mono,CompletableFuture,也不是 Kotlin 挂起函数。您可以配置blocking 控制器方法PredicateAnnotatedControllerConfigurer以提供帮助确定哪些方法被视为阻塞。spring-doc.cadn.net.cn

Spring for GraphQL 的 Spring Boot Starters自动配置AnnotatedControllerConfigurer使用Executor对于虚拟线程,当属性spring.threads.virtual.enabled已设置。

接口架构映射

当控制器方法映射到架构接口字段时,默认情况下,映射为替换为多个映射,每个映射用于实现该接口的架构对象类型。这允许对所有子类型使用一个控制器方法。spring-doc.cadn.net.cn

例如,给定:spring-doc.cadn.net.cn

type Query {
	activities: [Activity!]!
}

interface Activity {
	id: ID!
	coordinator: User!
}

type FooActivity implements Activity {
	id: ID!
	coordinator: User!
}

type BarActivity implements Activity {
	id: ID!
	coordinator: User!
}

type User {
	name: String!
}

您可以像这样编写一个控制器:spring-doc.cadn.net.cn

@Controller
public class BookController {

	@QueryMapping
	public List<Activity> activities() {
		// ...
	}

	@SchemaMapping
	public User coordinator(Activity activity) {
		// Called for any Activity subtype
	}

}

如有必要,您可以接管各个子类型的映射:spring-doc.cadn.net.cn

@Controller
public class BookController {

	@QueryMapping
	public List<Activity> activities() {
		// ...
	}

	@SchemaMapping
	public User coordinator(Activity activity) {
		// Called for any Activity subtype except FooActivity
	}

	@SchemaMapping
	public User coordinator(FooActivity activity) {
		// ...
	}

}

@Argument

在 GraphQL Java 中,DataFetchingEnvironment提供对特定字段参数值的映射的访问。这些值可以是简单的标量值(例如 String、Long)、Map之 值,或List的价值观。spring-doc.cadn.net.cn

使用@Argument注释,使参数绑定到目标对象,并且 注入到处理程序方法中。绑定是通过将参数值映射到 primary data 构造函数,或使用 构造函数来创建对象,然后将参数值映射到其属性。这是 递归重复,使用所有嵌套参数值并创建嵌套目标对象 因此。例如:spring-doc.cadn.net.cn

@Controller
public class BookController {

	@QueryMapping
	public Book bookById(@Argument Long id) {
		// ...
	}

	@MutationMapping
	public Book addBook(@Argument BookInput bookInput) {
		// ...
	}
}
如果目标对象没有 setter,并且您无法更改它,则可以使用 属性AnnotatedControllerConfigurer允许通过直接回退绑定 现场访问。

默认情况下,如果方法参数名称可用(需要-parameters编译器 标志与 Java 8+ 或来自编译器的调试信息),它用于查找参数。 如果需要,您可以通过注释自定义名称,例如@Argument("bookInput").spring-doc.cadn.net.cn

@Argument注释没有“必需”标志,也没有选项 指定默认值。这两者都可以在 GraphQL 架构级别指定,并且 由 GraphQL Java 强制执行。

如果绑定失败,则BindException以累积为字段的绑定问题提出 错误,其中field每个错误的参数路径是发生问题的参数路径。spring-doc.cadn.net.cn

您可以使用@Argument使用Map<String, Object>参数,以获取 论点。例如:spring-doc.cadn.net.cn

@Controller
public class BookController {

	@MutationMapping
	public Book addBook(@Argument Map<String, Object> bookInput) {
		// ...
	}
}
在 1.2 之前,@Argument Map<String, Object>如果 注释没有指定名称。在 1.2 之后,@ArgumentMap<String, Object>始终返回原始参数值,与名称 或参数名称中指定的。要访问完整的参数 地图,请使用@Arguments相反。

ArgumentValue

默认情况下,GraphQL 中的输入参数是可为 null 且可选的,这意味着参数 可以设置为null字面意思,或者根本不提供。这种区别对 部分更新,其中基础数据也可能在,设置为null或者根本没有相应地改变。使用时@Argument没有办法做出这样的区分,因为你会得到null或空的Optional在这两种情况下。spring-doc.cadn.net.cn

如果您想不知道是否根本没有提供值,您可以声明ArgumentValuemethod 参数,它是结果值的简单容器, 以及一个标志,以指示是否完全省略了输入参数。你 可以使用这个代替@Argument,在这种情况下,参数名称是从 方法参数名称,或与@Argument以指定参数名称。spring-doc.cadn.net.cn

@Controller
public class BookController {

	@MutationMapping
	public void addBook(ArgumentValue<BookInput> bookInput) {
		if (!bookInput.isOmitted()) {
			BookInput value = bookInput.value();
			// ...
		}
	}
}

ArgumentValue也支持作为对象结构中的字段@Argumentmethod 参数,通过构造函数参数或通过 setter 初始化,包括 作为嵌套在顶层对象下方任何级别的对象的字段。spring-doc.cadn.net.cn

@Arguments

使用@Arguments注释,如果要将完整的参数映射绑定到单个 target 对象,而不是@Argument,它绑定了一个特定的命名参数。spring-doc.cadn.net.cn

例如@Argument BookInput bookInput使用参数“bookInput”的值 初始化BookInput@Arguments使用完整的参数映射,并且在 case,顶级参数绑定到BookInput性能。spring-doc.cadn.net.cn

您可以使用@Arguments使用Map<String, Object>参数,以获取 所有参数值。spring-doc.cadn.net.cn

@ProjectedPayload接口

作为将完整对象与@Argument, 您还可以使用投影接口通过 定义明确、最小的界面。当 Spring Data 位于类路径上时,参数投影由 Spring Data 的接口投影提供。spring-doc.cadn.net.cn

要利用这一点,请创建一个带有@ProjectedPayload并声明 它作为控制器方法参数。如果参数的注释为@Argument, 它适用于DataFetchingEnvironment.getArguments()地图。当声明时没有@Argument,则投影适用于 完整的参数映射。spring-doc.cadn.net.cn

@Controller
public class BookController {

	@QueryMapping
	public Book bookById(BookIdProjection bookId) {
		// ...
	}

	@MutationMapping
	public Book addBook(@Argument BookInputProjection bookInput) {
		// ...
	}
}

@ProjectedPayload
interface BookIdProjection {

	Long getId();
}

@ProjectedPayload
interface BookInputProjection {

	String getName();

	@Value("#{target.author + ' ' + target.name}")
	String getAuthorAndName();
}

在 GraphQL Java 中,DataFetchingEnvironment提供对源(即 parent/container) 实例。要访问它,只需声明一个方法参数 预期目标类型。spring-doc.cadn.net.cn

@Controller
public class BookController {

	@SchemaMapping
	public Author author(Book book) {
		// ...
	}
}

source 方法参数还有助于确定映射的类型名称。 如果 Java 类的简单名称与 GraphQL 类型匹配,则无需 在@SchemaMapping注解。spring-doc.cadn.net.cn

一个@BatchMappinghandler 方法可以批量加载查询的所有作者, 给定源/父书籍对象列表。spring-doc.cadn.net.cn

Subrange

当有CursorStrategySpring 配置中的 bean, 控制器方法支持Subrange<P>参数,其中<P>是一个相对位置 从光标转换而来。对于 Spring Data,ScrollSubrange公开ScrollPosition. 例如:spring-doc.cadn.net.cn

@Controller
public class BookController {

	@QueryMapping
	public Window<Book> books(ScrollSubrange subrange) {
		ScrollPosition position = subrange.position().orElse(ScrollPosition.offset());
		int count = subrange.count().orElse(20);
		// ...
	}

}

有关分页和内置机制的概述,请参阅分spring-doc.cadn.net.cn

Sort

当 Spring 配置中存在 SortStrategy bean 时,控制器 方法 支持Sort作为方法参数。例如:spring-doc.cadn.net.cn

@Controller
public class BookController {

	@QueryMapping
	public Window<Book> books(Optional<Sort> optionalSort) {
		Sort sort = optionalSort.orElse(Sort.by(..));
	}

}

DataLoader

当您为实体注册批量加载函数时,如批量加载中所述,您可以访问DataLoader通过声明 类型为DataLoader并使用它来加载实体:spring-doc.cadn.net.cn

@Controller
public class BookController {

	public BookController(BatchLoaderRegistry registry) {
		registry.forTypePair(Long.class, Author.class).registerMappedBatchLoader((authorIds, env) -> {
			// return Map<Long, Author>
		});
	}

	@SchemaMapping
	public CompletableFuture<Author> author(Book book, DataLoader<Long, Author> loader) {
		return loader.load(book.getAuthorId());
	}

}

默认情况下,BatchLoaderRegistry使用值类型的完整类名(例如 的类名Author) 用于注册密钥,因此只需声明 这DataLoader具有泛型类型的方法参数提供了足够的信息 在DataLoaderRegistry.作为后备,该DataLoadermethod 参数 解析器也会尝试将方法参数名称作为键,但通常不应该 是必要的。spring-doc.cadn.net.cn

请注意,对于加载相关实体的许多情况,其中@SchemaMapping只是 委托给DataLoader,您可以使用下一节中所述的@BatchMapping方法减少样板。spring-doc.cadn.net.cn

验证

javax.validation.Validator发现豆子,AnnotatedControllerConfigurer在带注释的控制器方法上启用对 Bean 验证的支持。通常,bean 的类型为LocalValidatorFactoryBean.spring-doc.cadn.net.cn

Bean 验证允许您声明对类型的约束:spring-doc.cadn.net.cn

public class BookInput {

	@NotNull
	private String title;

	@NotNull
	@Size(max=13)
	private String isbn;
}

然后,您可以使用@Valid在之前验证它 方法调用:spring-doc.cadn.net.cn

@Controller
public class BookController {

	@MutationMapping
	public Book addBook(@Argument @Valid BookInput bookInput) {
		// ...
	}
}

如果在验证期间发生错误,则ConstraintViolationException被提高。 您可以使用异常链来决定如何将其呈现给客户端 将其转换为错误以包含在 GraphQL 响应中。spring-doc.cadn.net.cn

除了@Valid,也可以使用 Spring 的@Validated这允许 指定验证组。

Bean 验证对以下情况很有用@Argument,@Arguments,并@ProjectedPayload方法参数,但更普遍地适用于任何方法参数。spring-doc.cadn.net.cn

验证和 Kotlin 协程

Hibernate Validator 与 Kotlin 协程方法不兼容,并且在以下情况下失败 内省他们的方法参数。请参阅 spring-projects/spring-graphql#344 (comment) 以获取相关问题的链接和建议的解决方法。spring-doc.cadn.net.cn

@BatchMapping

批量加载通过使用org.dataloader.DataLoader延迟加载单个实体实例,因此它们 可以一起加载。例如:spring-doc.cadn.net.cn

@Controller
public class BookController {

	public BookController(BatchLoaderRegistry registry) {
		registry.forTypePair(Long.class, Author.class).registerMappedBatchLoader((authorIds, env) -> {
			// return Map<Long, Author>
		});
	}

	@SchemaMapping
	public CompletableFuture<Author> author(Book book, DataLoader<Long, Author> loader) {
		return loader.load(book.getAuthorId());
	}

}

对于加载关联实体的直接情况,如上所示,@SchemaMapping方法只不过是委托给DataLoader.这是 可以通过@BatchMapping方法。例如:spring-doc.cadn.net.cn

@Controller
public class BookController {

	@BatchMapping
	public Mono<Map<Book, Author>> author(List<Book> books) {
		// ...
	}
}

以上成为BatchLoaderRegistry键在哪里Book实例及其作者加载的值。此外,一个DataFetcher也透明地绑定到author字段Book哪 只需将委托给DataLoader对于作者,给定其来源/父级Book实例。spring-doc.cadn.net.cn

要用作唯一键,Book必须实现hashcodeequals.spring-doc.cadn.net.cn

默认情况下,字段名称默认为方法名称,而类型名称默认为 输入的简单类名List元素类型。两者都可以通过 注释属性。类型名称也可以从类级别继承@SchemaMapping.spring-doc.cadn.net.cn

方法参数

批处理映射方法支持以下参数:spring-doc.cadn.net.cn

方法参数 描述

List<K>spring-doc.cadn.net.cn

源/父对象。spring-doc.cadn.net.cn

java.security.Principalspring-doc.cadn.net.cn

从 Spring Security 上下文(如果可用)获取。spring-doc.cadn.net.cn

@ContextValuespring-doc.cadn.net.cn

要从GraphQLContextBatchLoaderEnvironment, 这与DataFetchingEnvironment.spring-doc.cadn.net.cn

GraphQLContextspring-doc.cadn.net.cn

要从BatchLoaderEnvironment, 这与DataFetchingEnvironment.spring-doc.cadn.net.cn

BatchLoaderEnvironmentspring-doc.cadn.net.cn

GraphQL Java 中可用的环境org.dataloader.BatchLoaderWithContext.spring-doc.cadn.net.cn

context属性BatchLoaderEnvironment返回相同的GraphQLContext实例,也可用于@SchemaMapping通过DataFetchingEnvironment.spring-doc.cadn.net.cn

keyContexts属性BatchLoaderEnvironment返回 localContext 从DataFetchingEnvironmentDataLoader为每个钥匙调用。spring-doc.cadn.net.cn

返回值

批量映射方法可以返回:spring-doc.cadn.net.cn

返回类型 描述

Mono<Map<K,V>>spring-doc.cadn.net.cn

将父对象作为键,批量加载对象作为值的映射。spring-doc.cadn.net.cn

Flux<V>spring-doc.cadn.net.cn

批量加载的对象序列,必须与源/父级的顺序相同 对象传递到方法中。spring-doc.cadn.net.cn

Map<K,V>,Collection<V>spring-doc.cadn.net.cn

命令式变体,例如无需进行远程调用。spring-doc.cadn.net.cn

Callable<Map<K,V>>,Callable<Collection<V>>spring-doc.cadn.net.cn

要异步调用的命令式变体。为此,AnnotatedControllerConfigurer必须配置Executor.spring-doc.cadn.net.cn

Kotlin 协程与Map<K,V>、KotlinFlow<K,V>spring-doc.cadn.net.cn

适应Mono<Map<K,V>Flux<V>.spring-doc.cadn.net.cn

在 Java 21+ 上,当AnnotatedControllerConfigurer配置了Executor控制器 具有阻塞方法签名的方法将异步调用。默认情况下,控制器如果方法不返回异步类型(例如Flux,Mono,CompletableFuture,也不是 Kotlin 挂起函数。您可以配置blocking 控制器方法PredicateAnnotatedControllerConfigurer以提供帮助确定哪些方法被视为阻塞。spring-doc.cadn.net.cn

Spring for GraphQL 的 Spring Boot Starters自动配置AnnotatedControllerConfigurer使用Executor对于虚拟线程,当属性spring.threads.virtual.enabled已设置。

接口批处理映射

接口模式映射的情况一样, 当批处理映射方法映射到架构接口字段时,映射将替换为 多个映射,每个映射用于实现接口的架构对象类型。spring-doc.cadn.net.cn

这意味着,考虑到以下情况:spring-doc.cadn.net.cn

type Query {
	activities: [Activity!]!
}

interface Activity {
	id: ID!
	coordinator: User!
}

type FooActivity implements Activity {
	id: ID!
	coordinator: User!
}

type BarActivity implements Activity {
	id: ID!
	coordinator: User!
}

type User {
	name: String!
}

您可以像这样编写一个控制器:spring-doc.cadn.net.cn

@Controller
public class BookController {

	@QueryMapping
	public List<Activity> activities() {
		// ...
	}

	@BatchMapping
	Map<Activity, User> coordinator(List<Activity> activities) {
		// Called for all Activity subtypes
	}
}

如有必要,您可以接管各个子类型的映射:spring-doc.cadn.net.cn

@Controller
public class BookController {

	@QueryMapping
	public List<Activity> activities() {
		// ...
	}

	@BatchMapping
	Map<Activity, User> coordinator(List<Activity> activities) {
		// Called for all Activity subtypes
	}

	@BatchMapping(field = "coordinator")
	Map<Activity, User> fooCoordinator(List<FooActivity> activities) {
		// ...
	}
}

@GraphQlExceptionHandler

@GraphQlExceptionHandler使用 灵活的方法签名。当在 controller,异常处理程序方法适用于来自同一控制器的异常:spring-doc.cadn.net.cn

import graphql.GraphQLError;
import graphql.GraphqlErrorBuilder;

import org.springframework.graphql.data.method.annotation.Argument;
import org.springframework.graphql.data.method.annotation.GraphQlExceptionHandler;
import org.springframework.graphql.data.method.annotation.QueryMapping;
import org.springframework.graphql.execution.ErrorType;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindException;

@Controller
public class BookController {

	@QueryMapping
	public Book bookById(@Argument Long id) {
		return ...
	}

	@GraphQlExceptionHandler
	public GraphQLError handle(GraphqlErrorBuilder<?> errorBuilder, BindException ex) {
		return errorBuilder
				.errorType(ErrorType.BAD_REQUEST)
				.message(ex.getMessage())
				.build();
	}

}

当在@ControllerAdvice,异常处理程序方法适用于控制器:spring-doc.cadn.net.cn

import graphql.GraphQLError;
import graphql.GraphqlErrorBuilder;

import org.springframework.graphql.data.method.annotation.GraphQlExceptionHandler;
import org.springframework.graphql.execution.ErrorType;
import org.springframework.validation.BindException;
import org.springframework.web.bind.annotation.ControllerAdvice;

@ControllerAdvice
public class GlobalExceptionHandler {

	@GraphQlExceptionHandler
	public GraphQLError handle(GraphqlErrorBuilder<?> errorBuilder, BindException ex) {
		return errorBuilder
				.errorType(ErrorType.BAD_REQUEST)
				.message(ex.getMessage())
				.build();
	}

}

如上面的示例所示,您应该通过注入GraphQlErrorBuilder在方法签名中 因为它已经准备好了当前DataFetchingEnvironment.spring-doc.cadn.net.cn

异常处理方式@GraphQlExceptionHandler方法会自动应用于 控制器调用。要处理来自其他graphql.schema.DataFetcher不基于控制器方法的实现,会获得一个DataFetcherExceptionResolverAnnotatedControllerConfigurer,并在GraphQlSource.Builder作为 DataFetcherExceptionResolverspring-doc.cadn.net.cn

方法签名

异常处理程序方法支持带有方法参数的灵活方法签名 从DataFetchingEnvironment,并与@SchemaMapping方法的匹配。spring-doc.cadn.net.cn

下面列出了支持的返回类型:spring-doc.cadn.net.cn

返回类型 描述

graphql.GraphQLErrorspring-doc.cadn.net.cn

将异常解决为单个字段错误。spring-doc.cadn.net.cn

Collection<GraphQLError>spring-doc.cadn.net.cn

解决多个字段错误的异常。spring-doc.cadn.net.cn

voidspring-doc.cadn.net.cn

解决异常,没有响应错误。spring-doc.cadn.net.cn

Objectspring-doc.cadn.net.cn

将异常解决为单个错误、多个错误或无。 返回值必须是GraphQLError,Collection<GraphQLError>null.spring-doc.cadn.net.cn

Mono<T>spring-doc.cadn.net.cn

对于异步分辨率,其中<T>是受支持的同步返回类型之一。spring-doc.cadn.net.cn

命名空间

在架构级别,查询和变更作直接在QueryMutation类型。 丰富的 GraphQL API 可以在这些类型下定义数十个作,从而更难探索 API 并分离关注点。您可以选择在 GraphQL 架构中定义命名空间。虽然这种方法有一些注意事项,但您可以使用 Spring for GraphQL 注释控制器实现此模式。spring-doc.cadn.net.cn

例如,使用命名空间,您的 GraphQL 架构可以将查询作嵌套在顶级类型下,而不是将它们直接列在Query. 在这里,我们将定义MusicQueriesUserQueries类型,并使其在Query:spring-doc.cadn.net.cn

type Query {
    music: MusicQueries
    users: UserQueries
}

type MusicQueries {
    album(id: ID!): Album
    searchForArtist(name: String!): [Artist]
}

type Album {
    id: ID!
    title: String!
}

type Artist {
    id: ID!
    name: String!
}

type UserQueries {
    user(login: String): User
}

type User {
    id: ID!
    login: String!
}

GraphQL 客户端将使用album查询如下:spring-doc.cadn.net.cn

{
  music {
    album(id: 42) {
      id
      title
    }
  }
}

并得到以下响应:spring-doc.cadn.net.cn

{
  "data": {
    "music": {
      "album": {
        "id": "42",
        "title": "Spring for GraphQL"
      }
    }
  }
}

这可以在@Controller具有以下模式:spring-doc.cadn.net.cn

import java.util.List;

import org.springframework.graphql.data.method.annotation.Argument;
import org.springframework.graphql.data.method.annotation.QueryMapping;
import org.springframework.graphql.data.method.annotation.SchemaMapping;
import org.springframework.stereotype.Controller;

@Controller
@SchemaMapping(typeName = "MusicQueries") (1)
public class MusicController {

	@QueryMapping (2)
	public MusicQueries music() {
		return new MusicQueries();
	}

	(3)
	public record MusicQueries() {

	}

	@SchemaMapping (4)
	public Album album(@Argument String id) {
		return new Album(id, "Spring GraphQL");
	}

	@SchemaMapping
	public List<Artist> searchForArtist(@Argument String name) {
		return List.of(new Artist("100", "the Spring team"));
	}


}
1 @SchemaMappingtypeName属性,以避免在方法上重复它
2 定义一个@QueryMapping对于“music”命名空间
3 “music”查询返回“空”记录,但也可能返回空映射
4 查询现在声明为“MusicQueries”类型下的字段

而不是在控制器中显式声明包装类型(“MusicQueries”、“UserQueries”), 您可以选择使用运行时接线来配置它们GraphQlSourceBuilderCustomizer使用 Spring Boot:spring-doc.cadn.net.cn

import java.util.Collections;
import java.util.List;

import org.springframework.boot.autoconfigure.graphql.GraphQlSourceBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;


@Configuration
public class NamespaceConfiguration {

	@Bean
	public GraphQlSourceBuilderCustomizer customizer() {
		List<String> queryWrappers = List.of("music", "users"); (1)

		return (sourceBuilder) -> sourceBuilder.configureRuntimeWiring((wiringBuilder) ->
				queryWrappers.forEach((field) -> wiringBuilder.type("Query",
						(builder) -> builder.dataFetcher(field, (env) -> Collections.emptyMap()))) (2)
		);
	}

}
1 列出“查询”类型的所有包装器类型
2 手动声明每个数据获取器,返回一个空的 Map