DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workkloads.

Secure your stack and shape the future! Help dev teams across the globe navigate their software supply chain security challenges.

Releasing software shouldn't be stressful or risky. Learn how to leverage progressive delivery techniques to ensure safer deployments.

Avoid machine learning mistakes and boost model performance! Discover key ML patterns, anti-patterns, data strategies, and more.

  1. DZone
  2. Refcards
  3. GraphQL Essentials
refcard cover
Refcard #249

GraphQL Essentials

Declarative Data Fetching Over a Single API

As an alternative to REST, GraphQL is quickly gaining popularity as a tool for building APIs and fetching declarative data. This Refcard introduces GraphQL concepts such as core design principles, schemas and types, fields, arguments, and lastly, how to secure your GraphQL APIs.

Download Refcard
Free PDF for Easy Reference
refcard cover

Written By

author avatar Stephen Barlow
Documentation Lead, Apollo GraphQL
Table of Contents
► Introduction ► The Evolution of GraphQL ► Fundamentals of GraphQL ► GraphQL Queries and Mutations ► ► Conclusion
Section 1

Introduction

GraphQL is a language-independent specification for client-server communication. Its declarative query language enables application clients to specify which back-end data to fetch, without worrying about how that data is populated. A GraphQL server receives queries from clients and fulfils them by populating requested fields with back-end data from arbitrarily many sources (such as relational databases and REST APIs). 

Section 2

The Evolution of GraphQL

In 2012, Facebook’s native mobile apps for iOS and Android were thin wrappers around the views of their mobile website. These apps often crashed when making multiple simultaneous REST API calls. To resolve this issue, Facebook overhauled their infrastructure to enable their apps to fetch multiple types of data with a single API call. This solution paved the way for the GraphQL specification, which Facebook first released publicly in 2015. Today, GraphQL powers almost all of Facebook’s data fetching and is used in production by organizations such as IBM, Walmart, Netflix, The New York Times, Intuit, GitHub, and Airbnb. 

Benefits of GraphQL

Benefit Description
Suitable for complex systems and microservices GraphQL unifies multiple systems behind a single API, thus masking the complexity of those systems from clients.  
Data fetching with a single API call GraphQL is typically served over HTTP via a single endpoint that expresses the full set of a platform’s capabilities. 
Autogenerating API documentation A GraphQL API is tightly coupled with code, so documentation can change automatically as schema types and fields change. 
Versionless API evolution GraphQL eliminates the need for versioning by deprecating API functionality at the field level. Unused fields can be removed from the schema without affecting active queries.
Shared query logic (fragments) GraphQL fragments are units of query logic that can be shared across multiple queries. 
Elimination of over-fetching and under-fetching  GraphQL enables front-end applications to fetch exactly the data they need, when they need it. 
Section 3

Fundamentals of GraphQL

Design Principles

GraphQL offers some guidelines for how to think about a service:

Principle Description
Product-centric GraphQL is driven by the data needs of the client, the language, and the runtime that supports the client. 
Client-specific queries A GraphQL server provides the capabilities that clients can consume. 
Strong typing A GraphQL server is backed by the GraphQL type system. In the schema, each field has a specific type against which it’s validated. 
Hierarchical A GraphQL schema is hierarchical: Fields are nested within other fields, and queries have the same shape as the data they return. 
Introspective The client can query the GraphQL server’s type system. 

Schemas and Types 

In GraphQL, a schema defines a collection of types and the relationships between those types. These types and relationships together define the extent of a unified graph. Clients execute queries against this graph to fetch the data they need. The GraphQL schema language, also called the GraphQL Interface Description Language (IDL), is used to define a schema and types. 

Type DESCRIPTION Example
Object types

An object type that can be fetched, including the fields it provides 

For example, Movie is an object type with fields title, year, genres, and plot. [Movie] indicates a list of Movie objects, and ! indicates a non-nullable field. 

 
1
type Movie { 
2
id: ID! 
3
title: String 
4
year: Int 
5
plot: String 
6
poster: String 
7
genres: [String] 
8
similar: [Movie] 
9
rating: RATING 
10
actors: [Actor] 
11
series: [Series] 
12
avgStars: Float 
13
} 
Scalar types 

