How to solve N+1 problem using leangen/graphql-spqr

128 views Asked by At

Suppose I have below query method defined, Lets say getAllBooks returns 10 books, now if we query for price too, price method will be called multiple times (10 times in this case). How can I batch the call to price method.

@GraphQLQuery(name = "getAllBooks", description = "Get all books")
public List<Book> getAllBooks() {
    return bookService.getAllBooks();
}

@GraphQLQuery
public Long price(@GraphQLContext Book book) {
    return 10L; //In real world problem I want to fetch price from another internal http service.
}

I am looking for solution something similar to posted in below post.

https://jskim1991.medium.com/spring-boot-batching-graphql-queries-with-batchmapping-ed5955835432

Is the DataLoaderRegistryFactory way to go?

1

There are 1 answers

0
kaqqao On

There are multiple ways. The most common one in GraphQL is by using DataLoader. It is possible to register custom data loaders in SPQR in a few different ways, but the simplest is to mark a batch-loading function with @Batched:

@Batched
@GraphQLQuery
public List<Long> price(@GraphQLContext List<Book> books) {
    return fetchAllPrices(books);
}

Note: If you're using SPQR directly (and not via the Spring Boot starter, which already does this for you), make sure to initialize the GraphQL object via SPQR's GraphQLRuntime helper, e.g.

ExecutableSchema schema = new GraphQLSchemaGenerator()
    .withOperationsFromSingleton(...)
    .generateExecutable();

GraphQL gql = GraphQLRuntime.newGraphQL(schema).build();

(instead of GraphQL.newGraphQL(schema).build()). This because GraphQLRuntime accepts ExecutableSchema which contains batch loaders and other discovered elements on top of the actual GraphQL schema.

An alternative approach is to look into the DataFetchingFieldSelectionSet (obtained via DataFetchingEnvironment#getSelectionSet) and eagerly fetch sub-selected fields. This strategy is nicely described here;