In Spring for GraphQL, how do @QueryMapping and @MutationMapping map controller methods to schema fields, and how does @Argument bind incoming arguments?
answer
- method name == field name
- @QueryMapping/@MutationMapping = @SchemaMapping shortcuts
- @Argument binds one named arg (needs -parameters)
- input type -> POJO via constructor/setter binder
- @Arguments binds whole map
basics
~10 sPut @QueryMapping or @MutationMapping on a method in a @Controller; the method name matches the schema field under the Query or Mutation type. @Argument binds a named GraphQL argument to a method parameter.
solid answer
~40 sIn Spring for GraphQL you annotate methods on a Spring @Controller. @QueryMapping marks a handler for a field under the root Query type; @MutationMapping for a field under Mutation. By default the schema field name equals the method name (override with the annotation's value/field). The method's return value becomes the field's result. @Argument binds a single named GraphQL argument to a parameter — by default the parameter name (needs the -parameters compiler flag) or an explicit name. @Argument can bind a scalar, a List, or a whole input type mapped onto a POJO via constructor/setter binding. These are convenience shortcuts for @SchemaMapping with typeName pre-set to Query/Mutation. The controller is registered automatically by AnnotatedControllerConfigurer.
code
java · 24 lines@Controller
public class BookController {
private final BookService service;
BookController(BookService service) { this.service = service; }
// Resolves field `bookById` under type Query (method name == field name)
@QueryMapping
public Book bookById(@Argument Long id) {
return service.findById(id);
}
// Resolves field `addBook` under type Mutation; input type -> POJO
@MutationMapping
public Book addBook(@Argument BookInput input) {
return service.create(input.title(), input.authorId());
}
}
// schema.graphqls
// type Query { bookById(id: ID): Book }
// type Mutation{ addBook(input: BookInput!): Book }
// input BookInput { title: String!, authorId: ID! }go deeper
Know the three root-type shortcuts and that method name defaults to field name; know @Argument binds a named argument.
Explain input-type-to-POJO binding via the constructor, the -parameters requirement, and @Arguments vs @Argument.
Discuss the GraphQlArgumentBinder, ConversionService, Optional handling, and that these are @SchemaMapping shortcuts registered by AnnotatedControllerConfigurer.
Weigh annotated controllers vs programmatic RuntimeWiring, and the schema-first contract implications of method/field coupling.
Spring for GraphQL (the `spring-boot-starter-graphql` project) lets you implement GraphQL resolvers as annotated methods on a Spring `@Controller`, mirroring the Spring MVC programming model. **The mapping annotations** - `@QueryMapping` — the method resolves a field under the root `Query` type. - `@MutationMapping` — resolves a field under the root `Mutation` type. - `@SubscriptionMapping` — resolves a field under the root `Subscription` type (must return a stream). - `@SchemaMapping(typeName=..., field=...)` — the general form; the three above are shortcuts that pre-set `typeName` to `Query`/`Mutation`/`Subscription`. **Field-name resolution**: by default the GraphQL field name equals the Java method name. So `@QueryMapping public Book bookById(...)` binds to a schema field `bookById` under `type Query`. Override with `@QueryMapping("bookById")` or `@QueryMapping(name = "bookById")` if the method name differs. **@Argument binding**: `@Argument` binds one named GraphQL argument to a method parameter. The argument name comes from the parameter name — which requires compiling with the `-parameters` flag (Spring Boot's Gradle/Maven plugins enable this) — or from an explicit `@Argument("id")`. Binding capabilities: - Scalars bind directly (`@Argument Long id`). - Lists bind to `List<T>` / arrays. - A GraphQL **input type** binds to a Java POJO. Spring uses a `GraphQlArgumentBinder` that populates the object via its constructor (preferred) or setters, converting nested maps recursively. Type conversion goes through Spring's `ConversionService`. - `@Argument Optional<T>` distinguishes "absent" from "null". - `@Arguments` (plural) binds the *entire* arguments map to one object instead of a single named argument. **Other injectable parameters**: besides `@Argument`, handler methods may accept the source/parent object, `DataFetchingEnvironment`, `@ContextValue`, `GraphQLContext`, `Principal`, a `DataLoader`, `@ProjectedPayload` interfaces, etc. **Registration**: `AnnotatedControllerConfigurer` scans beans for these annotations and registers `DataFetcher`s with the underlying graphql-java `GraphQL` engine. Boot auto-configures it. **Gotchas** - Forgetting `-parameters` → argument name is unknown → binding fails at runtime; always name explicitly or ensure the flag is set. - The method name must match the schema field or you must override it; a mismatch means the field silently falls back to graphql-java's default `PropertyDataFetcher` (or errors if no property exists). - `@MutationMapping` doesn't make anything transactional or ordered; it's purely a routing annotation. **When to use**: annotated controllers are the idiomatic default for Spring GraphQL. Use them over programmatic `RuntimeWiring` `DataFetcher` registration unless you need fully dynamic wiring.
- Why might @Argument binding fail with 'name for argument cannot be determined'?The code was compiled without the -parameters flag, so parameter names are erased. Fix by adding the flag (Spring Boot plugins do) or giving an explicit name: @Argument("id").
- What is the difference between @Argument and @Arguments?@Argument binds a single named argument to a parameter. @Arguments (plural) binds the entire arguments map onto one target object — useful when all top-level arguments belong to one command object.
saying these in an interview costs you the question
- Claiming @Argument works like @RequestParam over HTTP query strings (it binds GraphQL argument maps, not URL params)
- Thinking @MutationMapping adds transactions or ordering
- Assuming parameter names always resolve without the -parameters flag