Common primitive types 

The GraphQL specification includes the built-in scalars Int, Float, String, Boolean, and ID (serialized as a string and can be human-readable). Schemas can also define custom scalars, such as the commonly defined Date. 

 
1
1
title: String 
Query type

Defines read-only entry points into a graph 

The Query type defines the top-level fields that are available to clients executing queries. A schema has exactly one Query type. 
 
5
1
type Query { 
2
moviesByTitle(title: 
3
String!, limit: Int= 
4
3): [Movie] 
5
} 


Mutation type

Defines write entry points into a graph 

The Mutation type defines the top-level fields that are available to clients executing mutations. A schema can have exactly one Mutation type

 
4
1
type Mutation { 
2
reviewMovie(review: 
3
ReviewInput):UserReview 
4
} 


Enumeration types 

A type of scalar restricted to a set of pre-defined values 

 
6
1
enum RATING { 
2
G 
3
PG 
4
PG13 
5
R 
6
}

Interface types 

Abstract type that defines a set of fields that object types can implement 

Interface types are used when a field might return one of multiple related types. 

 
4
1
interface Person { 
2
id: ID! 
3
name: String 
4
} 
Input types Used to pass complex objects as arguments to a field 
 
5
1
input ReviewInput { 
2
rating: Int! 
3
movieId: ID! 
4
userId: ID! 
5
} 
Union types 

Abstract type that defines a set of object types that all might be returned by a particular field  

Unlike interface types, members of a union type don't need to define any common fields. 

 
2
1
union PersonResult = 
2
User | Actor 
Section 4

GraphQL Queries and Mutations

The fields of the Query and Mutation types are the entry points into a graph. .

Fields

Each type is composed of one or more fields, which can be scalar values or complex objects that refer to other types, resulting in nesting. Each GraphQL query specifies which schema fields to return. This is referred to as the query’s selection set. 

Consider the following schema excerpt: 

Java
 
16
1
type Query { 
2
  topRatedMovies: [Movie] 
3
} 
4
type Movie { 
5
  id: ID! 
6
  title: String 
7
  year: Int 
8
  plot: String 
9
  poster: String 
10
  imdbRating: Float 
11
  genres: [String] 
12
  similar(limit: Int = 3): [Movie] 
13
  rating: RATING 
14
  actors: [Actor] 
15
  avgStars: Float 
16
} 

 

Here is a valid query against that schema: 

Java
 
7
1
{ 
2
  topRatedMovies { 
3
    title 
4
    year 
5
    avgStars 
6
  } 
7
}

 

And here is an example result of that query:

Java
 
21
1
{ 
2
  "data": { 
3
    "topRatedMovies": [ 
4
      { 
5
        "title": "Godfather, The", 
6
        "year": 1972, 
7
        "avgStars": 4.4875 
8
      }, 
9
      { 
10
        "title": "Shawshank Redemption, The", 
11
        "year": 1994, 
12
        "avgStars": 4.487138263665597 
13
      }, 
14
      { 
15
        "title": "On the Waterfront", 
16
        "year": 1954, 
17
        "avgStars": 4.448275862068966 
18
      } 
19
    ] 
20
  } 
21
} 

 

Arguments

Schema fields can accept arguments, which can be required or optional. Each argument can optionally have a default value if one isn’t provided. 

The following Query.moviesByTitle field accepts two arguments. The limit argument specifies a default value: 

Java
 
3
1
type Query { 
2
  moviesByTitle(title: String!, limit: Int = 3): [Movie] 
3
} 


 Here is an example query that provides the required title argument:

Java
 
9
1
{ 
2
  moviesByTitle(title: "Matrix Reloaded") { 
3
    title 
4
    similar(limit: 1) { 
5
      title 
6
      year 
7
    } 
8
  } 
9
} 

 

And here is an example result:

Java
 
