GraphQL is an API query language. It provides a runtime to describe and query the data, no matter what the storage engine is.



GraphQL is an API query language. It provides a runtime to describe and query the data, no matter what the storage engine is.

GraphQL's benefits include

Typed data

Get what you asked for

Multiple data requests in one call

One endpoint, changes in API are now bit easier

Subscriptions

etc.

For example, consider a system similar to a social network where we have users and they have other users as friends. Following entity will completely encapsulate the data model; how it is going to be dealt in Back End and Front End, we will see after that.

type User { id: String! fullName: String name: Name email: String! friends: [User] } type Name { first: String last: String }

For this data description, the front end will sent the request to data as follows:

{ user(id: "5a826fdf9856ad6503d728d5") { id name { first last } email friends { id email } } }

And will receive the response as follows:

And the good part is that the data can be from any interface, be it the RDBMS, NoSQL DB, a File or even in-memory operation.

GraphiQL

GraphiQL is a GUI tool to explore the GraphQL API. It lets you design your queries, play with the combinations and other things for the provided endpoint.

This tool also serves as a Documentation for the GraphQL API.

For above queries, following is the GraphiQL view:

In above screenshot, you can:

design your query in the left panel

see documentation in the right panel

see the data response in the middle panel

You can use the variables to optimize your queries, as shown in following way; the query can be exactly same in GraphiQL and and the FrontEnd, variables are passed separately:

Back End

Lets take a deep look at the following example of graphql with express , a node.js server framework.

Dependencies:

npm i -S apollo-server-express graphql-tools graphql express body-parser uuid node-fetch

Server:

const express = require('express'); const bodyParser = require('body-parser'); const { graphqlExpress, graphiqlExpress } = require('apollo-server-express'); const { makeExecutableSchema } = require('graphql-tools'); // The GraphQL schema in string form const typeDefs = require('./schema'); // The resolvers const resolvers = require('./resolvers'); // Put together a schema const schema = makeExecutableSchema({ typeDefs, resolvers, }); // Initialize the app const app = express(); // The GraphQL endpoint app.use('/graphql', bodyParser.json(), graphqlExpress({ schema })); // GraphiQL, a visual editor for queries app.use('/graphiql', graphiqlExpress({ endpointURL: '/graphql' })); // Start the server app.listen(3000, () => { console.log('Go to http://localhost:3000/graphiql to run queries!'); });

Schema:

module.exports = ` type Mutation { addUser(first: String, last: String, email: String, picture: String, friends: [String]): User } type Query { users: [User] user(id: String!): User } type User { id: String! fullName: String name: Name email: String! friends: [User] } type Name { first: String last: String } `;

Resolvers:

const uuid = require('uuid/v4'); // Some fake data const users = require('./users'); const friendsMapper = id => (Object.assign( {}, users[id], { friends: users[id].friends.map(i => users[i]) } )); // The resolvers module.exports = { Query: { users: () => Object.values(users).map(u => friendsMapper(u.id)), user: (_, {id}) => friendsMapper(id), }, Mutation: { addUser: (_, data) => { const uid = uuid(); users[uid] = Object.assign({}, data, {id: uid}) return friendsMapper(uid); } } };

And Data:

As the server.js is executed, the server will be up at port 3000 and then graphiql & graphql endpoints are available to use.

Brief Steps

Lets review above code in brief steps:

create schema definition as a string (see schema.js ); schema has following: types: the entities which are going to be used in the GraphQL Query type: this is a root type for all the queries that the API consumer can request Mutation type: this will contain all the data modification queries

); schema has following: create resolvers to define how data I/O should be done; this will have following in an object Query : all the query resolvers will reside under this key and should match the Query type in schema Mutation : same as queries, all the mutation will reside under this and should match with what is there in the Mutation type in schema

make the schema executable by makeExecutableSchema

attach the route /graphql to the express by the apollo plugin as app.use('/graphql', bodyParser.json(), graphqlExpress({ schema }));

to the express by the apollo plugin as attach the /graphiql route as app.use('/graphiql', graphiqlExpress({ endpointURL: '/graphql' }));

route as start the server 🚀

As above code list the example of data being seeded through JSON file and then completely in memory.

REST Endpoints in GraphQL

You can also make the resolver to fetch the data form an endpoint and then return it, consider following schema and resolver:

const typeDefs = ` type Post { id: Int! userId: Int title: String body: String } type Query { posts: [Post] } `; const resolvers = { Query: { posts: async () => fetch('https://jsonplaceholder.typicode.com/posts') .then(response => response.json()) } } module.exports = { typeDefs, resolvers }

And the queries can be used as shown in following screenshot:

And in similar manner you can make it work with other data tools like mongodb, SQL etc.

Front End

From front end point of view, the use of graphql is pretty simple as there are not many things changing; and is approximately similar effort.

Though any change in requirement of data will introduce change in the request-query as well; which in case is good because the errors are intended and hence fixed right away.

Lets take a look at basic vanilla JS code to get data and show it on front end. For certain, this code will be passed through bundler like webpack or rollup .

Dependencies:

npm i -D [email protected] webpack-cli npm i -S graphql graphql-tag apollo-cache-inmemory apollo-client apollo-link-http

Code:

import { ApolloClient } from 'apollo-client'; import { HttpLink } from 'apollo-link-http'; import { InMemoryCache } from 'apollo-cache-inmemory'; import gql from 'graphql-tag'; const client = new ApolloClient({ link: new HttpLink({ uri: 'http://localhost:3000/graphql' }), cache: new InMemoryCache() }); client.query({ query: gql` query users { users { id fullName email } } `, }) .then(({data}) => appendData(data)) .catch(error => console.error(error)); const appendData = (data) => { console.log(data); const app = document.querySelector('#app'); app.innerHTML = ''; data.users.map(user => { const d = document.createElement('div'); d.innerHTML = `<div class="user"> <h3>${user.fullName}</h3> <p>${user.email}</p> </div>`; app.appendChild(d.firstElementChild); }) }

And it will look like following in the HTML page

Conclusion

GraphQL is considered a replacement or alternative to REST API. Above examples show a quick configuration and usage of GraphQL on both BackEnd and FrontEnd; the actual usage requires more configuration and proofing. The real world use case also involves complex schema and resolvers, which will pose you different challenges.

Let us know your experiences and troubles while using GraphQL via comments and social network.

Thank you!

Check the code on GitHub