TLDR; Use lazy properties to avoid unecessary database connections and queries. Also use optional properties to avoid n+1 queries.
The big backstory is that I’m working on an API gateway that allows clients to access various backend services
without knowing the specific data shapes expected by, and returned by, each, what content type each service is expecting,
or even what data comes from wich. You know, an API gateway.
It was decided that this gateway would implement a GraphQL interface using the graphql-kotlin
library.
I’ll go more into this decision in a future post (hopefully).
This post covers a solution I came across for a situation involving data sourced from two different databases.
I wanted to avoid making unecessary queries, both via overfetching, and n+1 queries.
Schema and Query
1
2
3
4
5
6
7
8
9
10
11
12
13
14
type Book {
authors: String
id: Int!
imageUrl: String
product: Product
product_id: Int
title: String
}
type Product {
id: Int!
name: String!
price: Float!
}
In the data shape above we have a clear split between Book
metadata and Product
sales information.
This split makes sense from a schema perspective because the situations where product information is needed is a
distinct group (Store Page, Shopping Cart). Whereas the metadata is useful in those situations, as well as other (content production).
In addition, this makes implementation a bit easier.
The actual data is stored within two separate services. Book metadata is stored in a service that handles user ownership (Bookshelf), and user generated content, such as annotations, bookmarks, and highlights. The product information is stored by service that handles sales operations (Shop) In order to satisfy a query like the one below at least two queries would have to be performed, one to the Bookshelf and one to the Shop service
1
2
3
4
5
6
7
8
9
10
11
query($searchParameters: BookSearchParametersInput!) {
searchBooks(searchParameters: $searchParameters) {
id
imageUrl
productId
title
product {
price
}
}
}
Initial Implementation
Lampshade the passthrough layer (using jooq directly)
1
// slimed down version that makes request in one go
(Explaintaion on why this wont work). If we were to make the following query, an unecessary request would be made against the Shop database
Soloution 1: Lazy Properties
Problem 2: A shit load of queries
This works ok, but can lead to n+1 queries (brief explain). This is a massive was of time and network resources.
Solution 2: Optionally set the Product info on creation.
Look at graphql query env, see if product is in there, make the query (dollar sign)