15
1
{ 
2
  "data": { 
3
    "moviesByTitle": [ 
4
      { 
5
        "title": "Matrix Reloaded, The", 
6
        "similar": [ 
7
          { 
8
            "title": "Matrix, The", 
9
            "year": 1999 
10
          } 
11
        ] 
12
      } 
13
    ] 
14
  } 
15
} 


Variables 

GraphQL variables enable you to provide values for arguments without hardcoding their values directly into a query string. This helps prevent injection attacks that use string interpolation to build queries from user-supplied content. To use variables, first declare $varName as a valid variable for the query, then replace the value in the query with $varName. Finally, pass the key-value pair varName: value in a dictionary alongside the query. 

Here’s an example query with two variables: 

Java
 
9
1
query MoviesByTitle($movieTitle: String!, $similarLimit: Int) { 
2
  moviesByTitle(title: $movieTitle) { 
3
    title 
4
    similar(limit: $similarLimit) { 
5
      title 
6
      year 
7
    } 
8
  } 
9
} 


And here’s a variables object that’s provided alongside that query: 

 
21
1
{ 
2
  "movieTitle": "Matrix Reloaded", 
3
  "similarLimit": 1 
4
} 
5
 
6
Result: 
7
{ 
8
  "data": { 
9
    "moviesByTitle": [ 
10
      { 
11
        "title": "Matrix Reloaded, The", 
12
        "similar": [ 
13
          { 
14
            "title": "Matrix, The", 
15
            "year": 1999 
16
          } 
17
        ] 
18
      } 
19
    ] 
20
  } 
21
}


Mutations 

While queries enable you to read back-end data, GraphQL mutations enable you to create, update, and delete that data. To enable mutations, a schema defines a Mutation type. The fields of this type are entry points that correspond to different write operations that clients can execute. 

Consider a UserReview type: 

Java
 
5
1
type UserReview { 
2
  user: User 
3
  rating: Int 
4
  movie: Movie 
5
}


To create a new UserReview, a schema might define this Mutation field: 

Java
 
3
1
type Mutation { 
2
  createReview(userId: ID!, movieId: ID!, rating: Int): UserReview 
3
} 


Note that the mutation returns a UserReview object. This means that you can access any of the fields available on Movie and User (in a nested fashion): 

Mutation:

 
14
1
mutation { 
2
  createReview(userId: "20", movieId: "16", rating: 5) { 
3
    movie { 
4
      title 
5
      similar(limit: 2) { 
6
        title 
7
      } 
8
    } 
9
    user { 
10
      name 
11
    } 
12
    rating 
13
  } 
14
} 

 

Result: 

 
21
1
{ 
2
  "data": { 
3
    "createReview": { 
4
      "movie": { 
5
        "title": "Casino", 
6
        "similar": [ 
7
          { 
8
            "title": "Four Brothers" 
9
          }, 
10
          { 
11
            "title": "Night and the City" 
12
          } 
13
        ] 
14
      }, 
15
      "user": { 
16
        "name": "Nicole Ramsey" 
17
      }, 
18
      "rating": 5 
19
    } 
20
  } 
21
} 


Input Types  

In the previous mutation example, three individual primitive arguments were passed to the createReview field. Instead, this field could accept a single input type that includes all of those individual primitive values as fields. Input types are especially useful for mutations where the goal is to pass an update as a single object. 

Input type: 

 
5
1
input ReviewInput { 
2
  rating: Int! 
3
  movieId: ID! 
4
  userId: ID! 
5
} 


Then modify the createReview field to accept one argument of type ReviewInput: 

 
3
1
type Mutation { 
2
  createReview(review: ReviewInput!): UserReview 
3
} 


The mutation becomes: 

 
11
1
mutation CreateReviewForMovie($review: ReviewInput) { 
2
  createReview(review: $review) { 
3
    movie { 
4
      title 
5
    } 
6
    user { 
7
      name 
8
    } 
9
    rating 
10
  } 
11
} 


Variables: 

 
7
1
{ 
2
  "review": { 
3
    "movieId": "16", 
4
    "userId": "20", 
5
    "rating": 5 
6
  } 
7
} 


