- What is BaseLoader?
- What is DataLoader?
- How does BaseLoader work?
- How to use BaseLoader?
- LoadOne
- LoadByRelatedId
What is BaseLoader?
BaseLoader, an extension of DataLoader included in the BaseResolver package, is a powerful tool that enhances data loading capabilities in GraphQL APIs. It builds upon DataLoader, an open-source library developed by Facebook, to provide batching, caching, and performance optimization features.
What is DataLoader?
Before diving into BaseLoader, let's understand DataLoader.
DataLoader is a utility library designed to handle data batching and caching. It allows you to fetch multiple individual items from a data source, such as a database, in a single request instead of making separate requests for each item.
Imagine you have a list of task IDs, and you want to retrieve their details from a database. With DataLoader, you can batch all the requests together and fetch all the task details in a single query, significantly improving efficiency.
DataLoader also caches the results of each request, reducing the need for redundant queries in the future.
DataLoader is particularly valuable in GraphQL servers where you often need to fetch related data.
By using DataLoader, you can fetch all the related data in a single batch, improving performance and minimizing round trips to the data source.
Now, let's explore how BaseLoader leverages DataLoader to enhance data loading capabilities in Graphweaver.
How does BaseLoader work?
BaseLoader provides an interface for loading single and related entities with caching, error handling, and performance optimization features.
It utilizes DataLoader under the hood to batch and optimize data retrieval.
BaseLoader consists of two primary functions:
loadOne
: Loads a single entity by ID using DataLoader.loadByRelatedId
: Loads related entities based on a related ID and a filter using DataLoader.
These functions enable efficient data loading by batching requests and reducing unnecessary trips to the data source.
How to use BaseLoader?
LoadOne
To illustrate the usage of BaseLoader, let's consider an example where we want to load a user from a task.
Here's how it can be achieved using BaseLoader:
const user = await BaseLoaders.loadOne({
gqlEntityType: Task,
id: task.dataEntity.user.unwrap().id,
});
In this example, we utilize BaseLoader's loadOne
function to fetch a single user by its ID.
This is especially important if you are using custom field resolvers. Custom field resolvers will be called many times as the graph is resolved. When using BaseLoader you are insuring this is as performant as possible.
Letβs look at what this custom field resolver would look like using the example from above:
@RelationshipField
decorator uses the BaseLoader functions underneath the hood. For more on this decorator see the decorators section.@ObjectType('Task')
export class Task extends GraphQLEntity<OrmTask> {
public dataEntity!: OrmTask;
...
@Field(() => User)
async user(@Root() task: Task) {
const user = await BaseLoaders.loadOne({
gqlEntityType: Task,
id: task.dataEntity.user.unwrap().id,
});
return User.fromBackendEntity(user);
}
}
LoadByRelatedId
The loadByRelatedId
function can be used in a similar way to the above loadOne
function. Yet, this function will return a collection of related entities.
Here's an example:
@Field(() => [Tasks])
async tasks(@Root() user: User) {
const tasks = await BaseLoaders.loadByRelatedId({
gqlEntityType: Task,
relatedField: 'userId',
id: user.id,
});
return tasks.map((task) => Task.fromBackendEntity(task));
}
In this case, we fetch an array of Task
entities related to a specific User
using the loadByRelatedId
function.