serdar_yegulalp
Senior Writer

How to get started with GraphQL

how-to
Jul 03, 20248 mins
APIsOpen SourceSoftware Development

GraphQL is a developer's tool of choice for developing efficient and evolvable APIs. Here's a first look at the tools and concepts that will help you get started.

Runners at the starting line
Credit: PeopleImages.com - Yuri A/Shutterstock

Developed by Facebook and released as an open standard for all to use, GraphQL is intended as an alternative to REST APIs. Like REST, GraphQL provides a way to create and consume web-based APIs, but queries and returned data use formal schemas and a type system to guarantee consistency.

In this article, we’ll walk through the basics of designing and implementing a GraphQL API and discuss many of the key considerations and decisions you’ll make during the process.

GraphQL languages and frameworks

If you’re planning to use GraphQL as your web application API, there is a very good chance the language and data components you’re already using will support your efforts. GraphQL libraries are available for almost every major language in production use. Clients are available for C#/.NET, Go, Java and Android, JavaScript, Swift/Objective-C, and Python, and the server libraries cover even more ground. 

If you’re starting entirely from scratch, you’re still best off picking whatever language, runtime, and data layer you’re most familiar with from other projects. Using GraphQL doesn’t impose many restrictions on the server or client, and it’s database-agnostic. However, you may need to perform more or less manual integration of your data layer depending on what that is. (More about this in the next section.)

We’ll use the Python implementation of GraphQL for reference in this article. The concepts and functionality will be more or less the same for other languages.

GraphQL’s data query schema

GraphQL takes in queries constructed from strongly typed fields in various hierarchical arrangements. The one part of creating a GraphQL API you need to give the most thought to is what schema to provide for queries.

In many cases, the query fields can be mapped one-to-one to an underlying data source, to expose all the relevant fields in the database (or other data source) for your queries. Because GraphQL queries can be considerably more open-ended and varied than their REST counterparts, you should plan from the beginning which fields can be queried and how those will map to your database.

For instance, if we have a database table for movies, with the fields title and year (as an integer), we could use a GraphQL query like this:


type Character {
    title: String!
    year: Int
}

The ! following String means a given field is mandatory, so we would need at least a title to perform this query.

You must also ensure that the fields you expose through GraphQL use types that correctly match the underlying data. For instance, GraphQL does not have a native “date” or “datetime” data type, in large part because of the sheer diversity of implementations available. If you want to allow searches by date ranges, you will need to enforce the formatting of the dates as taken in through the API, and also ensure that those date requests are translated into their proper counterparts for the back-end database when you query it.

Depending on the framework you’re using, this work might already have been done for you. Graphene, a popular GraphQL library for Python, provides ISO-8601 formatted date-time values as a type native, so you don’t have to wrangle that yourself.

If your data set has many fields, start by exposing the smallest functional subset of those fields that don’t require complex type enforcements—e.g., simple string or numerical queries. You can then gradually expand the available fields as you figure out how to implement queries for them through the GraphQL connector you’re using.

Storing and retrieving GraphQL data

Storing and retrieving data from your back end typically uses the middleware supported by the GraphQL library for your language.

In many cases, you can have GraphQL perform this work through data layers for common application frameworks. Python’s Graphene library for GraphQL, for instance, supports the Django web framework, along with Django’s built-in ORM. Graphene also supports the SQLAlchemy ORM and added support for the popular Starlette and FastAPI frameworks. It can also interoperate with Google App Engine’s data connectors, and the Relay JavaScript framework (used by React).

If you’re using a data layer that is not described by any of these components, you can use Graphene’s middleware and DataLoader objects to close the gap. These provide you with places to manually plug in the integration you need with your data layer. With DataLoader, you have a way to coalesce multiple, concurrent requests for related data and thus reduce the number of round-trips to your back end.

None of this, by the way, precludes you from performing caching yourself at any layer of the application. For instance, the responses you return could be cached by way of a proxy, while the back-end data could be cached using Memcached or Redis. That said, it would be your responsibility to make sure those caches are evicted whenever data changes.

GraphQL queries and mutations

GraphQL uses a specific query format, called a “mutation query,” to create, update, or delete elements from a data set. Give some thought to the way these queries will work—not just which queries you’ll allow and what fields you’ll require for them, but also what data you will return from the query following the mutation.

When you design a mutation query, you can allow the return of any number of output fields. That said, it’s probably not a good idea to nest response objects more than one or two layers deep, as that makes the results difficult to parse—both when looking at the query itself and when writing code to handle the results.

Another important caveat is not to let old REST API design habits dictate the way you organize your mutation queries. For instance, rather than create multiple mutation queries to handle different kinds of changes on the same object—a pattern common to REST — you could consolidate them into a single mutation query. One way to do that would be to use distinct, non-optional fields to record each possible operation, as per the “upvote/downvote” in this example.

Another would be to use a value field plus an enum type to describe the desired behavior with that value. One great advantage to an enum is it’s unambiguous: you can use it to reflect intent precisely, so it’s highly self-documenting. There’s a good chance your language’s GraphQL library will give you a way to use enums that’s consistent with the language’s own implementation of the concept. For instance, GraphQL enums in Graphene for Python can look a lot like Python’s standard library enum class.

GraphQL caching and performance acceleration

Underneath it all, a GraphQL query polls and retrieves data the same as any other query. That means it can be accelerated by many of the same methods used to speed up querying APIs:

  • Caching: Any service that has a database as a back end, or returns data from a front end, can benefit from caching on both ends. Keep in mind that the responsibility for expiring those caches falls to you, so you’ll probably have to use the GraphQL framework’s middleware hooks (like the ones described above for Graphene) to trigger such things. It’s recommended that you use unique identifiers whenever possible to support client-side caching. 
  • Cursors and pagination: A request should have some default upper limit for how many records it returns at once, to keep both the client and the server from being flooded. It also makes sense to allow clients to explicitly describe the maximum number of records to return, and which “page” of records to ask for. The official GraphQL documentation has some useful tips on how to integrate pagination metaphors into the GraphQL request format.

GraphQL tools

In addition to the libraries available for various languages, GraphQL has a slew of native and third-party tools to make it easier to develop clients, servers, schemas, and query processing layers:

  • Apollo GraphQL devotes its resources to creating open source tooling for GraphQL, including GraphQL clients and GraphQL servers. It also maintains GraphQL Tools, a set of utilities for generating and mocking GraphQL schemas and “stitching” multiple APIs into a single API—carrying out GraphQL’s stated mission of consolidating multiple API endpoints and making them more manageable.
  • If you’re looking at porting an existing Swagger-generated API to GraphQL, the Swagger2GraphQL tool was made for the job. It also allows side-by-side maintenance of a legacy Swagger-generated API, so you can use both standards during a transition period.
  • Finally, Facebook’s own GraphQL group has a few tools worth noting. GraphiQL is an in-browser IDE for creating GraphQL queries; it can be used internally or as a public-facing solution. There’s also a JavaScript implementation of GraphQL, a GraphQL-over-HTTP server and client suite, and a GraphQL Language Service for IDEs.
serdar_yegulalp
Senior Writer

Serdar Yegulalp is a senior writer at InfoWorld, covering software development and operations tools, machine learning, containerization, and reviews of products in those categories. Before joining InfoWorld, Serdar wrote for the original Windows Magazine, InformationWeek, the briefly resurrected Byte, and a slew of other publications. When he's not covering IT, he's writing SF and fantasy published under his own personal imprint, Infinimata Press.

More from this author