Companies and individuals use online services to connect with friends, offer a digital service, and do their job, all of which results in storing petabytes of data every day. In addition, giant tech companies like Twitter, Facebook, Google, and Netflix serve millions of users daily through their mobile, desktop, and web applications. They realized that current solutions could not serve their ever-growing userbase efficiently, so they started thinking about new ways of making users’ data available.
GraphQL is one of the most recent innovations from Facebook, an efficient way to make users’ data available to mobile, desktop, and web applications via API. At its core, GraphQL is a language to query graphs of data. The language comes with an official specification. In addition, there are plenty of GraphQL server frameworks that allow developers to build GraphQL APIs that are compatible with the language specification. In this article, we will review GraphQL API in detail and how it can be of help in solving today’s data problems. Technical challenges and limitations of the existing solutions pushed Facebook to come with new ideas about how apps should fetch data and use it.
Rest APIs are not efficient
Back in 2015, when Facebook announced GraphQL publicly, Rest APIs were the de-facto of the API world, and many companies, including Facebook, were using Restful APIs to make users’ data available to them. For example, a simple online shop had to send multiple HTTP requests to fetch the required data and display it.
As you may have noticed, the above works but has its’ own limitations, mainly:
-
Every HTTP request contains a network latency, the time it takes to reach the server. Therefore, more HTTP requests mean more time on network latency. As a result, the end-user has to wait longer for the data.
-
It’s very likely that the app does not use all of the received data but a portion of it. That said, it took some time for the API to prepare and send the unused data.
In the context of a giant company like Facebook, it meant that millions of users were experiencing slowness and a lot of pressure on Facebook’s database. With the introduction of HTTP 2 and concepts like content negotiation, things got slightly better, but the underlying problem was still there.
Efficient data retrieval via GraphQL
Conceptually, GraphQL API models the data it works with as a graph. The nodes in the graph itself are connected, and the type of their relation (parent-child, one to one, one to many, many to many) is clearly defined. As a result, consumers of a GrphQL API (mobile, web, desktop, or 3rd-parties) can easily ask what they need and receive only what they asked. Moreover, consumers can take advantage of the Graph concept and request data from different parts of the graph all within one single request to the GraphQL API.
In our online shop example, the mobile app can send one HTTP request to the GraphQL server and fetch discounted products and the user profile. Moreover, the app can decide what portion of the product data set it needs.
In the following two paragraphs, we go through GraphQL’s core concepts and the powerful typing system that GraphQL offers today and explore the ways GraphQL can help improve the experience of our bookshop users.
Core GraphQL concepts
So far, we have talked about GraphQL and how fetching data via GraphQL is efficient. That said, GraphQL is more than a way to fetch data. In this section, we go through some of the core concepts in GraphQL and how you can use them in your next project.
GraphQL Query Language
GraphQL’s query capabilities allow you to quickly fetch the data you need, combine multiple sets of data and request what you need. The below example shows how we can fetch an author’s profile.
{
authors(id: "2") {
id
name
books {
id
title
}
}
}
GraphQL mutations
Apart from query capabilities, GraphQL offers a simple and elegant way to change data called mutations
. Using GraphQL mutations, you can easily trigger add, update and delete actions on the server. The below example shows how an author can be added via GraphQL API.
mutation addAuthor {
addAuthor(name: "haruki murakami", website: "harukimurakami.com") {
id
name
website
}
}
Aliases
Using aliases, you can rename the field names in response to match your requirements. The below example shows how the profile of two different authors is fetched using aliases.
{
haruki: authors(website: "harukimurakami.com") {
id
name
website
}
orwell: authors(website: "orwellfoundation.com") {
id
name
website
}
}
The response to this request will look like this:
{
"data": {
"haruki": {
"id": "1",
"name": "Haruki Murakami",
"website": "harukimurakami.com"
},
"orwell": {
"id": "2",
"name": "George Orwell",
"website": "orwellfoundation.com"
}
}
}
Fragments
Fragments allow you to reuse a portion of a query that otherwise you have to repeat multiple times. In our previous example, we have repeated the id, name, and name twice. We can leverage fragments to fix this problem. The result will be identical.
{
haruki: authors(website: "harukimurakami.com") {
...authorProfile
}
orwell: authors(website: "orwellfoundation.com") {
...authorProfile
}
}
fragment authorProfile on Author {
id
name
website
}
Query Variables
GraphQL has the native support of variables. You can use variables to have dynamic queries. For example, let’s try to fetch an author’s profile using variables.
query authorProfile($id: ID!) {
authors(id: $id) {
id
name
email
}
}
GraphQL types
In the previous section, we briefly talked about modeling your data as a graph and represent it using GraphQL. This section will cover core types in GraphQL and how they help you model your data as a graph.
Object types
Object types are one of the core components of any GraphQL API. Using an Object type, you can model your data. For example, for a typical online bookshop, we could define the following object types for authors and books:
type Author {
id: ID!
name: String!
books: [Book!]!
}
type Book {
id: ID!
title: String!
isbn: String!
authors: [Author!]!
}
- An author has an id, name
- A book has id, title, and ISBN
- We have defined a “one to many” relationship between an author and books by adding the “books” field to the Author type
- We have defined a “one to many” relationship between a book and author(s) by adding the “authors” field to the Book type
Scalar types
As we mentioned earlier, in GraphQL, everything has a type. Object types allow us to model our data by supporting fields. Therefore, each field in a GraphQL API must have a type, either an Object type or scalar type. GraphQL Scalar Types allows us to define the type of the low-level fields. Out of the box, GraphQL APIs support Int, Float, String, Boolean, and ID. Moreover, depending on the GraphQL framework of your choice, you should be able to introduce custom scalar types like Date when needed.
Nullable types
By default, all of the GraphQL types are nullable, which means that a field may or may not have the expected value. Let’s take the following Author object type as an example:
type Author {
id: Int
name: String
}
The above type definition translates to:
- id is a nullable integer. The value of the field may be either “null” or an integer.
- name is a nullable String. The value of the field may be either “null” or string.
In reality, though, we know that authors all have a unique ID and a name, so we can add the ”!” sign at the end of each type to make them non-nullable.
type Author {
id: Int!
name: String!
}
Lists
GraphQL supports lists (arrays). Each list will have a type, either object type or scalar type. For example, the “books” field in the below example is a list of non-nullable books.
type Author {
id: ID!
name: String!
books: [Book!]!
}
Enumeration types
Using Enumeration types, you can define a type and possible values for that type. For example, the status of a book in our bookshop example can be either AVAILABLE, UPCOMING, or SOLD_OUT. The below code shows how we can define the “BookStatus” enumeration type and use it in our Book type.
enum BookStatus {
AVAILABLE
UPCOMING
SOLD_OUT
}
type Book {
id: ID!
title: String!
status: BookStatus!
}
Union Types
Using Union Types in GraphQL, a field can have more than one type. Union types are mostly for edge cases and not something you will need to use daily. In our bookshop example, let’s say we need to return search results, either an author or a book. We could do it using union types.
type Book {
id: ID!
title: String!
}
type Author {
id: ID!
name: String!
}
union SearchResult = Book | Author
Field arguments
Field arguments are one of GraphQL unique features. Using this feature, you can pass extra information to a field (at any level) to return value. In our bookshop example, we could tweak the “title” field of Book to accept a language. When provided, we could use this value to return the book title in the provided language.
enum Language {
ENGLISH
SPANISH
RUSSIAN
}
type Book {
id: ID!
title(lang: Language!): String!
status: BookStatus!
}
Input Types
Input types are a companion for Field arguments, and you can use Input types to pass a group of values as one argument. For our bookshop search, we could define a SearchQuery input type to accept multiple values under one argument:
input SearchQuery {
keywords: String!
pageIndex: Int
pageSize: Int
}
Interfaces
Interfaces allow you to define a set of object types with common fields. Our bookshop example could leverage GraphQL Interfaces to support paper books, ebooks, and audiobooks.
interface Book {
id: ID!
title: String!
}
type PaperBook implements Book {
# shared between all kinds of books
id: ID!
title: String!
# unique to Paper Books
isbn: String!
}
type EBook implements Book {
# shared between all kinds of books
id: ID!
title: String!
# unique to ebooks
ePubFile: String!
pdfFile: String!
}
type AudioBook implements Book {
# shared between all kinds of books
id: ID!
title: String!
# unique to audiobooks
steamLink: String!
}
type Author {
id: ID!
name: String!
# including an interface (Book)
books: [Book!]!
}
Top 5 benefits of GraphQL APIs
Although efficient data fetching is the most significant advantage of using GraphQL, some other great benefits, in this section, we cover some of GraphQL API advantages:
-
Batching data retrieval is probably the most significant advantage of using GraphQL. You no longer need to send multiple HTTP requests to fulfill the data requirements for your app, as GraphQL allows you to request various sets of data all in one request.
-
Thanks to the powerful query capabilities of GraphQL, you can fetch what you need. GraphQL allows consumers to define what subset of data (fields) they need, and it only returns the requested information.
-
Rest APIs are only accessible via HTTP, a convenient but not necessarily very efficient protocol. Unlike Restful APIs, GraphQL is transfer-protocol agnostic so that you can run a GraphQL API on both HTTP and other more efficient data exchange protocols.
-
GraphQL APIs are strongly typed. Therefore, to make data available via GraphQL, engineers should first define the shape of the data. As a result, GraphQL APIs are self-documented and easy to understand.
-
Thanks to the strongly-typed nature of GraphQL APIs, it’s virtually impossible to leak data in a GraphQL API accidentally as users are limited to fetch the explicitly defined data.
Top 3 GraphQL challenges
GraphQL’s novel approach to data fetching made it possible to solve many problems and offer great benefits. That said, this novel approach also introduced a new set of challenges that are worth knowing upfront.
-
It’s possible to fetch the entire data set of a company using a single GraphQL request. However, serving complex GraphQL queries may be costly and cause pressure on infrastructure. It’s important to monitor GraphQL queries and prevent complex queries. The good news is that many GraphQL server frameworks offer the building blocks to calculate the complexity of a GraphQL query and potentially limit it.
-
You cannot use standard HTTP caching techniques to cache GraphQL requests as HTTP-based GraphQL APIs are available via one endpoint, usually /graphql or /query, and consumers send a POST request to fetch data. As a result, standard HTTP caching techniques that rely on HTTP GET requests and URLs to cache data won’t work with GraphQL APIs. However, the GraphQL community has developed caching solutions for GraphQL APIs you can leverage to improve the performance of your API.
-
Handling errors in GraphQL is different from Rest as you no longer use HTTP Status Code to communicate operation results. Instead, GraphQL specification includes a section for returning errors to the users. That said, you can use many built-in GraphQL features to return errors to the consumers.
Testing GraphQL APIs
Almost all GraphQL APIs are available via HTTP protocol and return data in JSON format, so you should leverage your existing tools and techniques to test GraphQL APIs. If you haven’t read it already, we highly recommend having a read of the best API testing tools we wrote a while back. It compares some of the best API testing tools in the market, and most of them support GraphQL API testing.
Testfully supports testing GraphQL APIs, so you can easily leverage our platform for this purpose.
If your API testing tool does not support GraphQL but does support Restful APIs, you should be able to use it for testing a GraphQL API. When you want to query a GraphQL API, think of the API as an endpoint in a Restful API that only accepts HTTP POST requests. You can send a POST request and pass the following JSON object as a request payload:
query
field should contain your GraphQL query or mutation. This field is mandatory.variables
can also be passed when your query contains some variables.
We talked about how to test GraphQL APIs. In this section, we go through what you need to test.
-
Unlike Restful API endpoints, GraphQL API responses are not fixed. GraphQL returns what you have asked for, so it’s essential to test real-world queries. A real-world query is a query that users of the GraphQL API send.
-
Mutations are a big part of GraphQL APIs, so don’t forget to test those scenarios as well.
-
GraphQL APIs should support variables in queries. Try to send queries with variables to make sure this feature continues to work for your API.
-
Test unhappy paths as well. For example, try to fetch an entity that does not exist. Make sure GraphQL API gracefully handles the request and returns the expected error.
Top 10 GraphQL best practices
At Testfully, we have been building and supporting GraphQL APIs for some time, and throughout our journey, we have learned a couple of things that we would like to share with you as GraphQL best practices.
-
GraphQL is extendable, which means you can start small and expand your GraphQL API later. It’s both very easy and backward compatible to add a new field or type to your API. However, it’s considered a breaking change when you remove a field, so make sure you don’t introduce a new field or a new type unless you need it.
-
You should not use HTTP Status code to communicate about GraphQL errors. Remember, users, can combine multiple queries into one query and send it to the server.
-
GraphQL specification does not offer a great deal of information about how you should handle errors, so return errors so that it is easy for consumers of your GraphQL API to use it.
-
Leverage GraphQL enum types when values of a field are finite and known
-
If a field cannot contain null, make sure to set it as non-nullable. Non-nullable fields make it easier for developers to use your GraphQL API.
-
Union types and interfaces can make your GraphQL API complicated. You should use them only when required.
-
Do not remove any fields from your types as it may break existing users of your API. Instead, flag it as
deprecated.
-
Pick short and self-documented names for your object types
-
When building your GraphQL API, we highly recommend you to think upfront about your caching strategy, query complexity limits, and batching queries to the upstream sources (e.g., databases) using data loaders.
-
When building GraphQL APIs, start thinking in graphs.
Top 5 free GraphQL clients/IDEs
As we talked about earlier, due to their strongly typed nature, GraphQL APIs are all self-documented. Using a GraphQL client allows you to explore available types to query and mutate quickly.
-
Most GraphQL APIs come with a web-based client to explore the API. They’re usually available under
/graphql
or/playground
URLs. You can use the bundled client to test a GraphQL API without installing any extra software on your computer. Have a look at Rick & Morty GraphQL API for an example of GraphQL playground. -
If you prefer a desktop application, Insomina is your best bet. Using Insomina, you can easily explore types for a GraphQL API, send requests and review the result.
-
GraphiQL is another IDE for GraphQL APIs. It doesn’t offer the fanciest UI.
-
Postman also supports GraphQL APIs, so you can easily use them to send requests. If you’re a Postman user looking for a change, we highly recommend our Top 5 Postman alternatives article.
-
You can use Apollo GraphQL Studio Sandbox to explore and play with any GraphQL API.
-
Hoppscotch is a free, open source and web-based HTTP client that supports GraphQL as well. You don’t need to sign up to use Hoppscotch.
GraphQL APIs to play with
To better understand GraphQL APIs and how they tackle problems, we have put together four free GraphQL APIs you can play with to understand GraphQL better.
Useful resources
We have put together a list of resources to help you get on board with GraphQL API. Whether you’re a user of GraphQL or planning to build a GraphQL API, there should be something in this list for you.
- graphql.org is the official website. Explore this website to learn about GraphQL and more.
- Apollo Blog is a great place to learn more about GraphQL and best practices. The team at Apollo GraphQL publishes regular content related to front-end, back-end and devops.
- For a weekly newsletter dedicated to GraphQL, head to GraphQL Weekly
- GraphQL in Medium is a good place to find quality content from independent publishers and bloggers related to GraphQL.
Concusion
In this article, we went through the problems that GraphQL attempts to solve, what benefits we get and what new challenges GraphQL introduces. First, it’s essential to acknowledge that GraphQL is not a silver bullet by any means and like any other technology, GraphQL comes with limitations.
Frequently Asked Questions
We got an answer for your questions
-
What’s the difference between GraphQL unions and GraphQL interfaces?
Both GraphQL union and interface types allow a field to have more than one type. However, unioned types do not need to have fields in common, while types that implement an interface must have the common fields defined by the interface.
-
is GraphQL a database?
No, GraphQL is a language to query data. The data itself may be stored in a database, disk, or fetched via other services. GraphQL offers a way to query data that is not coupled with the way the data is stored.
-
What is the difference between GraphQL and SQL?
Both GraphQL and SQL are query languages. While SQL is a query language for querying relational databases, GraphQL is a query language for data graphs.