Sie sind auf Seite 1von 16

Hiring? Toptal handpicks top API development specialists to suit your needs.

Start hiring
Login

Top 3%
Why
Clients
Partners
Community
Blog
About Us
Start hiring
Apply as a Developer
Login
Questions?
Contact Us

Search Topics
Hire a developer

GraphQL vs. REST - A GraphQL Tutorial


View all articles

by Amaury Martiny - Full-stack Developer @ Toptal

#GraphQL #REST #Tutorial

201shares

You might have heard about the new kid around the block: GraphQL. If not, GraphQL is, in a word, a new way to fetch
APIs, an alternative to REST. It started as an internal project at Facebook, and since it was open sourced, it has gained a lot
of traction.

The aim of this article is to help you make an easy transition from REST to GraphQL, whether youve already made your
mind for GraphQL or youre just willing to give it a try. No prior knowledge of GraphQL is needed, but some familiarity
with REST APIs is required to understand the article.

The first part of the article will start by giving three reasons why I personally think GraphQL is superior to REST. The
second part is a tutorial on how to add a GraphQL endpoint on your back-end.

Graphql vs. REST: Why Drop REST?


If you are still hesitating on whether or not GraphQL is suited for your needs, a quite extensive and objective overview of
REST vs. GraphQL is given here. However, for my top three reasons to use GraphQL, read on.

Reason 1: Network Performance


Say you have a user resource on the back-end with first name, last name, email, and 10 other fields. On the client, you
generally only need a couple of those.

Making a REST call on the /users endpoint gives you back all the fields of the user, and the client only uses the ones it
needs. There is clearly some data transfer waste, which might be a consideration on mobile clients.
GraphQL by default fetches the smallest data possible. If you only need first and last names of your users, you specify that
in your query.

The interface below is called GraphiQL, which is like an API explorer for GraphQL. I created a small project for the
purpose of this article. The code is hosted on GitHub, and well dive into it in the second part.

On the left pane of the interface is the query. Here, we are fetching all the userswe would do GET /users with REST
and only getting their first and last names.

Query
query {
users {
firstname
lastname
}
}

Result
{
"data": {
"users": [
{
"firstname": "John",
"lastname": "Doe"
},
{
"firstname": "Alicia",
"lastname": "Smith"
}
]
}
}

If we wanted to get the emails as well, adding an email line below lastname would do the trick.

Some REST back-ends do offer options like /users?fields=firstname,lastname to return partial resources. For what its
worth, Google recommends it. However, it is not implemented by default, and it makes the request barely readable,
especially when you toss in other query parameters:

&status=active to filter active users


&sort=createdAat to sort the users by their creation date
&sortDirection=desc because you obviously need it
&include=projects to include the users projects

These query parameters are patches added to the REST API to imitate a query language. GraphQL is above all a query
language, which makes requests concise and precise from the beginning.

Reason 2: The Include vs. Endpoint Design Choice


Lets imagine we want to build a simple project management tool. We have three resources: users, projects, and tasks. We
also define the following relationships between the resources:
Here are some of the endpoints we expose to the world:

Endpoint Description

GET /users List all users

GET /users/:id Get the single user with id :id

GET /users/:id/projects Get all projects of one user

The endpoints are simple, easily readable, and well-organized.

Things get trickier when our requests get more complex. Lets take the GET /users/:id/projects endpoint: Say I want to
show only the projects titles on the home page, but projects+tasks on the dashboard, without making multiple REST calls. I
would call:

GET /users/:id/projects for the home page.


GET /users/:id/projects?include=tasks (for example) on the dashboard page so that the back-end appends all
related tasks.
Its common practice to add query parameters ?include=... to make this work, and is even recommended by the JSON
API specification. Query parameters like ?include=tasks are still readable, but before long, we will end up with ?
include=tasks,tasks.owner,tasks.comments,tasks.comments.author.