Results: 

 
13
1
{ 
2
  "data": { 
3
    "createReview": { 
4
      "movie": { 
5
        "title": "Casino" 
6
      }, 
7
      "user": { 
8
        "name": "Nicole Ramsey" 
9
      }, 
10
      "rating": 5 
11
    } 
12
  } 
13
} 


Fragments  

A fragment is a reusable set of fields that can be defined and referenced by name in multiple GraphQL queries. This enables you to factor out common logic and reduce repetition in operations. To apply a fragment inside a query, use a fragment spread operator (...) inside the selection set: 

 
10
1
{ 
2
  moviesByTitle(title: "Matrix Reloaded") { 
3
    ...movieSummaryFields 
4
  } 
5
} 
6
fragment movieSummaryFields on Movie { 
7
  title 
8
  year 
9
  imdbRating 
10
} 


Result: 

 
11
1
{ 
2
  "data": { 
3
    "moviesByTitle": [ 
4
      { 
5
        "title": "Matrix Reloaded, The", 
6
        "year": 2003, 
7
        "imdbRating": 7.2 
8
      } 
9
    ] 
10
  } 
11
} 


Inline Fragments 

Inline fragments are useful for queries where a field’s return type is determined at runtime. These fragments use the syntax ...on <TYPE>. They are primarily used when a field’s return type is an abstract type (i.e., a union or interface). 

Consider the following: 

 
4
1
type Query { 
2
  personByName(name: String!): [PersonResult] 
3
} 
4
union PersonResult = User | Actor 


PersonResult can be either a User or Actor. In this case, an inline fragment can be used to fetch the appropriate fields for each type in the union: 

 
13
1
{ 
2
  personByName(name: "Tom Cruise", limit: 3) { 
3
    ... on Actor { 
4
      name 
5
      movies { 
6
        title 
7
      } 
8
    } 
9
    ... on User { 
10
      name 
11
    } 
12
  }
13
} 


Result: 

 
20
1
{ 
2
  "data": { 
3
    "personByName": [ 
4
      { 
5
        "name": "Tom Cruise", 
6
        "movies": [ 
7
          { 
8
            "title": "Risky Business" 
9
          }, 
10
          { 
11
            "title": "Cocktail" 
12
          }, 
13
          { 
14
            "title": "Top Gun" 
15
          } 
16
        ] 
17
      } 
18
    ] 
19
  } 
20
} 


Subscriptions 

Often, clients want to receive updates from the server when certain data changes. In addition to queries and mutations, GraphQL supports a third operation type, subscription, which allows a client to subscribe to receive event updates. Subscriptions are real-time streaming chunks of data that allow bi-directional interaction over a single persistent connection (often WebSocket). 

Let's say a client wants to receive updates when a user submits a movie rating for a particular movie. If the user is viewing a movie page, the UI would update when a new rating is received.  

Every time the underlying MovieReviewSubscription is changed, the new value for rating will be pushed over WebSocket (or some other type of persistent connection). The nature of operations performed by subscription is slightly different than that of query — the former has real-time fetching of data while the latter fetches only once.  

Subscription operation: 

 
8
1
subscription MovieReviewSubscription($movieId: ID!) { 
2
  movieReviewSubscription(movieId: $movieId) { 
3
    movie { 
4
      title 
5
    } 
6
    rating 
7
  } 
8
} 


Directives 

GraphQL directives enable static and dynamic schema modification. Here are two built-in directive examples: 

@skip 

@include 

 
3
1
query myMovieQuery($testValue: Boolean!) { 
2
  experimentalField @skip(if: $testValue) 
3
} 

 

In this example, experimentalField is queried only if the variable $testValue has the value false. 

 
3
1
query myMovieQuery($testValue: Boolean!) { 
2
  experimentalField @include(if: $testValue) 
3
} 


In this example, experimentalField is queried if the variable $testValue has the value true. 

Learn more about directives here. 

Securing Your GraphQL APIs 

