It's good practice to start new IT projects by considering how to easily and quickly consume and display data, and one of the first steps is creating or choosing the right API for your business. So why not choose an API that's a universal query language and provides a modern approach to accessing your data sources?
With its growing popularity, you have probably already heard about GraphQL, another great tool that Facebook developers make available to the world in addition to React. GraphQL was developed internally by Facebook in 2012 before being released to the public in 2015.
Advantages of GraphQL
- A single endpoint.
- No more over-fetching.
- No more under-fetching.
- Display changes in real time.
- Access multiple data sources from a single point.
- Front-end teams can easily test their applications by mocking up the required data structures.
- Services usually respond using JSON, which is easy to read and debug.
- Works with other JavaScript-based libraries and frameworks, such as Vue, Angular, and others.
- Can be used with any back-end framework or programming language.
GraphQL vs Rest
Let's take a look at the Rest call image below:
Image courtesy of How to GraphQL
As How to GraphQL explains, "With REST, you have to make three requests to different endpoints to fetch the required data. You’re also overfetching since the endpoints return additional information that’s not needed."
One solution used in Rest API is query parameters. It works, but it requires complex logic and has no flexibility. Furthermore, working in this way slows the whole process of developing other data endpoints.
How GraphQL Works in the Same Situation
Image courtesy of How to GraphQL
Much simpler, don't you think?
How it Works
The syntax is simple and easy to understand. Developers who are familiar with JSON will quickly adapt to GraphQL. Look at the image below to see what this query returns.
Schema & Type System
GraphQL's Schema Definition Language (SDL) serves as the contract between the client and the server to define how a client can access the data.
BASIC TYPES
String
Int
Float
ID
Boolean
OPERATION TYPES
Queries: are data requests to the server based on your needs.
Mutations: are used to insert, update, or delete data.
Subscriptions: push data from the server to the clients who chose to listen to real-time messages from the server.
RESOLVERS
Resolvers provide the instructions for turning a GraphQL operation into data. Resolvers are organized into a one to one mapping to the fields in a GraphQL schema. - Apollo Docs
GraphQL Best Practices
The following recommendations are brief paraphrases of the best practices listed on the GraphQL website.
HTTP
Avoid creating a suite of URLs. GraphQL supports this, but having a suite of URLs makes it harder to access GraphQL tools like the IDE, and you will also have other endpoints, which goes against the main idea behind GraphQL.
JSON (with GZIP)
In a production GraphQL service, it's recommended that GZIP compression is enabled. So in client requests, we can set in the header:
Accept-Encoding: gzip
Versioning
As with any other API, you can start versioning your GraphQL Project, but usually you have to do this when you have limited control over the data that is returned or when you have new features.
GraphQL only returns what is explicitly requested, so new capabilities can be added via new types and new fields on those types without introducing a big change in the code.
Nullability
By default, all types in GraphQL are nullable and can go awry in a networked service backed by databases and other services.
Pagination
The GraphQL type system allows for some fields to return lists of values but leaves the pagination of longer lists of values up to the API designer.
Ultimately, designing APIs with feature-rich pagination led to a best practice pattern called "Connections."
Server-Side Batching & Caching
A naive GraphQL service can be very "chatty" or repeatedly load data from your databases. A good way to handle that is to collect multiple requests and later dispatch them in a single request.
A good tool is Facebook DataLoader.
Some Front-End Clients to Make Your Life Easier
- Relay
- Apollo Client
Some advantages:
Data fetching
Caching logic
Easier pagination
GraphQL Examples for Two Different Scenarios
Below, I will give two very brief examples of GraphQL implementations, one for the flow and the other for the source code.
CONSUMING AND PROVIDING DATA WITH APOLLO/GRAPHQL IN AN ORACLE DATABASE
Back-End Provider
First, you need to define your endpoint:
const schema = graphqlTools.makeExecutableSchema({typeDefs, resolvers});
graphqlAC.use('/graphql', graphql({
graphiql: true,
schema
}));
const typeDefs = `
type Post {
identifier: Int!,
title: String!
},
`
}
const resolvers = {
Query: {
posts(root, args, context, info) {
return getAllPosts();
},
},
};
async function getAllPosts() {
let sql = 'select * from posts';
const result = await database.simpleExecute(sql);
let allPosts = [];
for (let r of result.rows){
const newTitle = {"identifier": r.IDENTIFIER, "title": r.TITLE};
allPosts.push(newTitle);
}
return allPosts;
}
Front-End Consumer
In your React application, you must connect your app component, wrapping it with the ApolloProvider tag:
const client = new ApolloClient({ uri: 'http://localhost:5000/graphql' });
<ApolloProvider client={client}>
<App />
</ApolloProvider>
const GET_MOTIVO = gql`
{
posts {
identifier
title
}
}
`
const Apollo = () => (
<Query query={GET_MOTIVO}>
{({ loading, error, data }) => {
if (loading) return <div>Loading...</div>;
if (error) return <div>Error :(</div>;
return data.motivos.map(({ identifier , title }) => (
<div key={identifier}>
<p>{`${identifier}: ${title}`}</p>
</div>
));
}}
</Query>
QRAPHQL WORKING WITH MONGODB
Back-End Provider
As with the fist scenario, we start by defining an endpoint.
app.use('/graphql',
graphqlHttp({
schema : graphiqlSchema,
rootValue: graphilResolvers,
graphiql: true
})
);
type Event {
_id: ID!
title: String!
description: String
price: Float!
date: String!
creator: User!
}
type RootQuery{
events: [Event!]!
}
events: async () => {
try {
const events = await Event.find();
return events.map(event => {
return event;
});
} catch(err) {
throw err;
}
},
Front-End Without a Client
The following example shows how to consume a GraphQL service without a client:
fetchEvents() {
const requestBody = {
query: `
query {
events {
_id
title
date
description
price
creator {
_id
}
}
}
`
};
fetch('http://localhost:5000/graphql', {
method: 'POST',
body: JSON.stringify(requestBody),
headers: {
'Content-Type': 'application/json',
}
}).then(res =>{
if(res.status !== 200 && res.status !== 201){
throw new Error ('Failed');
}
return res.json();
}).then(resData => {
const events = resData.data.events;
this.setState({ events : events});
}
}).catch(error => {
console.log(error);
});
}
Conclusion
The main goal of the two different scenarios above is to demonstrate how flexible, powerful, and easy to use your APIs can be with GraphQL. So don't be afraid to use GraphQL in your next project--at least make one MVP to try it out. Be brave!
References/Further Reading:
For references and further reading, I recommend that you check out:
3. The New York Times - Now on Apollo
5. React, Relay and GraphQL: Under the Hood of The Times Website Redesign
6. React and GraphQL at the NYTimes
Author
Leandro Rezende Pinheiro
Leandro Pinheiro is a UI Engineer at Avenue Code. In addition to being addicted to web application solutions, he is a movie marathonist and a music lover who enjoys having a good beer by his side.