Working with GraphQL
1. Adding Spring GraphQL Dependencies (spring-boot-starter-graphql)
Example: GraphQL starter dependencies
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-graphql</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
2. Defining GraphQL Schema (schema.graphqls)
Example: GraphQL schema: types, queries, mutations
# src/main/resources/graphql/schema.graphqls
type Query {
book(id: ID!): Book
books(page: Int = 0, size: Int = 20): [Book!]!
}
type Mutation {
addBook(input: BookInput!): Book!
}
type Book { id: ID!, title: String!, author: Author! }
type Author { id: ID!, name: String! }
input BookInput { title: String!, authorId: ID! }
3. Creating Query Resolvers (@QueryMapping)
Example: Query resolvers for book and books
@Controller
public class BookController {
private final BookService svc;
public BookController(BookService s) { this.svc = s; }
@QueryMapping public Book book(@Argument Long id) { return svc.findById(id); }
@QueryMapping public List<Book> books(@Argument int page, @Argument int size) {
return svc.findAll(page, size);
}
}
4. Creating Mutation Resolvers (@MutationMapping)
Example: Mutation resolver: add book
@MutationMapping
public Book addBook(@Argument BookInput input) {
return svc.create(input);
}
5. Implementing Data Fetchers (DataFetcher)
Example: Field resolver for book author
@SchemaMapping(typeName = "Book", field = "author")
public Author author(Book book) {
return authorService.findById(book.getAuthorId()); // per-field fetcher
}
6. Handling Arguments (@Argument)
| Annotation | Use |
|---|---|
@Argument |
Bind GraphQL arg by name |
@Argument(name="x") |
Custom name |
@Arguments |
Bind whole input object map |
@ContextValue |
Read from GraphQLContext |
7. Using GraphQL Context (GraphQLContext)
Example: Inject user into GraphQL context
@Component
public class AuthInterceptor implements WebGraphQlInterceptor {
@Override public Mono<WebGraphQlResponse> intercept(WebGraphQlRequest req, Chain chain) {
String user = req.getHeaders().getFirst("X-User");
req.configureExecutionInput((e, b) -> b.graphQLContext(c -> c.put("user", user)).build());
return chain.next(req);
}
}
@QueryMapping public Book book(@Argument Long id, @ContextValue String user) { /* … */ }
8. Implementing Pagination (Connection pattern)
Example: Cursor-based pagination schema
type Query { books(first: Int, after: String): BookConnection! }
type BookConnection { edges: [BookEdge!]!, pageInfo: PageInfo! }
type BookEdge { node: Book!, cursor: String! }
type PageInfo { hasNextPage: Boolean!, endCursor: String }
9. Implementing Error Handling (GraphQLError)
Example: GraphQL exception resolver
@Component
public class GqlExceptionResolver extends DataFetcherExceptionResolverAdapter {
@Override protected GraphQLError resolveToSingleError(Throwable ex, DataFetchingEnvironment env) {
if (ex instanceof NotFoundException nfe) {
return GraphqlErrorBuilder.newError(env)
.errorType(ErrorType.NOT_FOUND).message(nfe.getMessage()).build();
}
return null;
}
}
10. Testing GraphQL Endpoints (GraphQlTester)
Example: Test GraphQL query with GraphQlTester
@AutoConfigureGraphQlTester
@SpringBootTest
class BookGqlTests {
@Autowired GraphQlTester tester;
@Test void getBook() {
tester.document("{ book(id: 1) { title } }")
.execute()
.path("book.title").entity(String.class).isEqualTo("Effective Java");
}
}
11. Integrating with GraphiQL UI
Example: Enable GraphiQL browser UI
spring:
graphql:
graphiql:
enabled: true
path: /graphiql
path: /graphql
schema.printer.enabled: true