Failing to secure APIs properly can have serious consequences, especially with GraphQL. Because clients can craft complex queries, servers must be ready to handle such queries. Certain queries might be abusive or malicious, or they might simply be very large. In all of these cases, the query can potentially bring down your GraphQL server. GraphQL recommends a few guidelines and strategies. 

Timeout 

Setting a timeout informs a server and any intermediaries of the maximum amount of time they can spend to execute any query. If a query exceeds this maximum, the server ceases execution. 

Limiting Maximum Query Depth 

GraphQL schemas are often cyclic graphs, meaning a malicious GraphQL query can exploit nested relationships. For example, let’s say there’s an Entertainment API that exposes an Actor type. Each Actor can belong to a Movie, and each Movie can have an Actor in the form of an Artist. Considering this, a deeply nested query such as the following is valid: 

A circular reference like this can lead to significant load on API servers. 

GraphQL servers can enforce depth-limiting caps to control the amount of nesting that can be present in any given query. Before the query is processed, its depth is calculated (the above query has six nesting levels). If the nesting depth exceeds the given limit, it is rejected outright. 

Query Complexity Limits 

Another troublesome query relates to complexity — for example, a client can simply request many fields on the root query object. 

To deal with this kind of query, GraphQL has built-in support for complexity analysis. An arbitrary number can be assigned as points to any field. When an incoming query is received, these arbitrary numbers are summed. If the total exceeds the threshold, an appropriate error message is returned. 

Field-Based Permissions 

Given a schema with the objects Users, Bookings, and Movies, the Bookings and Users objects are private, so authentication is needed to access them. Authentication is handled by resolvers. The Movies object is public and can be accessed without being authenticated. Now, what should happen with the query below if the client is not authenticated? 

Section 5

Assuming that the client making the query above isn’t authenticated, they can access all of the user’s data, which breaches user privacy. The problem above is solved by adding a permission on the query, object, and field level. 

Permission on field level allows you to add a check over the field. Let’s say for the object User, some fields can be viewed by anyone like name, but we don’t want to show the field Booking, as this data is considered private and only accessible by the User or Admin. 

Logic inside resolver: 

When a field is restricted and used in a GraphQL operation, the consumer receives an error response (e.g., 400 Bad Request). 

Section 6

Conclusion

 While this Refcard covered the primary benefits of GraphQL and introduced some essential GraphQL concepts, as well as more advanced fundamentals, there are still many topics left to explore. Below is an overview of additional resources available to learn more about GraphQL and tools to simplify the process of building GraphQL applications: 

  • Graphql.org – Portal for all things GraphQL 
  • GraphQL specification – A working draft of the GraphQL specification, maintained by Facebook 
  • Apollo Client and Server – Flexible GraphQL libraries for back-end and front-end applications 
  • Apollo Odyssey – Interactive, in-depth tutorials for getting started with GraphQL 
  • Sandbox – In-browser IDE for exploring GraphQL endpoints 
  • graphql-tools – Opinionated structure for how to build a GraphQL schema and resolvers in JavaScript, following the GraphQL-first development workflow 
  • Prisma – Open-source database toolkit 
  • DataLoader – Utility for batching and caching requests, often used with GraphQL services 
  • PostGraphQL – Create a GraphQL API by reflection over a PostgreSQL schema 
  • Awesome GraphQL – A collection of links to GraphQL resources including tutorials, libraries, and examples 

Like This Refcard? Read More From DZone

related article thumbnail

DZone Article

GraphQL: Core Features, Architecture, Pros, and Cons
related article thumbnail

DZone Article

How To Create a GraphQL Schema With GraphQL.js and Express?
related article thumbnail

DZone Article

How to Convert XLS to XLSX in Java
related article thumbnail

DZone Article

Automatic Code Transformation With OpenRewrite
related refcard thumbnail

Free DZone Refcard

GraphQL Essentials
related refcard thumbnail

Free DZone Refcard

API Integration Patterns
related refcard thumbnail

Free DZone Refcard

Getting Started With Cross-Platform Heterogeneous Computing
related refcard thumbnail

Free DZone Refcard

Introduction to Digital Asset Management via APIs

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends: