Designing Powerful APIs with GraphQL Query Parameters
GraphQL queries provide an efficient way to fetch data, even across multiple models. This results in a great abstraction layer on top of databases, but sometimes more is needed to satify specific data requirements of modern applications.
Our GraphQL API puts the client in control of the data and provides the best possible developer experience (DX) by exposing different query arguments. Similar to our nested mutations syntax which sees adoption by more and more companies, we at Graphcool are happy to share our best practices designing powerful GraphQL APIs with the GraphQL community.
This tutorial explores some of the capabilities of our GraphQL APIs including:
- Filters: Filters nodes by applying one or many matching rules.
- Sorting: Orders the set of results ascending or descending by a field.
- Pagination: Groups nodes in different pages that can be seeked, either forwards or backwards.
Filters reduce client complexity
Often you are interested to query specific parts of your data. In a movie database for example, you might search movies that are released after a certain date or have a specific title. While you can always query all movies and filter them client side, this would result in unnecessary data - something that GraphQL is set out to avoid.
This is a great use case for GraphQL query arguments! By adding a
filter parameter to a query, the above scenario can quickly be solved. If you are interested in movies with the title "The Dark Knight", you only have to specify the
title field on
Filtering by title works great for fetching single movies. In fact, the filter system is much more powerful than that, as it is encoding a boolean algebra. This allows a great level of expressiveness based on logical operators.
You can combine filter conditions using the
AND operators to select multiple movies you are interested in. For example, if you are interested in the movie "Inception" and additionally in movies released after 2009 that have a title starting with "The Dark Knight", you can combine the two conditions with
By providing the
filter query argument, the server is doing the heavy lifting while the client stays in full control over its data requirements. This results in a clear and expressive API and separates concerns between the frontend and the backend.
Expressing even complex data requirements
Another typical requirement is sorting data - again something that is better handled by the server than the client. Let's combine sorting data with filters!
This time we're interested in actors that appeared in movies released since 2009. The
filter argument is a powerful system for requests like that. We can use
movies_some with a nested
releaseDate_gte: "2009", meaning that we are only interested in actors where some of their movies fulfill the nested conditions.
On top of that, we are sorting the actors ascending by name with
Combining filter and order parameters like that allows you to easily express even complex data requirements. We could also use
movies_all to express that no or all movies of an actor fulfill certain conditions.
If you look closely, you can also find the
first: 3 argument in the above query. Let's see what this is about.
Browsing data in equally sized pages
Imagine a website that lists movies and their actors. Your data might contain thousands of movies each with dozens of actors. A typical scenario is then to only display a few movies at the same time, allowing the user to seek forwards and backwards through the whole list.
What you can do instead of fetching all movies at once in this case is to mirror the representation parameters in your query and only fetch the data you currently need. Again, this simplifies the needed client logic a lot while also reducing transmitted data. This approach is called offset-based pagination. An even more advanced pagination variant is the cursor-based pagination that is also available by combining
before. Here we are focusing on offset-based pagination though.
The pagination arguments integrate seamlessly with filtering and ordering. This way, we end up with a simple query that fulfills a very complex request. Let's have a look at how we can apply all what we've learned so far in the following query. We display the first two movies that are released since 2000, order them by their release date and sort their actors by name. But see for yourself:
You can experiment with the available query variables to see what effect they have. For example, you can change the
title_DESC and run the query again. This returns the second page of movies sorted descending by title.
Our carefully designed GraphQL APIs offer great flexibility and control for client applications. With different rules to filter, sort and paginate your data, you can exactly express the data you are interested in and let the backend figure out the rest.