If you have any project questions, concerns, or contribution ideas, join our #pwa Slack channel. Find out how to create an account by visiting Community Resources

What is GraphQL

GraphQL is a language for querying and manipulating data. It is widely viewed as more powerful, flexible, and efficient than REST.

Benefits provided by GraphQL

Predictable results from your queries

A GraphQL query returns only data the user asks for in their query.

Single request for many results

A single request made through GraphQL can return any number of resources and their fields by following references between them as defined in the typed schema.

Organized data with a typed schema

A single schema defines how users access data using GraphQL. These schemas, formatted as JSON objects, let users know exactly how to get the data they need.

The following is an example of a schema that defines a Species type with name and origin fields:

type Species {
  name: String
  origin: Planet
}
type Planet {
  name: String
}

Note: The origin field is a Planet type, which also has a name field.

Why use GraphQL over REST

While GraphQL and REST are both specifications for constructing and querying APIs, GraphQL has some significant advantages over REST.

No versioning

REST APIs typically have multiple versions, such as v1, v2, etc. This is because updating endpoints in REST will often impact existing queries.

With GraphQL, there is no need for versioning, since new types and fields can be added to the schema without impacting existing queries.

Removing fields is done through deprecation instead of deleting them from the schema. If an old query tries to read a deprecated field, GraphQL displays a customized warning.

type ExampleType {
  firstName: String
  lastName: String
  name: String @deprecated(reason: "Split this field into two. Use `firstName` and `lastName`")
}

This prevents old queries from throwing confusing errors when trying to read outdated fields, lending to code maintainability.

Faster and more efficient

REST APIs typically require loading from multiple URLs. Imagine a REST API designed to get users and their forum posts. users/<id> would return information like name and user/<id>/posts would have to be queried separately to return the user’s comments.

With GraphQL, these types and their fields are returned using one query, which saves calls to the API.

In the following schema example, a User type contains a posts field, which is an array of Post types:

type Query {
  user(id: Int): User
  # This is our resolver; our entry into the query
  # It lets us query `user` with an argument `id`
  # And Expects to return a type `User`
  # Yes, you can leave comments in schemas!
}

type User {
  id: Int!
  name: String
  posts: [Post]
}

type Post {
  id: Int!
  title: String
  author: User
}

Note: The exclamation mark (!) next to a field in the schema indicates it is non-nullable, which means the GraphQL service promises to always return a value for this field on a query.

A query for this schema that requests the name and all the post titles for a specific user would look like the following:

{
 user(id: 12345) {
   name
   posts {
     title
   }
 }
}

The data response for the query would look like the following:

{
  "data": {
    "user": {
      "name":  "Jane Doe"
      "posts": [
         {
           title: "Hello World"
         },
         {
           title: "I Love GraphQL"
         }
      ]
    }
  }
}

Sample queries

Simple query

Imagine a database that simply contains an object User, with the fields name, email, and phone.

type Query {
  user: User
}

type User {
  name: String
  email: String
  phone: String
}

A simple query requesting this data would look like the following:

 {
  user {
    name
    email
    phone
  }
 }

The response to this query would look like the following:

{
  "data": {
    "user": {
      "name":  "Jane Doe"
      "email": "JaneDoe@example.com"
      "phone": "012-345-6789"
    }
  }
}

Custom data query

What if you don’t need the phone number from User? The previous query can be rewritten to return specific fields:

{
  user {
    name
    email
  }
}

The response only provides the data requested:

{
  "data": {
    "user": {
      "name":  "Jane Doe"
      "email": "JaneDoe@example.com"
    }
  }
}

Arguments in a query

Now, what if you had multiple users and needed to grab a specific one using its id? Well, with GraphQL you can pass arguments into the query:

{
 user(id: 12345) {
   id
   name
   email
 }
}

The response would look like the following:

{
  "data": {
    "user": {
      "id": "12345"
      "name": "Jane Doe"
      "email": "JaneDoe@example.com"
    }
  }
} 

Note: The id field is requested in the response in this example, but this is optional. It is used here to demonstrate that the correct user is returned.

Query connected resources

In this example, imagine that in our database a User is associated with multiple hobbies. The schema would look like the following:

type Query {
  user: User
}

type User {
  name: String
  email: String
  phone: String
  hobbies: [Hobby]
}

type Hobby {
  name: String
  frequency: String
}

The following query requests the hobbies associated with a specific user:

{
 user(id: 12345) {
   name
   email
   phone
   hobbies {
     name
     frequency
   }
 }
}

The response would look like the following:

{
  "data": {
    "user": {
      "name":  "Jane Doe"
      "email": "JaneDoe@example.com"
      "phone": "012-345-6789"
      "hobbies": [
        {
          "name": "painting",
          "frequency": "weekly"
        },
        {
          "name": "video games",
          "frequency": "daily"
        }
      ]
    }
  }
}

Notice how the user’s hobbies are returned in an array as defined in the schema.

Learn more

This topic just covers the basics of GraphQL. To learn more, visit the GraphQL website.