Is graphql a better way to build APIs?
by Saurav Singh, Software Engineer
Before You Begin
Orignally published on Plain English in 2019
Ever since Facebook open-sourced GraphQL, its popularity has skyrocketed, becoming almost ubiquitous today. But what makes it so popular? How does it compare to REST architecture, and will it eventually replace REST APIs? Here’s what I think about GraphQL.
When I first started learning GraphQL, I had zero prior knowledge. I assumed it would be entirely different from REST APIs. However, halfway through my learning journey, I realized I had developed some misconceptions, the biggest being that GraphQL is completely distinct and doesn’t use any concepts we’re familiar with in REST APIs. This is far from true. It’s a common misconception among those who haven’t delved into GraphQL.
What Exactly Is GraphQL?
If I were to define it in the simplest terms, I’d say GraphQL is just a specification—a very cool way of utilizing existing web technologies. Under the hood, GraphQL queries are simply HTTP POST requests to an API’s endpoint. Yes, it's a POST request to an endpoint designed to handle requests containing GraphQL queries. Let's quickly explore this by building a GraphQL server.
For simplicity’s sake, I’ll use Node.js, but since GraphQL is a runtime in itself, it doesn’t matter what language we use to build an API. Let’s install the dependencies:
npm install apollo-server moment
And build a simple GraphQL API
const { ApolloServer, gql } = require("apollo-server");
const moment = require("moment");
const server = new ApolloServer({
resolvers: {
Query: {
getDateTime: () => ({
date: moment().format("MMM DD YYYY"),
isoString: new Date().toISOString(),
}),
},
},
typeDefs: gql`
type dateTime {
date: String!
isoString: String!
}
type Query {
getDateTime: dateTime
}
`,
});
server
.listen(4000)
.then(() =>
console.log(
`Application worker ${process.pid} is running a server at http://localhost:4000`
)
);
To run a query
curl -X POST -H "Content-Type: application/json" --data '{ "query": "{ getDateTime { date isoString } }" }' http://localhost:4000
This will return the current date and time in the format we specified in the getDateTime
resolver.
Wait this isn’t how you run a query in GraphQL!
You're right, and if you’ve ever used GraphQL Playground, you’d know it. But this is exactly what I was talking about earlier. Under the hood, a GraphQL client (like GraphQL Playground) sends a POST request to the specified API endpoint with a body similar to the one above. The GraphQL runtime knows how to handle the request because it has a schema for the data it’s going to receive and send back.
However, this can sometimes lead to unexpected behavior if you return a value for something not specified in the type definitions. GraphQL tries to automatically typecast the value and will fail if it doesn’t work.
Is Schema the Only Reason GraphQL Is So Powerful?
No, there’s much more. GraphQL empowers your APIs, especially on the client side, by allowing clients to query only specific fields. This means they can request only the data they need, which reduces transfer size, bandwidth, and latency. Let’s modify our code from above and see this in action.
const { ApolloServer, gql } = require("apollo-server");
const moment = require("moment");
const server = new ApolloServer({
resolvers: {
Query: {
getDateTime: () => ({
date: moment().format("MMM DD YYYY"),
isoString: new Date().toISOString(),
localString: new Date().toLocaleString(),
}),
},
},
typeDefs: gql`
type dateTime {
date: String!
isoString: String!
localString: String!
}
type Query {
getDateTime: dateTime
}
`,
});
server
.listen(4000)
.then(() =>
console.log(
`Application worker ${process.pid} is running a server at http://localhost:4000`
)
);
We’ve added another field to the type dateTime, and this time we don’t want to query the other two fields. And it’s really dead simple, all we have to do is specify the fields we are interested when making a request like below
curl -X POST -H "Content-Type: application/json" --data '{ "query": "{ getDateTime { localString } }" }' http://localhost:4000
For a small application, this might not make much difference. But for a large application, you always want the most optimized solutions. The ability to query only the required fields is powerful, and it’s always been a pattern in traditional REST architecture to create routes for retrieving specific data. This works fine for small applications and theoretically, but as the app grows larger (think Facebook), the complexity increases, and you might find yourself needing to redesign the system using something like GraphQL.
There’s still a lot more cool stuff that GraphQL offers (like Subscriptions), but we’ll save that for another article. For now, let's discuss whether GraphQL is better than traditional REST APIs.
Is GraphQL Really Better Than REST? Will It Replace REST Completely?
I agree that GraphQL is a better version of REST and a powerful alternative, but it’s not going to replace REST APIs today or anytime soon. Here are a couple of reasons why:
- For small applications, a REST API can do almost everything a GraphQL API can.
- GraphQL gives more power to the clients by allowing them to query only the fields they need, but this comes at the cost of server-side performance. If a client requests a lot of nested fields that require multiple resources (like reading from a file system or database) and there are millions of such requests with servers that can’t scale quickly, you’ll eventually run out of resources.