In this case, would be it wiser to create a /projects endpoint to do this? Something like /projects?
userId=:id&include=tasks, as we would have one level of relationship less to include? Or, actually, a /tasks?
userId=:id endpoint might work too. This can be a difficult design choice, even more complicated if we have a many-to-
many relationship.

GraphQL uses the include approach everywhere. This makes the syntax to fetch relationships powerful and consistent.

Heres an example of fetching all projects and tasks from the user with id 1.

Query
{
user(id: 1) {
projects {
name
tasks {
description
}
}
}
}

Result
{
"data": {
"user": {
"projects": [
{
"name": "Migrate from REST to GraphQL",
"tasks": [
{
"description": "Read tutorial"
},
{
"description": "Start coding"
}
]
},
{
"name": "Create a blog",
"tasks": [
{
"description": "Write draft of article"
},
{
"description": "Set up blog platform"
}
]
}
]
}
}
}

As you can see, the query syntax is easily readable. If we wanted to go deeper and include tasks, comments, pictures, and
authors, we wouldnt think twice about how to organize our API. GraphQL makes it easy to fetch complex objects.

Reason 3: Managing Different Types of Clients


When building a back-end, we always start by trying to make the API as widely usable by all clients as possible. Yet clients
always want to call less and fetch more. With deep includes, partial resources, and filtering, requests made by web and
mobile clients may differ a lot one from another.

With REST, there are a couple of solutions. We can create a custom endpoint (i.e., an alias endpoint, e.g., /mobile_user), a
custom representation (Content-Type: application/vnd.rest-app-example.com+v1+mobile+json), or even a client-
specific API (like Netflix once did). All three of them require extra effort from the back-end development team.

GraphQL gives more power to the client. If the client needs complex requests, it will build the corresponding queries itself.
Each client can consume the same API differently.

How to Start with GraphQL


In most debates about GraphQL vs. REST today, people think that they must choose either one of the two. This is simply
not true.

Modern applications generally use several different services, which expose several APIs. We could actually think of
GraphQL as a gateway or a wrapper to all these services. All clients would hit the GraphQL endpoint, and this endpoint
would hit the database layer, an external service like ElasticSearch or Sendgrid, or other REST endpoints.
A second way of using both is to have a separate /graphql endpoint on your REST API. This is especially useful if you
already have numerous clients hitting your REST API, but you want to try GraphQL without compromising the existing
infrastructure. And this is the solution we are exploring today.

As said earlier, I will illustrate this tutorial with a small example project, available on GitHub. It is a simplified project
management tool, with users, projects, and tasks.

The technologies used for this project are Node.js and Express for the web server, SQLite as the relational database, and
Sequelize as an ORM. The three modelsuser, project, and taskare defined in the models folder. The REST endpoints
/api/users, /api/projects and /api/tasks are exposed to the world, and are defined in the rest folder.

Do note that GraphQL can be installed on any type of back-end and database, using any programming language. The
technologies used here are chosen for the sake of simplicity and readability.

Our goal is to create a /graphql endpoint without removing the REST endpoints. The GraphQL endpoint will hit the
database ORM directly to fetch data, so that it is totally independant from the REST logic.

Types
The data model is represented in GraphQL by types, which are strongly typed. There should be a 1-to-1 mapping between
your models and GraphQL types. Our User type would be:
type User {
id: ID! # The "!" means required
firstname: String
lastname: String
email: String
projects: [Project] # Project is another GraphQL type
}

Queries

Queries define what queries you can run on your GraphQL API. By convention, there should be a RootQuery, which
contains all the existing queries. I also pointed out the REST equivalent of each query:
type RootQuery {
user(id: ID): User # Corresponds to GET /api/users/:id
users: [User] # Corresponds to GET /api/users
project(id: ID!): Project # Corresponds to GET /api/projects/:id
projects: [Project] # Corresponds to GET /api/projects
task(id: ID!): Task # Corresponds to GET /api/tasks/:id
tasks: [Task] # Corresponds to GET /api/tasks
}

Mutations
If queries are GET requests, mutations can be seen as POST/PATCH/PUT/DELETE requests (although really they are
synchronized versions of queries).

By convention, we put all our mutations in a RootMutation:


type RootMutation {
createUser(input: UserInput!): User # Corresponds to POST /api/users
updateUser(id: ID!, input: UserInput!): User # Corresponds to PATCH /api/users
removeUser(id: ID!): User # Corresponds to DELETE /api/users

createProject(input: ProjectInput!): Project


updateProject(id: ID!, input: ProjectInput!): Project
removeProject(id: ID!): Project

createTask(input: TaskInput!): Task


updateTask(id: ID!, input: TaskInput!): Task
removeTask(id: ID!): Task
}

Note that we introduced new types here, called UserInput, ProjectInput, and TaskInput. This is a common practice with
REST too, to create an input data model for creating and updating resources. Here, our UserInput type is our User type
without the id and projects fields, and notice the keyword input instead of type:
input UserInput {
firstname: String
lastname: String
email: String
}

Like what you're reading?


Get the latest updates first.
Enter your email address...
Get Exclusive Updates
No spam. Just great engineering posts.
Like what you're reading?
Get the latest updates first.
Thank you for subscribing!
Check your inbox to confirm subscription. You'll start receiving posts after you confirm.

109shares

Schema
With types, queries and mutations, we define the GraphQL schema, which is what the GraphQL endpoint exposes to the
world:
schema {
query: RootQuery
mutation: RootMutation
}

This schema is strongly typed and is what allowed us to have those handy autocompletes in GraphiQL.

Resolvers

Now that we have the public schema, it is time to tell GraphQL what to do when each of these queries/mutations is
requested. Resolvers do the hard work; they can, for example:

Hit an internal REST endpoint


Call a microservice
Hit the database layer to do CRUD operations

We are choosing the third option in our example app. Lets have a look at our resolvers file:
const models = sequelize.models;

RootQuery: {
user (root, { id }, context) {
return models.User.findById(id, context);
},
users (root, args, context) {
return models.User.findAll({}, context);
},
// Resolvers for Project and Task go here
},

/* For reminder, our RootQuery type was:


type RootQuery {
user(id: ID): User
users: [User]

# Other queries
}

This means, if the user(id: ID!) query is requested on GraphQL, then we return User.findById(), which is a Sequelize
ORM function, from the database.

What about joining other models in the request? Well, we need to define more resolvers:
User: {
projects (user) {
return user.getProjects(); // getProjects is a function managed by Sequelize ORM
}
},

/* For reminder, our User type was:


type User {
projects: [Project] # We defined a resolver above for this field
# ...other fields
}
*/

So when we request the projects field in a User type in GraphQL, this join will be appended to the database query.

And finally, resolvers for mutations:


RootMutation: {
createUser (root, { input }, context) {
return models.User.create(input, context);
},
updateUser (root, { id, input }, context) {
return models.User.update(input, { ...context, where: { id } });
},
removeUser (root, { id }, context) {
return models.User.destroy(input, { ...context, where: { id } });
},
// ... Resolvers for Project and Task go here
}

You can play around with this here. For the sake of keeping the data on the server clean, I disabled the resolvers for
mutations, which means that the mutations will not do any create, update or delete operations in the database (and thus
return null on the interface).

Query
query getUserWithProjects {
user(id: 2) {
firstname
lastname
projects {
name
tasks {
description
}
}
}
}

mutation createProject {
createProject(input: {name: "New Project", UserId: 2}) {
id
name
}
}

Result
{
"data": {
"user": {
"firstname": "Alicia",
"lastname": "Smith",
"projects": [
{
"name": "Email Marketing Campaign",
"tasks": [
{
"description": "Get list of users"
},
{
"description": "Write email template"
}
]
},
{
"name": "Hire new developer",
"tasks": [
{
"description": "Find candidates"
},
{
"description": "Prepare interview"
}
]
}
]
}
}
}

It may take some time to rewrite all types, queries, and resolvers for your existing app. However, a lot of tools exist to help
you. For instance, there are tools that translate a SQL schema to a GraphQL schema, including resolvers!

