I am new to Graphql and looking into creating a proof of concept to see how it works. I am using Spring Boot (2.2.2.RELEASE) and bringing in the graphql-spring-boot-starter.
<dependency>
<groupId>com.graphql-java-kickstart</groupId>
<artifactId>graphql-spring-boot-starter</artifactId>
<version>6.0.1</version>
</dependency>
I have setup my graphql schema as a file on the classpath with the following configuration:
type Order {
orderNumber: ID!
customers: [Customer]
items: [Item]
}
type Customer {
customerNumber: ID!
fullName: String
postalAddresses: [PostalAddress]
}
type PostalAddress {
line1: String
line2: String
city: String
stateCode: String
postalCode: String
postalCodeExtension: String
countryCode: String
}
type Item {
itemId: ID!
fullDescription: String
}
type Query {
findOrdersByCustomerNumber(customerNumber: String): [Order]
}
I have created a root Query class:
@Component
public class Query implements GraphQLQueryResolver {
private OrderService orderService;
@Autowired
public Query(OrderService orderService) {
this.orderService = orderService;
}
public List<Order> findOrdersByCustomerNumber(String customerNumber) {
return this.orderService.findOrdersByCustomerNumber(customerNumber);
}
}
And here is my Order resolver:
@Component
public class OrderResolver implements GraphQLResolver<Order> {
private ItemRepository itemRepository;
private CustomerRepository customerRepository;
@Autowired
public OrderResolver(CustomerRepository customerRepository, ItemRepository itemRepository) {
this.customerRepository = customerRepository;
this.itemRepository = itemRepository;
}
public List<Item> item(Order order) {
return itemRepository.findItemsByOrderNumber(order.getOrderNumber());
}
public List<Customer> customers(Order order) {
return customerRepository.findCustomersByOrderNumber(order.getOrderNumber());
}
}
Everything seems to work fine and I can send a graphql request and get a response. It was actually really easy to implement and impressed with how quickly this library allowed me to do that.
However, here is my issue. It's the dreaded n+1 SQL issue.
So, when I have customer with 162 orders.
1 = Driver SQL (get all the orders for the customer number)
162 = Customer SQL (One query is fired off for each order and it's same customer for each select)
162 = Postal Address SQL (One query is fired off for each customer...note, not included in the code snippets)
162 = Item SQL (assume one item per order).
So, that totals 487 SQL queries. And as a result, this has performance implications. I am using straight JDBC to query the database (no JPA or ORM's at the moment).
My questions is how can I get hold of the GraphQL request in the root Query resolver so that can manipulate the SQL for the dependent objects in the graph? When doing some research, I see that in the Node/Javacript world, there a dataloader utility that can help address this issue (https://github.com/graphql/dataloader)
So, I am unclear on how to solve this with this java implementation. If anyone has any suggestions or sample code, that would be really helpful to see if this POC has any merit.