An Introduction to GraphQL
This article was originally written for DigitalOcean.
Introduction
As web and mobile applications become more mature and complex, software engineers invent clever new ways of improving the interaction between client and server within an application. One of the biggest paradigm shifts over the last few years in this regard has been GraphQL, an open-source query language and runtime for manipulating APIs. GraphQL was designed by Facebook in 2012 (and released publicly in 2015) to solve various weaknesses with traditional REST architecture by making a new system that is declarative, client-driven, and performant.
In this article, you will learn what GraphQL is, familiarize yourself with important terminology and concepts of GraphQL, and discover how the GraphQL specification compares with the REST architectural style.
What is GraphQL?
GraphQL stands for Graph Query Language, but unlike other query languages such as SQL (Structured Query Language), it is not a language for communicating directly with a database, but rather a language that defines a contract through which a client communicates with a API server. The GraphQL specification is an open standard that describes the rules and characteristics of the language. It also provides instructions for executing a GraphQL query.
Due to the fact that GraphQL is defined by an open-standard, there is no official implementation of GraphQL. A GraphQL implementation can be written with any programming language, integrate with any type of database, and support any client (such as mobile or web applications), as long as it follows the rules outlined in the spec. One of the most popular commercial GraphQL implementations is Apollo GraphQL, a which touts several GraphQL client and server implementations, but it is not necessary to use Apollo to use or understand GraphQL.
GraphQL Characteristics
There are several key characteristics of GraphQL design. GraphQL queries are declarative and hierarchical, and a GraphQL schema is strongly-typed and introspective.
Declarative
GraphQL queries are declarative, meaning the client will declare exactly which fields it is interested in, and the response will only include those properties.
This example GraphQL query for a hypothetical fantasy game API requests a wizard
with an ID of "1"
, and requests the name
and race
fields on that object.
{
wizard(id: "1") {
name
race
}
}
The response, which is returned in JSON format, will return a data
object that contains the found wizard
object, with the two fields the query requested.
{
"data": {
"wizard": {
"name": "Merlin",
"race": "HUMAN"
}
}
}
Since a GraphQL response only gives you the exact information you want, it results in a more efficient and performant network request than alternatives that always provide a complete set of data.
Hierarchical
GraphQL queries are also hierarchical. The data returned follows the shape of the query. In this example, the query has been extended to include spells
, and is requesting the name
and attack
fields of every spell.
{
wizard(id: "1") {
name
spells {
name
attack
}
}
}
The response will now include an array of all the spell
objects associated with this particular wizard
. Although wizards
and spells
might be stored in separate database tables, they can be fetched with a single GraphQL request. (However, GraphQL is not opinionated about how the data itself is stored, so that is a presumption.)
{
"data": {
"wizard": {
"name": "Merlin",
"spells": [
{
"name": "Lightning Bolt",
"attack": 2
},
{
"name": "Ice Storm",
"attack": 2
},
{
"name": "Fireball",
"attack": 3
}
]
}
}
}
Strongly-typed
GraphQL is strongly-typed, as described by the GraphQL Type system. Types describe the capabilities of the values within a GraphQL server. The GraphQL types will be familiar to most programmers, with scalars (primitive values) like strings, booleans, and numeric integers, as well as more advanced values like objects.
This example creates a Spell
Object type with fields that correspond to String
and Int
scalar types.
type Spell {
name: String!
attack: Int
range: Int
}
A GraphQL schema is defined using the type system, which allows the server to determine whether or not a query is valid before attempting to query the data. GraphQL Validation ensures the request is syntactically correct, unambiguous, and mistake-free.
Self-documenting
The Introspection feature allows GraphQL clients and tools to query the GraphQL server for the underlying schema's shape and data. This allows for the creation of tools like GraphiQL, an in-browser IDE and playground for working with GraphQL queries, and other tools for automatically generating documentation.
For example, you can find out more about the Spell
type through this introspection feature via the __schema
.
{
__schema {
types {
name
kind
description
}
}
}
The response will also be JSON like any other GraphQL response
{
"data": {
"__schema": {
"types": [
{
"name": "Spell",
"kind": "OBJECT",
"description": "A powerful spell that a wizard can read from a scroll."
}
]
}
}
}
Client-driven
The work of developing a GraphQL API happens on the backend, where the schema is defined and implemented. However, since all of the power of the GraphQL API is encompassed a single endpoint on the server, it is up to the client via declarative queries to decide exactly what data it needs. This empowers developers to iterate quickly, as the front end developer can continue to query the data the GraphQL API exposes without doing any additional backend work.
Architecture
GraphQL exists in the application layer between client and data. The GraphQL server describes the capabilities exposed in the API, and the client describes the requirements of the request.
Server
A GraphQL API is defined with a single endpoint, usually the /graphql
endpoint, which can access the full capabilities of the GraphQL server. Since GraphQL is an application layer technology and is transport agnostic, it can be served over any protocol, but it is most commonly served over HTTP.
A GraphQL server implementation can be written with any programming language, such as the express-graphql middleware which allows you to create a GraphQL API on a Node/Express HTTP server. GraphQL is also database agnostic, and the data for the application can be stored in MySQL, PostgreSQL, MongoDB, or any other database. The data can even be supplied by an aggregation of several traditional REST API endpoints. All that matters is that the data is defined in a GraphQL schema, which defines the API by describing the data available to be queried.
Client
Requests made to a GraphQL server are called documents and consist of operations such as queries (for read requests) and mutations (for write requests).
Although there are advanced GraphQL clients, such as Apollo Client or Facebook's Relay which provide mechanisms for caching as well as additional tools, no special client is required to make a request to a GraphQL server. A simple XMLHttpRequest
or fetch
from a web browser is sufficient for making requests by sending a GraphQL document to a GraphQL server.
Below is an example of a fetch
request to a /graphql
endpoint, which passes the GraphQL document as a string in the body of the POST
request.
async function fetchWizards() {
const response = await fetch('/graphql', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
query: `{
wizards {
id
name
},
}`,
}),
})
const wizards = await response.json()
return wizards
}
fetchWizards()
This will return a JSON response for the request.
{
"data": {
"wizards": [
{ "id": "1", "name": "Merlin" },
{ "id": "2", "name": "Gandalf" }
]
}
}
GraphQL vs. REST
GraphQL and REST are not interchangeable concepts, but they solve similar problems for applications. REST stands for Representational State Transfer, and is a software architectural style for sharing data between different systems. A RESTful API is an API that adheres to the principles and constraints of REST, which include being stateless, cacheable, enforcing a separation of concerns between the client and server, and having a uniform interface, such as through URIs. GraphQL, as covered previously, is a specification for a query language and runtime for executing queries.
There are advantages and disadvantages to both systems, and both have their use in modern API development. However, GraphQL was developed to combat some perceived weaknesses with the REST system, and to create a more efficient, client-driven API.
-
Architecture - A REST API is typically defined by multiple endpoints on a server, but GraphQL exchanges data over a single endpoint. A GraphQL endpoint can return a complex graph of data that might require multiple REST queries, reducing the number of requests over the network for a single view.
-
Data fetching - A REST API returns the set of data that was determined on the server. This might be far too much data, such as if the view only requires one property from a response, or it might not be enough, such as a list endpoint that doesn't return every property that a table requires in the view. GraphQL prevents this over and under fetching of data via declarative queries.
-
Error Handling - Since it is not necessary for GraphQL to be served over HTTP, there is no specification about using HTTP response codes for errors. Typically all GraphQL endpoints will resolve with a
200
HTTP code response, and failed results will include anerrors
property alongside thedata
property in the response. RESTful APIs, on the other hand, utilize different400
level HTTP codes for client errors and200
level HTTP codes for successful responses. -
Versioning - GraphQL APIs strive to be backwards compatible and avoid breaking changes, contrasting with the common REST pattern of versioning endpoints, often with a
/v1
or/v2
in the URL itself to determine the version. However, it is possible to implement your own versioning with GraphQL, or version via evolution with REST, it's just less conventional. -
Caching - Cacheability is an integral part of the REST guiding constraints. Since HTTP-based REST APIs consist of multiple endpoints using different HTTP methods, it can take advantage of existing HTTP conventions for caching and avoiding refetching resource. And since essentially every GraphQL request will be different but use the single endpoint, it cannot take advantage of any of the built-in HTTP caching mechanisms. GraphQL clients can take advantage of Global Object Identification to enable simple caching.
This list does not cover all the similarities and differences between REST and GraphQL, but summarizes many of the most critical points. Additionally, GraphQL can be used as a gateway that aggregates multiple REST endpoints or services, in which case both technologies can be used in harmony side-by-side.
Feature | GraphQL | REST |
---|---|---|
Description | GraphQL is a query language for APIs, and a server-side runtime | An architectural style for designing web services |
Data Fetching | A single HTTP endpoint that responds to deterministic queries | A set of HTTP endpoints that typically return a predetermined dataset |
Versioning | Versioning discouraged | Versioning common |
HTTP Status Codes | All responses, including errors, are typically 200 |
Implements HTTP Status codes |
Validation | Built-in metadata validation | Validation must be manually implemented |
Documentation | Built-in via type system and introspection | Not self-documenting, tools like OpenAPI available |
Caching | No | Yes |
Request Methods | Queries, mutations, and subscriptions (over POST for HTTP) |
All HTTP methods utilized (GET , POST , PATCH , PUT , DELETE , etc) |
Response Content-Type | JSON | Any (JSON, XML, HTML, etc.) |
Conclusion
GraphQL is an open-source query language and runtime for APIs. GraphQL was invented by developers at Facebook to solve various issues encountered with traditional REST APIs, such as over/under fetching data and inefficient network requests, by making a client-driven, declarative query language for APIs.
While GraphQL is not an interchangeable concept with REST, they both describe different ways to manage communication between a client and a server. In this article, you learned what GraphQL is, key differences and similarities between GraphQL and REST, and how a GraphQL server exposes data to a client.
Comments