此版本仍在开发中,尚未被视为稳定版本。对于最新的稳定版本,请使用 Spring GraphQL 1.3.4spring-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 将此方法绑定到查询,即 Query 类型下的字段。
2 如果未在注释上声明,则从方法名称确定查询。

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

声明

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

AnnotatedControllerConfigurer检测@Controllerbean 并注册其 注解的处理程序方法为DataFetcherS 通过RuntimeWiring.Builder.它是一个 实现RuntimeWiringConfigurer可以添加到GraphQlSource.Builder. Boot Starter 会自动声明AnnotatedControllerConfigurer作为 Bean 并添加所有RuntimeWiringConfigurerbeans 设置为GraphQlSource.Builder这使得 支持 AnnotatedDataFetcher,请参阅 GraphQL RuntimeWiring 部分 在 Boot Starter 文档中。spring-doc.cadn.net.cn

@SchemaMapping

@SchemaMappingannotation 将处理程序方法映射到 GraphQL 架构中的字段 并声明它是DataFetcher对于该字段。注解可以指定 父类型名称,以及字段名称:spring-doc.cadn.net.cn

@Controller
public class BookController {

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

@SchemaMappingannotation 也可以省略这些属性,在这种情况下, field name 默认为 method name,而 type name 默认为 simple 类 注入方法的源/父对象的名称。例如,下面的 默认为 type “Book” 和字段 “author”:spring-doc.cadn.net.cn

@Controller
public class BookController {

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

@SchemaMapping注解可以在类级别声明以指定默认的 键入类中所有处理程序方法的 name。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分别。实际上,这些是快捷方式注释 for 字段 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处理程序方法具有灵活的签名,并且可以从一系列 方法参数和返回值..spring-doc.cadn.net.cn

方法参数

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

方法参数 描述

@Argumentspring-doc.cadn.net.cn

用于访问绑定到更高级别类型化 Object 的命名字段参数。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

用于访问绑定到更高级别的类型化 Object 的命名字段参数 带有一个标志,用于指示是否省略了 input 参数,而不是设置为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

参见 PaginationScrollSubrange.spring-doc.cadn.net.cn

Sortspring-doc.cadn.net.cn

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

参见 PaginationSort.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

要从主GraphQLContextDataFetchingEnvironment.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控制器 具有阻塞方法签名的方法将异步调用。默认情况下,控制器 如果 method 不返回异步类型(如Flux,Mono,CompletableFuture,也不是 Kotlin 挂起函数。您可以配置 阻塞控制器方法PredicateAnnotatedControllerConfigurer帮助 确定哪些方法被视为阻塞。spring-doc.cadn.net.cn

Spring Boot starter for Spring for GraphQL 会自动配置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提供对特定于字段的映射的访问权限 argument 值。这些值可以是简单的标量值(例如 String、Long)、一个Map之 值进行更复杂的输入,或者List的值。spring-doc.cadn.net.cn

使用@Argumentannotation 将参数绑定到目标对象,并将 注入到 handler 方法中。通过将参数值映射到 primary data 构造函数,或者使用默认的 constructor 创建对象,然后将 argument 值映射到其属性。这是 递归重复,使用所有嵌套参数值并创建嵌套目标对象 因此。例如: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允许通过 Direct 进行回退绑定 字段访问。

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

@Argumentannotation 没有 “required” 标志,也没有 指定 Default (默认值)。这两者都可以在 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>始终返回 Raw 参数值,并与名称匹配 在注释中指定,或添加到参数名称。要访问完整参数 map 中,请使用@Arguments相反。

ArgumentValue

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

如果你想知道某个值是否根本没有提供,你可以声明一个ArgumentValuemethod 参数,该参数是结果值的简单容器 以及一个标志,以指示是否完全省略了 input 参数。你 可以使用 this 而不是@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注解,如果要将完整的 arguments 映射到单个 target Object 与@Argument,它绑定一个特定的命名参数。spring-doc.cadn.net.cn

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

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

@ProjectedPayload接口

作为使用 完整 Object 的替代方法@Argument, 您还可以使用投影接口通过 定义明确的最小接口。当 Spring Data 位于 class path 上时,参数投影由 Spring Data 的接口投影提供。spring-doc.cadn.net.cn

要使用此功能,请创建一个带有@ProjectedPayload并声明 it 作为控制器方法参数。如果参数带有@Argument, 它适用于DataFetchingEnvironment.getArguments()地图。当声明时没有@Argument,则投影适用于 完整的 arguments 映射。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) 实例。要访问它,只需声明一个 method 参数 的预期目标类型。spring-doc.cadn.net.cn

@Controller
public class BookController {

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

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

一个@BatchMappinghandler 方法可以批量加载查询的所有作者, 给定 Source/Parent Books 对象的列表。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);
		// ...
	}

}

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