Putting Everything Together


With a well-defined schema and resolvers on what to do on each query of the schema, we can mount a /graphql endpoint
on our back-end:
// Mount GraphQL on /graphql
const schema = makeExecutableSchema({
typeDefs, // Our RootQuery and RootMutation schema
resolvers: resolvers() // Our resolvers
});
app.use('/graphql', graphqlExpress({ schema }));

And we can have a nice-looking GraphiQL interface on our back-end. To make a request without GraphiQL, simply copy
the URL of the request, and run it with cURL, AJAX, or directly in the browser. Of course, there are some GraphQL clients
to help you build these queries. See below for some examples.

Whats Next?
This articles aim is to give you a taste of what GraphQL looks like and show you that its definitely possible to try
GraphQL without throwing away your REST infrastructure. The best way to know if GraphQL suits your needs is to try it
yourself. I hope that this article will make you take the dive.

There are a lot of features we havent discussed about in this article, such as real-time updates, server-side batching,
authentication, authorization, client-side caching, file uploading, etc. An excellent resource to learn about these features is
How to GraphQL.

Below are some other useful resources:

Server-side Tool Description

The reference implementation of GraphQL. You can use it with express-graphql to


graphql-js
create a server.

graphql-server An all-in-one GraphQL server created by the Apollo team.

Implementations for other


Ruby, PHP, etc.
platforms

Client-side Tool Description

Relay A framework for connecting React with GraphQL.

apollo-client. A GraphQL client with bindings for React, Angular 2, and other front-end frameworks.

In conclusion, I believe that GraphQL is more than hype. It wont replace REST tomorrow just yet, but it does offer a
performant solution to a genuine problem. It is relatively new, and best practices are still developing, but it is definitely a
technology that we will hear about in the next couple of years.

Understanding the Basics


What is GraphQL?

GraphQL is a query language and an alternative to REST. It started as an internal project at Facebook.

What is different in GraphQL over REST?

GraphQL merges all your RESTful endpoints into one and uses less network traffic.

About the author


View full profile
Hire the Author
Amaury Martiny, France
member since September 8, 2015
JavaScriptCSS3HTML5Node.jsReact.jsGit
Amaury has more than five years of experience building full-stack web and mobile apps (Node.js, React, React Native). He
is currently working at Parity as a blockchain app developer. He is really interested in entrepreneurship and has worked for
startups of various sizes. In his spare time, he reads about machine learning and writes about hitchhiking, culture, and
philosophy on his travel blog. [click to continue...]
Hiring? Meet the Top 10 Freelance API Development Specialists for Hire in December 2017
8 Comments Toptal
1 Login

Sort by Best
Recommend 5 Share

Join the discussion

LOG IN WITH
OR SIGN UP WITH DISQUS ?

Name

Dima Pilipenko 13 days ago


Thank you for article!

> Reason 1: Network Performance is weak.


In other words, we can say that GraphQL also has bad performance if asks all fields.

In right hands REST approach is strong and doesn't have declared weaknesses.
For program there is not difference between building queries for `include` or graph syntax.

GraphQL just more comfortable for data manipulations.


2 Reply Share
Amaury Martiny > Dima Pilipenko 11 days ago
Very true. REST doesn't have declared weaknesses if used correctly. Though empirically, people would
`GET /users` without listing all the filtered `?fields=`. With GraphQL you are invited by design to only
take the minimum.
Reply Share

Tom T. 12 days ago


GraphQL seems very comfortable to work with from the Client perspective. I'm afraid server side, if not
attention is payed to every detail by developers, it seems that it easily can become less performant than Rest
API.

Taking a basic example from above where we fetch just a field or two from the Users table, in a Rest API we
would just fetch those fields from the DB while with GraphQL developers would be tempted to just fetch all user
data.

Maybe it's makes sense for APIs used by many different clients with different requirements.
Reply Share

Amaury Martiny > Tom T. 11 days ago


