You are on page 1of 9

249 BROUGHT TO YOU IN PARTNERSHIP WITH

GraphQL Essentials CONTENTS

•  The Evolution of GraphQL

Declarative Data Fetching Over a Single API •  Fundamentals of GraphQL

•  GraphQL Queries and Mutations

•  Conclusion

STEPHEN BARLOW
DOCUMENTATION LEAD, APOLLO GRAPHQL

GraphQL is a language-independent specification for client-server BENEFIT DESCRIPTION


communication. Its declarative query language enables application
Autogenerating API A GraphQL API is tightly coupled with code,
clients to specify which back-end data to fetch, without worrying about
documentation so documentation can change automatically
how that data is populated. A GraphQL server receives queries from as schema types and fields change.
clients and fulfils them by populating requested fields with back-end
Versionless API evolution GraphQL eliminates the need for versioning
data from arbitrarily many sources (such as relational databases and
by deprecating API functionality at the field
REST APIs). level. Unused fields can be removed from the
schema without affecting active queries.
THE EVOLUTION OF GRAPHQL
Shared query logic GraphQL fragments are units of query logic
In 2012, Facebook’s native mobile apps for iOS and Android were
(fragments) that can be shared across multiple queries.
thin wrappers around the views of their mobile website. These apps
often crashed when making multiple simultaneous REST API calls. To Elimination of over- GraphQL enables front-end applications to
resolve this issue, Facebook overhauled their infrastructure to enable fetching and under- fetch exactly the data they need, when they
fetching need it.
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
Table 1

BENEFIT DESCRIPTION

Suitable for complex GraphQL unifies multiple systems behind a


systems and single API, thus masking the complexity of
microservices those systems from clients.

Data fetching with a GraphQL is typically served over HTTP via a


single API call single endpoint that expresses the full set of
a platform’s capabilities.

TABLE CONTINUES IN NEXT COLUMN

REFCARD | MAY 2022 1


REFCARD | GR APHQL ESSENTIALS

FUNDAMENTALS OF GRAPHQL TYPE DESCRIPTION EXAMPLE


DESIGN PRINCIPLES type Query {
Query type Defines read-only entry
GraphQL offers some guidelines for how to think about a service: points into a graph moviesByTitle(title:
String!, limit: Int=
Table 2 The Query type defines
3): [Movie]
the top-level fields that
}
PRINCIPLE DESCRIPTION are available to clients
executing queries. A
Product-centric GraphQL is driven by the data needs of the schema has exactly one
client, the language, and the runtime that Query type.
supports the client.
Mutation Defines write entry points type Mutation {
Client-specific queries A GraphQL server provides the capabilities reviewMovie
type into a graph
that clients can consume. (review:ReviewInput)
The Mutation type defines
:UserReview
Strong typing A GraphQL server is backed by the GraphQL the top-level fields that
}
type system. In the schema, each field has a are available to clients
specific type against which it’s validated. executing mutations. A
schema can have exactly
Hierarchical A GraphQL schema is hierarchical: fields are one Mutation type.
nested within other fields, and queries have
the same shape as the data they return. Enumeration A type of scalar restricted to enum RATING {
types a set of pre-defined values G
Introspective The client can query the GraphQL server’s PG
type system. PG13
R
}
SCHEMAS AND TYPES
Interface Abstract type that defines a interface Person {
In GraphQL, a schema defines a collection of types and the relationships
types set of fields that object types id: ID!
between those types. These types and relationships together define name: String
can implement
the extent of a unified graph. Clients execute queries against this graph }
Interface types are used
to fetch the data they need. The GraphQL schema language, also called when a field might return
the GraphQL Interface Description Language (IDL), is used to define a one of multiple related
types.
schema and types.
Input types Used to pass complex input ReviewInput {
Table 3
objects as arguments to a rating: Int!
TYPE DESCRIPTION EXAMPLE field movieId: ID!
userId: ID!
Object types An object type that can be type Movie { }
fetched, including the fields id: ID!
it provides title: String Union types Abstract type that defines union PersonResult =
year: Int a set of object types that User | Actor
For example, Movie is
plot: String all might be returned by a
an object type with fields
poster: String particular field
title, year, genres, and
genres: [String]
plot. [Movie] indicates Unlike interface types,
similar: [Movie]
a list of Movie objects, and members of a union type
rating: RATING
! indicates a non-nullable don't need to define any
actors: [Actor]
field. common fields.
series: [Series]
avgStars: Float
}
GRAPHQL QUERIES AND MUTATIONS
Scalar types Common primitive types title: String The fields of the Query and Mutation types are the entry points into a
The GraphQL specification graph.
includes the built-in
scalars Int, Float, FIELDS
String, Boolean, and ID Each type is composed of one or more fields, which can be scalar values
(serialized as a string and
can be human-readable). or complex objects that refer to other types, resulting in nesting. Each
Schemas can also define GraphQL query specifies which schema fields to return. This is referred
custom scalars, such as the to as the query’s selection set.
commonly defined Date.

