How to Filter Using GraphQL: A Simple Tutorial
APIs are the most common way of communicating with both the back and front ends of today's applications. These programming interfaces allow developers to provide a simple solution to make data available for whomever or whatever may need it. There are two popular types of APIs: REST and GraphQL. We're going to focus on the second one—more specifically, how to do GraphQL filtering.
In technology, new methods and concepts are constantly emerging. Each has its advantages and disadvantages. Developed by Facebook, GraphQL offers a much more efficient, powerful alternative to REST. With no data issues, GraphQL allows you to perform declarative lookups, where a client specifies exactly what data it needs from the API. So now instead of having multiple endpoints, GraphQL exposes just one. Also, it efficiently and accurately responds to the requested data. Let's start to get into the details.
How Does GraphQL Filtering Work?
GraphQL is a query language for APIs. You can use a large number of programming languages to implement it. There are two main parts: The client and the server. You can choose between some of the solutions available. But we're going to focus on the Apollo Server and Apollo Client when taking a closer look at our GraphQL filtering examples.
Reasons to Use GraphQL
Let's examine these one by one.
- Network Performance: GraphQL is ideal for when you want to increase network performance by sending less data or only necessary and relevant information to clients.
- The Project Choice "Include Requisition X Additional Endpoints:" The most difficult choice when developing API projects is whether to include the request or create an additional endpoint. But with GraphQL, this problem is solved because it relies on the schema and resolvers functions. That way, the client has control of the data that should be returned.
- Managing Different Types of Clients: Imagine you have an API, and all your clients (iOS apps, Android apps, web apps, and so on) are completely different. Each needs a totally different structure or a different amount of data returned from the server. With the REST approach, you can create a separate API. In contrast, with GraphQL, you don't need a separate API because you can have everything returned from a single endpoint.
A Real-World Example of GraphQL Filtering
One of the main problems developers face when using REST APIs is that you can get either more or less information than your front-end application actually needs. We commonly use the terms overfetching and underfetching to describe these situations.
In contrast, when you write and use a GraphQL query, the application can get exactly the required fields. That’s one of the main advantages. After all, you don’t want to spend more resources than you actually need to.
Let’s dive into a simple example to demonstrate how filtering actually works on the server side. Consider the following GraphQL schema:
type Movie {
id: ID!
title: String
year: Int
director: Director
}
type Query {
movie(id: ID!) : Movie
}
Now we've defined the Movie type and a type named Query to allow us to fetch the data about a Movie by providing an id. So the movie field expects an id of the type ID and returns the data about the Movie. In this case, we're allowing the application to filter a specific item.
How could we fetch the data? It's pretty simple—just take a look at the code below:
query getMovieById {
movie (id: "9") {
title
year
}
}
It's important to understand that each field in GraphQL has a Resolver function. For example, from the getMovieById query, a resolver function could be generated so that if the client called this query, its API would return a response—the Movies JSON in this case. This behavior is done in a Resolver function. The resolver for the Movie field would look like this:
const resolvers = {
Query: {
movie(parent, args, context, info) {
return movies.find(movie => movie.id === movie.id);
}
}
}
You may notice that the resolver can take some arguments that are optional. Let's talk a little about each of them:
- Parent: the result (or "resolution") of the "parent" of the type that the current function will resolve
- Args: the input parameters that the client sent
- Context: an object that the GraphQL implementation provides to resolvers. The context can contain authentication or authorization data, or it can have references to external APIs, for example.
- Info: an object that contains information relevant to resolving the type (not commonly used)
Going Further
What if we need to query a list of movies and then filter it? Let’s return to the Query type and add a new field:
type Query {
movie(id: ID!) : Movie
movies(director: Director) : [Movie]!
}
So now we can get a list of movies with the option of filtering by the director. Notice that filtering is optional in this case. The query would look like this:
query GetMoviesByDirector{
movies(director: “John Doe”) {
title
year
}
}
And in the resolver, the difference is that now we return the data using the filter function instead of find because now it’s a list of movies.
Complex Filtering
You can also use what's called Input Type. This contains all the GraphQL filter options that are necessary. So instead of creating multiple fields for filtering, we can have all the filters inside just one type. Not clear? Take a look at the example below:
type MovieFilters = {
ids: [ID!]
director: Director
}
type MoviesInput = {
filter: MovieFilters
}
type Query {
movie(id: ID!) : Movie
movies(input: MoviesInput) : [Movie]!
}
After that, just change the logic of the resolver. Of course, it gets a little more complex now. That's because instead of having just a single type of GraphQL filter, the resolver needs to deal with the different types and return the results for each one. It may seem like a much more complex task, but it isn't. Using JavaScript, just identify the type of GraphQL filter to be used. (This GraphQL filter will be passed in the args parameter.) Now we can filter both movies using ids and return a list of movies using the director as a filter.
At the End of the Day
By adopting GraphQL in your applications, you'll have a slightly slower learning curve at first. But quickly the added value of GraphQL stands out. The back-end and front-end development become more agile and dynamic. And you'll have fewer round-trips. There are also lots of examples and cases to use as models.
The biggest difficulty of GraphQL is not in its implementation and use but in its design. It doesn't have the design issues that a REST application has, but it nonetheless brings new challenges. There's still no widespread consensus on design patterns with GraphQL. There's a quality and versatility of GraphQL compared to REST solutions.
In this article, we focused on one main point. However, GraphQL still provides a lot of tools that, if used correctly, can make your API extremely efficient and save time and resources in development. Imagine the complexity of a front end having to access several different APIs to get information. In a scenario like that, GraphQL works very well.
Visit Traceable AI for more information on this and other issues. You can check out webinars or view a demo. There's also a helpful blog.
This post was written by Rhuan Souza. A software engineer who has experience with infrastructure, Rhuan is currently working as a full-stack web developer. He’s a passionate developer who focuses not only on code, but also wants to help change processes and make people's lives easier.
The Inside Trace
Subscribe for expert insights on application security.