Yes, in my examples I'm fetching all data from the db even if only some fields are needed. But it wouldn't
be too hard to only fetch the requested fields, and GraphQL developers should be careful about that. It's
not a magic solution, there's still work to be done on the backend to make it work well.
Reply Share

Vijay Thirugnanam 13 days ago


Nice article. For transactional systems, I will still recommend API over GraphQL. Mutations are ok but does not
have the clarity that a REST API provides. GraphiQL is a good tool, but I feel the frameworks for REST are far
mature. For example, testing an API in JavaScript is possible via supertest. I am not aware of any testing utility
for testing GraphQL server.
Reply Share

Amaury Martiny > Vijay Thirugnanam 11 days ago


Good point. Let's give it some months/years to see how the ecosystem grows.
Reply Share

Michel H. 13 days ago


Some REST frameworks have an aspect oriented approach and you can omit values and/or add a schema to
include related values from a related domain. However, GraphQL just feels like you have more control and
hence it makes the whole development experience better. Good write up!
Reply Share

Amaury Martiny > Michel H. 11 days ago


Thanks!
Reply Share

Subscribe
The #1 Blog for Engineers
Get the latest content first.
Enter your email address...
Get Exclusive Updates
No spam. Just great engineering posts.
The #1 Blog for Engineers
Get the latest content first.
Thank you for subscribing!
Check your inbox to confirm subscription. You'll start receiving posts after you confirm.

109shares

Trending articles

Fastlane: iOS Automation on Cruise Control2 days agoMagento 2: Revision or Revolution?3 days agoGetting
Started with the Elm Programming Language9 days agoGraphQL vs. REST - A GraphQL Tutorial12 days agoTips to
Attract, Manage, and Retain Software Developers16 days agoGetting Started with TensorFlow: A Machine Learning
Tutorial17 days agoQuick Wins in the Enterprise With Salesforce AppExchange24 days agoFrom Solving Equations to
Deep Learning: A TensorFlow Python Tutorial25 days ago
Relevant Technologies

API Development

About the author

Amaury Martiny
Full-stack Developer
Amaury has more than five years of experience building full-stack web and mobile apps (Node.js, React, React Native). He
is currently working at Parity as a blockchain app developer. He is really interested in entrepreneurship and has worked for
startups of various sizes. In his spare time, he reads about machine learning and writes about hitchhiking, culture, and
philosophy on his travel blog.

Hire the Author


Toptal connects the top 3% of freelance talent all over the world.

Toptal Developers
Android Developers
AngularJS Developers
Back-End Developers
C++ Developers
Data Scientists
DevOps Engineers
Ember.js Developers
Freelance Developers
Front-End Developers
Full Stack Developers
HTML5 Developers
iOS Developers
Java Developers
JavaScript Developers
Machine Learning Engineers
Magento Developers
Mobile App Developers
.NET Developers
Node.js Developers
PHP Developers
Python Developers
React.js Developers
Ruby Developers
Ruby on Rails Developers
Salesforce Developers
Scala Developers
Software Developers
Unity or Unity3D Developers
Web Developers
WordPress Developers

See more freelance developers


Learn how enterprises benefit from Toptal experts.

Join the Toptal community.


Hire a developer
or
Apply as a Developer

Highest In-Demand Talent

iOS Developer
Front-End Developer
UX Designer
UI Designer
Financial Modeling Consultants
Interim CFOs

About
Top 3%
Clients
Freelance Developers
Freelance Designers
Freelance Finance Experts
About Us

Contact

Contact Us
Press Center
Careers
FAQ

Social
Facebook
Twitter
Google+
LinkedIn

Toptal

Hire the top 3% of freelance talent

Copyright 2010 - 2017 Toptal, LLC

Privacy Policy
Website Terms

Home Blog GraphQL vs. REST - A GraphQL Tutorial


Hiring? Toptal handpicks top API development specialists to suit your needs.

Start hiring
Login

Das könnte Ihnen auch gefallen