REFCARD | MAY 2022 3 BROUGHT TO YOU IN PARTNERSHIP WITH


REFCARD | GR APHQL ESSENTIALS

Consider the following schema excerpt: ARGUMENTS


Schema fields can accept arguments, which can be required or optional.
type Query {
Each argument can optionally have a default value if one isn’t provided.
topRatedMovies: [Movie]
}
The following Query.moviesByTitle field accepts two arguments.
type Movie {
The limit argument specifies a default value:
id: ID!
title: String type Query {
year: Int moviesByTitle(title: String!, limit: Int = 3):
plot: String [Movie]
poster: String }
imdbRating: Float
genres: [String] Here is an example query that provides the required title argument:
similar(limit: Int = 3): [Movie]
rating: RATING {
actors: [Actor] moviesByTitle(title: "Matrix Reloaded") {
title
avgStars: Float
similar(limit: 1) {
}
title
year
Here is a valid query against that schema: }
}
{
}
topRatedMovies {
title
And here is an example result:
year
avgStars {
} "data": {
} "moviesByTitle": [
{
"title": "Matrix Reloaded, The",
And here is an example result of that query:
"similar": [
{ {

"data": { "title": "Matrix, The",


"year": 1999
"topRatedMovies": [
}
{
]
"title": "Godfather, The",
}
"year": 1972,
]
"avgStars": 4.4875 }
},
}
{
"title": "Shawshank Redemption, The",
"year": 1994,
VARIABLES
"avgStars": 4.487138263665597 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
"title": "On the Waterfront", user-supplied content. To use variables, first declare $varName as a
"year": 1954,
valid variable for the query, then replace the value in the query with
"avgStars": 4.448275862068966
$varName. Finally, pass the key-value pair varName: value in a dictionary
}
alongside the query. Here’s an example query with two variables:
]
} query MoviesByTitle($movieTitle: String!,
} $similarLimit: Int) {
moviesByTitle(title: $movieTitle) {
title
similar(limit: $similarLimit) {
title
CODE CONTINUES ON NEXT PAGE
REFCARD | MAY 2022 4 BROUGHT TO YOU IN PARTNERSHIP WITH
REFCARD | GR APHQL ESSENTIALS

year Mutation:
}
} mutation {
} createReview(userId: "20", movieId: "16", rating:
5) {
movie {
And here’s a variables object that’s provided alongside that query:
title

{ similar(limit: 2) {

"movieTitle": "Matrix Reloaded", title

"similarLimit": 1 }
}
}
user {
name
Result: }
rating
{
}
"data": {
}
"moviesByTitle": [
{
"title": "Matrix Reloaded, The", Result:
"similar": [
{ {

"title": "Matrix, The", "data": {

"year": 1999 "createReview": {

} "movie": {

] "title": "Casino",

} "similar": [

] {

} "title": "Four Brothers"


},
}
{
"title": "Night and the City"
MUTATIONS }
While queries enable you to read back-end data, GraphQL mutations ]
},
enable you to create, update, and delete that data. To enable mutations,
"user": {
a schema defines a Mutation type. The fields of this type are entry "name": "Nicole Ramsey"
points that correspond to different write operations that clients can },
execute. "rating": 5
}
Consider a UserReview type: }
}
type UserReview {
user: User
rating: Int INPUT TYPES
movie: Movie 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
To create a new UserReview, a schema might define this Mutation as fields. Input types are especially useful for mutations where the goal
field: is to pass an update as a single object.

type Mutation {
Input type:
createReview(userId: ID!, movieId: ID!, rating:
Int): UserReview input ReviewInput {
} rating: Int!
movieId: ID!
userId: ID!
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).

REFCARD | MAY 2022 5 BROUGHT TO YOU IN PARTNERSHIP WITH


REFCARD | GR APHQL ESSENTIALS

Then modify the createReview field to accept one argument of type {


moviesByTitle(title: "Matrix Reloaded") {
ReviewInput:
...movieSummaryFields
type Mutation { }
createReview(review: ReviewInput!): UserReview }
} fragment movieSummaryFields on Movie {
title

The mutation becomes: year


imdbRating
mutation CreateReviewForMovie($review: ReviewInput) }
{
createReview(review: $review) {
Result:
movie {
title {
} "data": {
user { "moviesByTitle": [
name {
} "title": "Matrix Reloaded, The",
rating "year": 2003,
} "imdbRating": 7.2
} }
]
Variables: }
}
{
"review": {
"movieId": "16", INLINE FRAGMENTS
"userId": "20", Inline fragments are useful for queries where a field’s return type is
"rating": 5 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:


Results:

type Query {
{
personByName(name: String!): [PersonResult]
"data": {
}
"createReview": {
"movie": { union PersonResult = User | Actor

"title": "Casino"
}, PersonResult can be either a User or Actor. In this case, an inline
"user": { fragment can be used to fetch the appropriate fields for each type in
"name": "Nicole Ramsey" the union:
},
"rating": 5 {

} personByName(name: "Tom Cruise", limit: 3) {


... on Actor {
}
name
}
movies {
title
FRAGMENTS }

A fragment is a reusable set of fields that can be defined and referenced by }


... on User {
name in multiple GraphQL queries. This enables you to factor out common
name
logic and reduce repetition in operations. To apply a fragment inside a }
query, use a fragment spread operator (...) inside the selection set: }
}
SEE CODE IN NEXT COLUMN

REFCARD | MAY 2022 6 BROUGHT TO YOU IN PARTNERSHIP WITH


REFCARD | GR APHQL ESSENTIALS

Result: DIRECTIVES
GraphQL directives enable static and dynamic schema modification.
{
Here are two built-in directive examples:
"data": {
"personByName": [
@skip @include
{
"name": "Tom Cruise", query query
myMovieQuery($testValue: myMovieQuery($testValue:
"movies": [
Boolean!) { Boolean!) {
{
experimentalField @ experimentalField @
"title": "Risky Business" skip(if: $testValue) include(if: $testValue)
}, } }

{
In this example, In this example,
"title": "Cocktail" experimentalField is queried experimentalField is queried
}, only if the variable $testValue if the variable $testValue has
{ has the value false. the value true.
"title": "Top Gun"
} 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
SUBSCRIPTIONS these cases, the query can potentially bring down your GraphQL server.
Often, clients want to receive updates from the server when certain GraphQL recommends a few guidelines and strategies.
data changes. In addition to queries and mutations, GraphQL supports
TIMEOUT
a third operation type, subscription, which allows a client to subscribe
Setting a timeout informs a server and any intermediaries of the
to receive event updates. Subscriptions are real-time streaming chunks
maximum amount of time they can spend to execute any query. If a
of data that allow bi-directional interaction over a single persistent
query exceeds this maximum, the server ceases execution.
connection (often WebSocket).

Let's say a client wants to receive updates when a user submits a movie LIMITING MA XIMUM QUERY DEPTH
rating for a particular movie. If the user is viewing a movie page, the UI GraphQL schemas are often cyclic graphs, meaning a malicious GraphQL

would update when a new rating is received. query can exploit nested relationships. For example, let’s say there’s an
Entertainment API that exposes an Actor type. Each Actor can belong
Every time the underlying MovieReviewSubscription is changed, the to a Movie, and each Movie can have an Actor in the form of an Artist.
new value for rating will be pushed over WebSocket (or some other Considering this, a deeply nested query such as the following is valid:
type of persistent connection). The nature of operations performed by
subscription is slightly different than that of query — the former has Figure 1

real-time fetching of data while the latter fetches only once.

Subscription operation:

subscription MovieReviewSubscription($movieId: ID!)


{
movieReviewSubscription(movieId: $movieId) {
movie {
title
}
rating
}
}

REFCARD | MAY 2022 7 BROUGHT TO YOU IN PARTNERSHIP WITH


REFCARD | GR APHQL ESSENTIALS

A circular reference like this can lead to significant load on API servers. 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
GraphQL servers can enforce depth-limiting caps to control the amount
problem above is solved by adding a permission on the query, object,
of nesting that can be present in any given query. Before the query is
and field level.
processed, its depth is calculated (the above query has six nesting
levels). If the nesting depth exceeds the given limit, it is rejected Permission on field level allows you to add a check over the field. Let’s
outright. 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
QUERY COMPLEXITY LIMITS private and only accessible by the User or Admin.
Another troublesome query relates to complexity — for example, a
client can simply request many fields on the root query object. Figure 4

Figure 2

To deal with this kind of query, GraphQL has built-in support for
complexity analysis. An arbitrary number can be assigned as points to
Logic inside resolver:
any field. When an incoming query is received, these arbitrary numbers
are summed. If the total exceeds the threshold, an appropriate error Figure 5
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?
When a field is restricted and used in a GraphQL operation, the
Figure 3 consumer receives an error response (e.g., 400 Bad Request).

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

REFCARD | MAY 2022 8 BROUGHT TO YOU IN PARTNERSHIP WITH


REFCARD | GR APHQL ESSENTIALS

•  Apollo Odyssey – Interactive, in-depth tutorials for getting


started with GraphQL WRITTEN BY STEPHEN BARLOW,
DOCUMENTATION LEAD, APOLLO GRAPHQL
•  Sandbox – In-browser IDE for exploring GraphQL endpoints
Stephen enjoys words even more than code, and
•  graphql-tools – Opinionated structure for how to build a
Apollo’s documentation conveniently immerses
GraphQL schema and resolvers in JavaScript, following the him in both. Outside of Apollo, he writes for indie
GraphQL-first development workflow video games and auditions for voice-over gigs.

•  Prisma – Open-source database toolkit

•  DataLoader – Utility for batching and caching requests, often


600 Park Offices Drive, Suite 300
used with GraphQL services Research Triangle Park, NC 27709
888.678.0399 | 919.678.0300
•  PostGraphQL – Create a GraphQL API by reflection over a
At DZone, we foster a collaborative environment that empowers developers and
PostgreSQL schema tech professionals to share knowledge, build skills, and solve problems through
content, code, and community. We thoughtfully — and with intention — challenge
•  Awesome GraphQL – A collection of links to GraphQL resources the status quo and value diverse perspectives so that, as one, we can inspire
positive change through technology.
including tutorials, libraries, and examples

Copyright © 2022 DZone, Inc. All rights reserved. No part of this publication
may be reproduced, stored in a retrieval system, or transmitted, in any form or
by means of electronic, mechanical, photocopying, or otherwise, without prior
written permission of the publisher.

REFCARD | MAY 2022 9 BROUGHT TO YOU IN PARTNERSHIP WITH

You might also like