Sort

当 Spring 配置中有 SortStrategy bean 时,控制器 methods 支持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通过声明 method 参数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) 作为注册的密钥,因此只需声明 这DataLoadermethod 参数提供足够的信息 要在DataLoaderRegistry.作为回退,DataLoadermethod 参数 Resolver 还会尝试将方法参数 name 作为键,但通常不应这样做 是必要的。spring-doc.cadn.net.cn

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

验证

javax.validation.Validatorbean 的AnnotatedControllerConfigurer启用对带 Comments 的 Controller 方法的 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被提升。 您可以使用 Exceptions 链来决定如何将其呈现给客户端 将其转换为错误以包含在 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 (评论) 以获取相关问题的链接和建议的解决方法。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实例和 loaded 的值的作者。此外,一个DataFetcher也透明地绑定到author类型为Book哪 只需将DataLoader对于作者,给定其源/父级Book实例。spring-doc.cadn.net.cn

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

默认情况下,字段名称默认为方法名称,而类型名称默认为 输入的简单类名List元素类型。两者都可以通过以下方式进行定制 annotation 属性。类型名称也可以从类级别继承@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控制器 具有阻塞方法签名的方法将异步调用。默认情况下,控制器 如果 method 不返回异步类型(如Flux,Mono,CompletableFuture,也不是 Kotlin 挂起函数。您可以配置 阻塞控制器方法PredicateAnnotatedControllerConfigurer帮助 确定哪些方法被视为阻塞。spring-doc.cadn.net.cn

Spring Boot starter for Spring for GraphQL 会自动配置AnnotatedControllerConfigurer替换为Executor对于虚拟线程,当属性spring.threads.virtual.enabled已设置。

接口批处理映射

Interface Schema Mappings 一样, 将批处理映射方法映射到 Schema Interface 字段时,该映射将替换为 多个映射,每个映射用于实现接口的每个 Schema 对象类型。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

@Controller
public class BookController {

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

	@GraphQlExceptionHandler
	public GraphQLError handle(BindException ex) {
		return GraphQLError.newError().errorType(ErrorType.BAD_REQUEST).message("...").build();
	}
}

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

@ControllerAdvice
public class GlobalExceptionHandler {

	@GraphQlExceptionHandler
	public GraphQLError handle(BindException ex) {
		return GraphQLError.newError().errorType(ErrorType.BAD_REQUEST).message("...").build();
	}

}

异常处理方式@GraphQlExceptionHandler方法会自动应用于 控制器调用。处理来自其他graphql.schema.DataFetcher实现,而不是基于 Controller 方法,获取DataFetcherExceptionResolverAnnotatedControllerConfigurer,并在GraphQlSource.Builder作为 DataFetcherExceptionResolver 进行分配。spring-doc.cadn.net.cn

方法签名

异常处理程序方法支持带有方法参数的灵活方法签名 从DataFetchingEnvironment,并与 @SchemaMapping 方法的 MATCH 匹配。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

命名空间

在 schema 级别,query 和 mutation作直接在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 Annotate the controller with @SchemaMapping and a typeName attribute, to avoid repeating it on methods
2 Define a @QueryMapping for the "music" namespace
3 The "music" query returns an "empty" record, but could also return an empty map
4 Queries are now declared as fields under the "MusicQueries" type

Instead of declaring wrapping types ("MusicQueries", "UserQueries") explicitly in controllers, you can choose to configure them with the runtime wiring using a GraphQlSourceBuilderCustomizer with 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 List all the wrapper types for the "Query" type
2 Manually declare data fetchers for each of them, returning an empty Map