How to use GraphQL variables to give queries type safety

Illustrated graphic with a GraphQL logo
Published
October 22, 2021
Category

Guides

One of the things I love about GraphQL is how straightforward it is to get up and running with little to no experience. Using a browser-based GraphiQL interface — such as the GraphiQL explorer provided by Contentful — you can inspect your schema right there in the browser, and construct your queries in no time. But how can you make sure your GraphQL queries are safe from nasties? Let’s find out.

To inspect your schema in Contentful’s GraphiQL interface and construct a GraphQL query, enter this URL in your browser, and swap out the SPACE_ID for your Contentful space ID, and ACCESS_TOKEN for your Contentful Delivery API Key.

Make an HTTP POST request with your programming language of choice — and boom — you’ve got data.

This is an example of a query that we can use to request data from a single blog post by slug. Notice how we’re using a where clause to filter the items by a slug that matches a string we supply.

And here’s the data we get back.

Screenshot of HTTP POST data request return

Here’s how we can make the same request using JavaScript fetch (and no external dependencies!).

All of this is great, and perfectly valid GraphQL. And, if you’re using a static site generator such as Next.js, Gatsby or Nuxt which will pre-render your pages at build-time and serve static pages to the client, you should be good to go. I’d been doing this for months using Contentful’s GraphQL API to fetch my data to power my personal website built with Next.js. 

However, whilst queries like this are super-fast to write and get your projects out fast — what if you’re making GraphQL queries dynamically on the client and not as part of a static site build? What if someone could play around with your data in real-time by inserting an incorrect data type, a GraphQL mutation or similar instead of a string? 

Here’s where GraphQL variables save the day!

It’s worth mentioning that because the Contentful GraphQL API is read-only, this kind of scenario won’t happen — but security considerations are always good to bear in mind regardless. Let’s take a look!

Use GraphQL variables for type safety and self-documenting queries

GraphQL variables offer an extra layer of protection in your queries, namely type safety — meaning that a query will only accept dynamic variables of certain data types, such as String, Int (number), DateTime and so on. And what’s more, there isn’t much more work needed to make your GraphQL queries safer!

To use variables in your GraphQL queries:

  1. Create what looks like a traditional function prefaced by the word query. You can name this query function whatever you like. I’ve named mine GetBlogPostBySlug.

  2. Inside the parentheses of the function declaration, name and define the types of the variables the query will accept, and prefix your variable names with a $. The query below will accept a variable named $slug, which is of type String. The bang or exclamation mark that comes after the type name means that it is a required variable for the query to execute.

  3. In an HTTP POST request to the GraphQL API, variables are passed to the GraphQL request as a separate property inside the body of the request. Click on the query variables pane at the bottom of the GraphiQL explorer. Create an object, and add your stringified variable name and value as “key”: “value” (it’s important to stringify the key name here!).

Screenshot of the query returned making GraphQL variables safer

Let’s look at an example of using GraphQL variables using JavaScript fetch. Notice how we have replaced the original query with the function-style query from above, and have created a variable named variables that we pass into the body of the HTTP request.

And that’s how I learned to make my GraphQL queries type-safe and free from nasty attacks on dynamic API calls! 


Going further with more types

There are a variety of different variable data types available on Contentful’s GraphQL API. As well as the standard data types such as String, Int and DateTime, you can also pass variables to a query that are entry-specific and API-specific.

To inspect the types available on your schema, click on the Docs links at the top right of the GraphiQL explorer:

Screenshot of the query return when inspecting types available in schema

Click on Query:

Screenshot of clickable query

And find the content type you’d like to inspect.

Screenshot of how to find content type to inspect

Another thing I learned on this journey is that you can’t use variables in GraphQL for everything — namely keys in WHERE clauses.

I recently created a GraphQL query to fetch the events on my website. On the main events page, I wanted to show future events in ascending order, and on the past events page, events in descending order.

The two supported variables involved in this query are:

  • $order — date_ASC or date_DESC

  • $date — as an ISO string

But I also needed a third dynamic variable — which was to control whether the API returned events before (date_lt — date less than) or after (date_gt — date greater than) a particular date. Unfortunately, this part of a GraphQL query cannot be controlled with a variable, and so I had to be creative and pass in a calculated string to the query like so:

One other thing to notice is that the $order variable is of type EventOrder, which we saw when we inspected the schema above, which is an API and entry-specific type!

So there you have it. Fancy and safe GraphQL queries, so you can build great stuff with the Contentful GraphQL API without worrying. You can check out the code on GitHub for the full range of queries I make with GraphQL on my website, and if you’re curious about GraphQL and want to learn more, you can learn along with Stefan Judis’ React and GraphQL video course in our developer portal. Happy querying, friends!

About the author

Don't miss the latest

Get updates in your inbox
Discover new insights from the Contentful developer community each month.
add-circle arrow-right remove style-two-pin-marker subtract-circle remove