アノテーション付きコントローラー
Spring for GraphQL は、@Controller
コンポーネントがアノテーションを使用して、特定の GraphQL フィールドのデータをフェッチするための柔軟なメソッドシグネチャーを持つハンドラーメソッドを宣言する、アノテーションベースのプログラミングモデルを提供します。例:
@Controller
public class GreetingController {
@QueryMapping (1)
public String hello() { (2)
return "Hello, world!";
}
}
1 | このメソッドをクエリ、つまり Query 型のフィールドにバインドします。 |
2 | アノテーションで宣言されていない場合は、メソッド名からクエリを決定します。 |
Spring for GraphQL は RuntimeWiring.Builder
を使用して、上記のハンドラーメソッドを "hello" という名前のクエリの graphql.schema.DataFetcher
として登録します。
宣言
@Controller
Bean を標準の Spring Bean 定義として定義できます。@Controller
ステレオタイプは、クラスパス上の @Controller
および @Component
クラスを検出し、それらの Bean 定義を自動登録するための Spring 一般サポートと連携して、自動検出を可能にします。また、アノテーション付きクラスのステレオタイプとしても機能し、GraphQL アプリケーションでのデータ取得コンポーネントとしてのロールを示します。
AnnotatedControllerConfigurer
は @Controller
Bean を検出し、それらのアノテーション付きハンドラーメソッドを RuntimeWiring.Builder
を介して DataFetcher
として登録します。GraphQlSource.Builder
に追加できる RuntimeWiringConfigurer
の実装です。Boot スターターは自動的に AnnotatedControllerConfigurer
を Bean として宣言し、すべての RuntimeWiringConfigurer
Bean を GraphQlSource.Builder
に追加します。これにより、アノテーション付き DataFetcher
のサポートが有効になります。Boot スタータードキュメントの GraphQL RuntimeWiring セクションを参照してください。
@SchemaMapping
@SchemaMapping
アノテーションは、ハンドラーメソッドを GraphQL スキーマのフィールドにマップし、それがそのフィールドの DataFetcher
であることを宣言します。アノテーションは、親の型名とフィールド名を指定できます。
@Controller
public class BookController {
@SchemaMapping(typeName="Book", field="author")
public Author getAuthor(Book book) {
// ...
}
}
@SchemaMapping
アノテーションはこれらの属性を除外することもできます。その場合、フィールド名はデフォルトでメソッド名になり、型名はデフォルトでメソッドに注入されたソース / 親オブジェクトの単純なクラス名になります。例: 以下のデフォルトは、型が "Book" で、フィールドが "author" です。
@Controller
public class BookController {
@SchemaMapping
public Author author(Book book) {
// ...
}
}
@SchemaMapping
アノテーションをクラスレベルで宣言して、クラス内のすべてのハンドラーメソッドの既定の型名を指定できます。
@Controller
@SchemaMapping(typeName="Book")
public class BookController {
// @SchemaMapping methods for fields of the "Book" type
}
@QueryMapping
、@MutationMapping
、@SubscriptionMapping
はメタアノテーションであり、それ自体は @SchemaMapping
でアノテーションが付けられ、typeName はそれぞれ Query
、Mutation
、または Subscription
にプリセットされています。実質的には、これらはそれぞれクエリ、ミューテーション、サブスクリプション型のフィールドのショートカットアノテーションです。例:
@Controller
public class BookController {
@QueryMapping
public Book bookById(@Argument Long id) {
// ...
}
@MutationMapping
public Book addBook(@Argument BookInput bookInput) {
// ...
}
@SubscriptionMapping
public Flux<Book> newPublications() {
// ...
}
}
@SchemaMapping
ハンドラーメソッドには柔軟なシグネチャーがあり、さまざまなメソッド引数と戻り値から選択できます。
メソッド引数
スキーママッピングハンドラーメソッドは、次のメソッド引数のいずれかを持つことができます。
メソッド引数 | 説明 |
---|---|
| 上位レベルの型付きオブジェクトにバインドされた名前付きフィールド引数にアクセスするため。
|
| 生の引数値にアクセスするため。
|
| 入力引数が省略されたか
|
| 上位レベルの型付きオブジェクトにバインドされたすべてのフィールド引数にアクセスします。
|
| 引数の生のマップへのアクセス用。 |
|
For access to field arguments through a project interface. |
"Source" |
For access to the source (i.e. parent/container) instance of the field. See Source. |
| ページネーション引数へのアクセス用。 |
| 並べ替えの詳細へのアクセス用。 |
|
|
|
|
|
|
|
|
| 利用可能な場合、Spring Security コンテキストから取得されます。 |
| Spring Security コンテキストから |
|
|
|
|
| 基礎となる |
戻り値
スキーママッピングハンドラーメソッドは、以下を返すことができます。
任意の型の解決された値。
非同期値の
Mono
およびFlux
。リアクティブDataFetcher
に従って、コントローラーメソッドと任意のDataFetcher
でサポートされています。Kotlin コルーチンと
Flow
は、Mono
とFlux
に適合されます。java.util.concurrent.Callable
を使用して、値を非同期的に生成します。これを機能させるには、AnnotatedControllerConfigurer
をExecutor
で構成する必要があります。
Java 21+ では、AnnotatedControllerConfigurer
が Executor
で構成されている場合、ブロッキングメソッドシグネチャーを持つコントローラーメソッドが非同期的に呼び出されます。デフォルトでは、コントローラーメソッドは、Flux
、Mono
、CompletableFuture
などの非同期型を返さず、Kotlin の中断関数でもない場合はブロッキングと見なされます。AnnotatedControllerConfigurer
でブロッキングコントローラーメソッド Predicate
を構成すると、どのメソッドがブロッキングと見なされるかを判断できます。
Spring for GraphQL の Spring Boot スターターは、プロパティ spring.threads.virtual.enabled が設定されている場合、仮想スレッドの Executor を使用して AnnotatedControllerConfigurer を自動的に構成します。 |
インターフェーススキーママッピング
コントローラーメソッドがスキーマインターフェースフィールドにマップされると、デフォルトでは、インターフェースを実装するスキーマオブジェクト型ごとに 1 つずつ、複数のマッピングに置き換えられます。これにより、すべてのサブ型に対して 1 つのコントローラーメソッドを使用できるようになります。
例: 与えられた:
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!
}
コントローラーは次のように記述できます。
@Controller
public class BookController {
@QueryMapping
public List<Activity> activities() {
// ...
}
@SchemaMapping
public User coordinator(Activity activity) {
// Called for any Activity subtype
}
}
必要に応じて、個々のサブ型のマッピングを引き継ぐことができます。
@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
にすることができます。
@Argument
アノテーションを使用して、引数をターゲットオブジェクトにバインドし、ハンドラーメソッドに注入します。バインドは、引数値を予想されるメソッドパラメーターの型のプライマリデータコンストラクターにマップするか、既定のコンストラクターを使用してオブジェクトを作成し、引数値をそのプロパティにマップすることによって実行されます。これが再帰的に繰り返され、ネストされたすべての引数値が使用され、それに応じてネストされたターゲットオブジェクトが作成されます。例:
@Controller
public class BookController {
@QueryMapping
public Book bookById(@Argument Long id) {
// ...
}
@MutationMapping
public Book addBook(@Argument BookInput bookInput) {
// ...
}
}
ターゲットオブジェクトに setter がなく、それを変更できない場合は、AnnotatedControllerConfigurer のプロパティを使用して、フィールドへの直接アクセスによるバインディングのフォールバックを許可できます。 |
デフォルトでは、メソッドパラメーター名が使用可能な場合 (Java 8+ を指定した -parameters
コンパイラーフラグまたはコンパイラーからのデバッグ情報が必要)、引数の検索に使用されます。必要に応じて、アノテーションを使用して名前をカスタマイズできます。@Argument("bookInput")
。
@Argument アノテーションには、「必須」フラグも、デフォルト値を指定するオプションもありません。これらはどちらも GraphQL スキーマレベルで指定でき、GraphQL Java によって適用されます。 |
バインディングが失敗した場合、フィールドエラーとして蓄積されたバインディングの課題とともに BindException
が発生します。各エラーの field
は、問題が発生した引数パスです。
@Argument
を Map<String, Object>
引数とともに使用すると、引数の生の値を取得できます。例:
@Controller
public class BookController {
@MutationMapping
public Book addBook(@Argument Map<String, Object> bookInput) {
// ...
}
}
1.2 より前は、アノテーションで名前が指定されていない場合、@Argument Map<String, Object> は完全な引数マップを返しました。1.2 の後、@Argument と Map<String, Object> は常に、アノテーションで指定された名前またはパラメーター名のいずれかに一致する生の引数値を返します。完全な引数マップにアクセスするには、代わりに @Arguments を使用してください。 |
ArgumentValue
デフォルトでは、GraphQL の入力引数は null 可能でオプションです。つまり、引数を null
リテラルに設定することも、まったく指定しないこともできます。この区別は、基礎となるデータも null
に設定されているか、それに応じてまったく変更されていない可能性があるミューテーションによる部分的な更新に役立ちます。@Argument
を使用する場合、どちらの場合も null
または空の Optional
を取得するため、そのような区別を行う方法はありません。
値がまったく提供されていないかどうかを知りたくない場合は、入力引数が完全に省略されたかどうかを示すフラグとともに、結果の値の単純なコンテナーである ArgumentValue
メソッドパラメーターを宣言できます。これを @Argument
の代わりに使用できます。この場合、引数名はメソッドのパラメーター名から決定されます。または、@Argument
と一緒に使用して引数名を指定することもできます。
例:
@Controller
public class BookController {
@MutationMapping
public void addBook(ArgumentValue<BookInput> bookInput) {
if (!bookInput.isOmitted()) {
BookInput value = bookInput.value();
// ...
}
}
}
ArgumentValue
は、コンストラクター引数または setter を介して初期化された @Argument
メソッドパラメーターのオブジェクト構造内のフィールドとしてもサポートされます。これには、最上位オブジェクトの任意のレベルでネストされたオブジェクトのフィールドが含まれます。
@Arguments
特定の名前付き引数をバインドする @Argument
とは対照的に、完全な引数マップを単一のターゲットオブジェクトにバインドする場合は、@Arguments
アノテーションを使用します。
例: @Argument BookInput bookInput
は引数 "bookInput" の値を使用して BookInput
を初期化しますが、@Arguments
は完全な引数マップを使用し、その場合、最上位レベルの引数は BookInput
プロパティにバインドされます。
@Arguments
を Map<String, Object>
引数とともに使用して、すべての引数値の生のマップを取得できます。
@ProjectedPayload
インターフェース
@Argument
で完全なオブジェクトを使用する代わりに、射影 インターフェースを使用して、適切に定義された最小限のインターフェースを介して GraphQL リクエスト引数にアクセスすることもできます。Spring Data がクラスパス上にある場合、引数射影は Spring Data のインターフェース射影によって提供されます。
これを利用するには、@ProjectedPayload
でアノテーションを付けたインターフェースを作成し、それをコントローラーメソッドのパラメーターとして宣言します。パラメーターに @Argument
のアノテーションが付けられている場合、DataFetchingEnvironment.getArguments()
マップ内の個々の引数に適用されます。@Argument
なしで宣言すると、射影は完全な引数マップのトップレベルの引数で機能します。
例:
@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
はフィールドのソース (つまり、親 / コンテナー) インスタンスへのアクセスを提供します。これにアクセスするには、予想されるターゲット型のメソッドパラメーターを宣言するだけです。
@Controller
public class BookController {
@SchemaMapping
public Author author(Book book) {
// ...
}
}
ソースメソッドの引数は、マッピングの型名を決定するのにも役立ちます。Java クラスの単純な名前が GraphQL 型と一致する場合、@SchemaMapping
アノテーションで型名を明示的に指定する必要はありません。
|
Subrange
Spring 構成に CursorStrategy
Bean がある場合、コントローラーメソッドは Subrange<P>
引数をサポートします。<P>
はカーソルから変換された相対位置です。Spring Data の場合、ScrollSubrange
は ScrollPosition
を公開します。例:
@Controller
public class BookController {
@QueryMapping
public Window<Book> books(ScrollSubrange subrange) {
ScrollPosition position = subrange.position().orElse(ScrollPosition.offset());
int count = subrange.count().orElse(20);
// ...
}
}
ページネーションと組み込みメカニズムの概要については、ページネーションを参照してください。
Sort
Spring 構成に SortStrategy Bean がある場合、コントローラーメソッドはメソッド引数として Sort
をサポートします。例:
@Controller
public class BookController {
@QueryMapping
public Window<Book> books(Optional<Sort> optionalSort) {
Sort sort = optionalSort.orElse(Sort.by(..));
}
}
DataLoader
バッチ読み込みに従って、エンティティのバッチ読み込み関数を登録すると、型 DataLoader
のメソッド引数を宣言することでエンティティの DataLoader
にアクセスし、それを使用してエンティティを読み込むことができます。
@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
でそれを見つけるのに十分な情報が提供されます。フォールバックとして、DataLoader
メソッド引数リゾルバーもメソッド引数名をキーとして試行しますが、通常は必要ありません。
@SchemaMapping
が単純に DataLoader
に委譲する関連エンティティをロードする多くの場合、次のセクションで説明するように @BatchMapping メソッドを使用してボイラープレートを減らすことができることに注意してください。
検証
javax.validation.Validator
Bean が見つかると、AnnotatedControllerConfigurer
は、アノテーション付きコントローラーメソッドでの Bean バリデーションのサポートを有効にします。通常、Bean の型は LocalValidatorFactoryBean
です。
Bean 検証では、型に対する制約を宣言できます。
public class BookInput {
@NotNull
private String title;
@NotNull
@Size(max=13)
private String isbn;
}
次に、コントローラーメソッドパラメーターに @Valid
のアノテーションを付けて、メソッド呼び出しの前に検証できます。
@Controller
public class BookController {
@MutationMapping
public Book addBook(@Argument @Valid BookInput bookInput) {
// ...
}
}
検証中にエラーが発生すると、ConstraintViolationException
が発生します。例外チェーンを使用して、GraphQL レスポンスに含めるエラーに変換することで、それをクライアントに提示する方法を決定できます。
@Valid に加えて、検証グループを指定できる Spring の @Validated も使用できます。 |
Bean 検証は、@Argument
、@Arguments
、@ProjectedPayload メソッドパラメーターに役立ちますが、より一般的にはすべてのメソッドパラメーターに適用されます。
検証と Kotlin コルーチン Hibernate Validator は Kotlin コルーチンメソッドと互換性がなく、メソッドパラメーターをイントロスペクトするときに失敗します。関連する課題と推奨される回避策へのリンクについては、spring-projects/spring-graphql#344 (コメント) [GitHub] (英語) を参照してください。 |
@BatchMapping
バッチ読み込みは、org.dataloader.DataLoader
を使用して個々のエンティティインスタンスのロードを延期することで N+1 選択の問題に対処し、一緒にロードできるようにします。例:
@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
メソッドで回避できるボイラープレートです。例:
@Controller
public class BookController {
@BatchMapping
public Mono<Map<Book, Author>> author(List<Book> books) {
// ...
}
}
上記は、キーが Book
インスタンスであり、読み込まれた値が作成者である BatchLoaderRegistry
のバッチ読み込み関数になります。さらに、DataFetcher
は、型 Book
の author
フィールドにも透過的にバインドされます。これは、そのソース / 親 Book
インスタンスが与えられると、作成者の DataLoader
に単純に委譲します。
一意のキーとして使用するには、 |
デフォルトでは、フィールド名はメソッド名にデフォルト設定され、型名は入力 List
要素型の単純なクラス名にデフォルト設定されます。どちらもアノテーション属性を介してカスタマイズできます。型名は、クラスレベル @SchemaMapping
から継承することもできます。
メソッド引数
バッチマッピングメソッドは、次の引数をサポートしています。
メソッド引数 | 説明 |
---|---|
| ソース / 親オブジェクト。 |
| 利用可能な場合、Spring Security コンテキストから取得されます。 |
|
|
|
|
|
|
戻り値
バッチマッピングメソッドは以下を返すことができます。
戻りの型 | 説明 |
---|---|
| 親オブジェクトをキーとして、バッチロードされたオブジェクトを値として持つマップ。 |
| メソッドに渡されたソース / 親オブジェクトと同じ順序である必要があるバッチロードオブジェクトのシーケンス。 |
| 命令型のバリアント。リモート呼び出しを行う必要はありません。 |
| 非同期で呼び出される命令型バリアント。これを機能させるには、 |
|
|
Java 21+ では、AnnotatedControllerConfigurer
が Executor
で構成されている場合、ブロッキングメソッドシグネチャーを持つコントローラーメソッドが非同期的に呼び出されます。デフォルトでは、コントローラーメソッドは、Flux
、Mono
、CompletableFuture
などの非同期型を返さず、Kotlin の中断関数でもない場合はブロッキングと見なされます。AnnotatedControllerConfigurer
でブロッキングコントローラーメソッド Predicate
を構成すると、どのメソッドがブロッキングと見なされるかを判断できます。
Spring for GraphQL の Spring Boot スターターは、プロパティ spring.threads.virtual.enabled が設定されている場合、仮想スレッドの Executor を使用して AnnotatedControllerConfigurer を自動的に構成します。 |
インターフェースバッチマッピング
インターフェーススキーママッピングの場合と同様に、バッチマッピングメソッドがスキーマインターフェースフィールドにマップされると、マッピングは、インターフェースを実装するスキーマオブジェクト型ごとに 1 つずつ、複数のマッピングに置き換えられます。
つまり、次のようになります。
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!
}
コントローラーは次のように記述できます。
@Controller
public class BookController {
@QueryMapping
public List<Activity> activities() {
// ...
}
@BatchMapping
Map<Activity, User> coordinator(List<Activity> activities) {
// Called for all Activity subtypes
}
}
必要に応じて、個々のサブ型のマッピングを引き継ぐことができます。
@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
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
で宣言すると、例外ハンドラーメソッドはコントローラー全体に適用されます。
@ControllerAdvice
public class GlobalExceptionHandler {
@GraphQlExceptionHandler
public GraphQLError handle(BindException ex) {
return GraphQLError.newError().errorType(ErrorType.BAD_REQUEST).message("...").build();
}
}
@GraphQlExceptionHandler
メソッドによる例外処理は、コントローラーの呼び出しに自動的に適用されます。コントローラーメソッドに基づいていない他の graphql.schema.DataFetcher
実装からの例外を処理するには、AnnotatedControllerConfigurer
から DataFetcherExceptionResolver
を取得し、それを DataFetcherExceptionResolver として GraphQlSource.Builder
に登録します。
メソッド署名
例外ハンドラーメソッドは、DataFetchingEnvironment,
から解決され、@SchemaMapping メソッドのメソッド引数と一致するメソッド引数を使用した柔軟なメソッドシグネチャーをサポートします。
サポートされている戻り値の型を以下に示します。
戻りの型 | 説明 |
---|---|
| 単一フィールドのエラーに対する例外を解決します。 |
| 複数フィールドエラーの例外を解決します。 |
| レスポンスエラーを発生させずに例外を解決します。 |
| 例外を 1 つのエラーに解決するか、複数のエラーに解決するか、何も解決しません。戻り値は |
| 非同期解決の場合、 |
名前空間
スキーマレベルでは、クエリと変更操作は、Query
型と Mutation
型に直接定義されます。リッチ GraphQL API は、これらの型に数十の操作を定義できるため、API を調べて関心事を分離することが難しくなります。GraphQL スキーマで名前空間を定義する (英語) ことを選択できます。このアプローチにはいくつか注意点がありますが、Spring for GraphQL アノテーション付きコントローラーを使用してこのパターンを実装できます。
名前空間を使用すると、GraphQL スキーマは、たとえば、クエリ操作を Query
に直接リストするのではなく、トップレベルの型にネストすることができます。ここでは、MusicQueries
および UserQueries
型を定義し、Query
で使用できるようにします。
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
クエリを使用します。
{
music {
album(id: 42) {
id
title
}
}
}
そして、次のレスポンスが得られます。
{
"data": {
"music": {
"album": {
"id": "42",
"title": "Spring for GraphQL"
}
}
}
}
これは、次のパターンを使用して @Controller
に実装できます。
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 | メソッドで繰り返し使用されないように、コントローラーに @SchemaMapping と typeName 属性をアノテーションします。 |
2 | 「音楽」名前空間の @QueryMapping を定義する |
3 | 「音楽」クエリは「空」のレコードを返しますが、空のマップを返すこともできます。 |
4 | クエリは "MusicQueries" 型のフィールドとして宣言されるようになりました |
コントローラーで折り返し型 ("MusicQueries" ,"UserQueries" ) を明示的に宣言する代わりに、GraphQlSourceBuilderCustomizer
と Spring Boot を使用してランタイム接続で構成することもできます。
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 | それぞれに対して手動でデータフェッチャーを宣言し、空のマップを返す |