A GraphQL Tutorial | Toptal [PDF]

All clients would hit the GraphQL endpoint, and this endpoint would hit the database layer, an external service like Ela

4 downloads 35 Views 556KB Size

Recommend Stories


Read PDF SOLIDWORKS 2016: A Tutorial Approach
If you feel beautiful, then you are. Even if you don't, you still are. Terri Guillemets

Oracle tutorial beginners pdf
I cannot do all the good that the world needs, but the world needs all the good that I can do. Jana

Tutorial 2 (PDF)
Life is not meant to be easy, my child; but take courage: it can be delightful. George Bernard Shaw

Perl Tutorial pdf
Open your mouth only if what you are going to say is more beautiful than the silience. BUDDHA

[PDF] SOLIDWORKS 2016: A Tutorial Approach
The only limits you see are the ones you impose on yourself. Dr. Wayne Dyer

[PDF] SOLIDWORKS 2016: A Tutorial Approach
Never let your sense of morals prevent you from doing what is right. Isaac Asimov

Ableton Live Tutorial Pdf
Do not seek to follow in the footsteps of the wise. Seek what they sought. Matsuo Basho

Oracle 9i Tutorial Pdf
Be who you needed when you were younger. Anonymous

Wireless Communication Tutorial [PDF]
Wireless Communication Tutorial for Beginners - Learn Wireless Communication in simple and easy steps starting from basic to advanced concepts with examples including Overview, Terms in Mobile Telephony, Multiple Access, Channel Characteristics, TCP/

Csharp Tutorial Pdf
Stop acting so small. You are the universe in ecstatic motion. Rumi

Idea Transcript


Hiring? Toptal handpicks top API development specialists to suit your needs. Start hiring Log in Top 3% Why Clients Enterprise 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 0shares

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 you’ve already made your mind for GraphQL or you’re 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 we’ll dive into it in the second part. On the left pane of the interface is the query. Here, we are fetching all the users—we 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 it’s 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 Let’s 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. Let’s 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.

It’s 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. Here’s 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 wouldn’t 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 models—user, project, and task— are 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. 0shares

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. Let’s 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.

What’s Next? This article’s aim is to give you a taste of what GraphQL looks like and show you that it’s 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 haven’t 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

graphql-js

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

graphql-server

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

Implementations for other platforms

Ruby, PHP, etc.

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 won’t 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 GitNode.jsReact.jsJavaScriptCSS3HTML5 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 Technologies 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 March 2018 8 Comments

Toptal

Recommend 5

1

Login

Sort by Best

Share

Join the discussion… Dima Pilipenko • 3 months 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 • 3 months 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. 1

• Reply • Share ›



Tom T. • 3 months 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. • 3 months 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 • 3 months 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 • 3 months ago

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

• Reply • Share ›

Michel H. • 3 months 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. • 3 months ago

Thanks!

Subscribe

• Reply • Share ›

Add Disqus to your siteAdd DisqusAdd

Privacy

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. 0shares

Trending articles

Time-locked Wallets: An Introduction to Ethereum Smart Contracts5 days ago Database Migrations: Turning Caterpillars into Butterflies10 days agoAn Angular 5 Tutorial: Step by Step Guide to Your First Angular 5 App26 days agoBlockchain, IoT, and the Future of Transportation: Understanding the Motoro Coinabout 1 month agoMixed-integer Programming: A Guide to Computational Decision-makingabout 1 month agoExploring Supervised Machine Learning Algorithmsabout 1 month agoCommand Line Tools for Developersabout 1 month agoREST Assured vs. JMeter: A Comparison of REST Test Toolsabout 2 months 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 Technologies 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 - 2018 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 Log in

Smile Life

When life gives you a hundred reasons to cry, show life that you have a thousand reasons to smile

Get in touch

© Copyright 2015 - 2024 PDFFOX.COM - All rights reserved.