GraphQL Uncovered
So, GraphQl…….. ummmm… okay. Let’s talk about GraphQL.
In 2000, Roy Fielding in his doctoral dissertation titled "Architectural Styles and the Design of Network-based Software Architectures" at the University of California, Irvine. In little to no time REST got so popular that developers started seeing it as an alternative to SOAP (Simple Object Access Protocol).
Somehow in some ways, these times also feel like the early 2000s of REST but for GraphQL this time. However, it was initially developed internally at Facebook in 2012 to handle more efficient data fetching for their mobile applications. Facebook later open-sourced GraphQL in 2015, making it publicly available for developers to use as an alternative to traditional REST APIs.
GitHub Engineering Team: "GraphQL was a natural fit for GitHub's API because it allows us to expose our complex data graph, and users can now query exactly the data they need."
Stripe Developer Blog: "GraphQL gives us the flexibility to create APIs that are easier to use and adapt over time, which has been instrumental in building more scalable systems."
Phil Sturgeon, Developer Advocate, Stoplight: "GraphQL offers a declarative way of fetching data and allows clients to specify what they want, in stark contrast to REST’s rigidity. It's a game-changer in API development."
So, GraphQl is good. But, what it is exactly and how is it so good that it is seen as an alternative to REST?
What is GraphQL?
There are different defining statements for graphQL, all of them are correct but describe it differently. Let’s have a look at each of them.
Official GraphQL Website: GraphQL is a query language for APIs and a runtime for fulfilling those queries with your existing data. GraphQL provides a complete and understandable description of the data in your API, gives clients the power to ask for exactly what they need and nothing more, makes it easier to evolve APIs over time, and enables powerful developer tools.
Apollo GraphQL: "GraphQL is a flexible and powerful alternative to REST for defining how data is requested and fetched from a server."
Prisma.io: “GraphQL is a strongly-typed query language that describes how to request data from an API, making data queries more efficient, understandable, and adaptable.”
Keeping all these definitions in mind, I came up with this definition.
GraphQL is a powerful query language for APIs that allows clients to request exactly the data they need in a single request. Unlike traditional REST, it provides flexibility by enabling users to tailor their data queries to specific requirements. This approach enhances performance and improves the overall developer experience by simplifying data retrieval.
Now, let’s talk about what problems GraphQL solves.
Performance Related Issues:
Over-fetching and Under-fetching:
Problem: In REST APIs, clients often receive more data than needed (over-fetching) or require multiple requests to get all necessary data (under-fetching).
Solution: GraphQL allows clients to specify exactly what data they need, reducing the amount of data transferred and the number of requests made.
Multiple Endpoints:
Problem: REST APIs often require multiple endpoints for different resources, leading to complex client-side logic.
Solution: With GraphQL, a single endpoint handles all data queries, simplifying the API structure and making it easier for clients to interact with the API.
Data Related Issues:
Inconsistent Data Structures:
Problem: REST APIs may return inconsistent data structures, leading to additional client-side handling and processing.
Solution: GraphQL enforces a strong typing system with a consistent schema, ensuring that clients always know what data to expect.
Complex Data Relationships:
Problem: Navigating complex relationships between resources can lead to convoluted queries in REST APIs.
Solution: GraphQL supports querying nested data and relationships in a single request, making it easier to work with complex data models.
As we can see, GraphQL does solve important problems that could be caused by a REST API.
Key Concepts:
Let’s talk about some key concepts and features that define graphQL as what it is today.
1. Queries
Queries in GraphQL are used to retrieve data from the server. They allow clients to specify the exact structure of the response they want. This means you can request not just top-level fields, but also nested data in one go. For example, if you want information about a user and their posts, you can request both the user details and the associated posts in a single query. This reduces the number of network requests and optimizes data retrieval, ensuring that clients only receive the data they need.
To retrieve information about all the posts from a user:
query {
userPosts(id: 1) {
id,
posts {
id
title
content
}
}
}
This query would return:
{
"data": {
"user": {
"id": 1,
"posts": [
{
"id": 101,
"title": "First Post",
"content": "This is my first post."
},
{
"id": 102,
"title": "Second Post",
"content": "Here's another post."
}
]
}
}
}
2. Mutations
Mutations are used to modify data on the server, similar to how you would use POST, PUT, or DELETE methods in REST APIs. With mutations, clients can create new data entries, update existing ones, or delete data. Each mutation typically returns the updated data, allowing clients to synchronize their local state with the server. This makes it easy to perform operations like adding a new user, updating a post, or deleting a comment, all through well-defined mutation queries.
mutation {
createPost(userId: 1, title: "My New Post", content: "This is the content of the new post.") {
id
title
content
user {
id
name
}
}
}
We use the
createPost
mutation to create a new post for a user withuserId: 1
.The mutation returns the newly created post’s
id
,title
, andcontent
, as well as some user information.
As we defined in our schema the createPost mutation will return the post we just created. An example return would look like:
{
"data": {
"createPost": {
"id": 103,
"title": "My New Post",
"content": "This is the content of the new post.",
"user": {
"id": 1,
"name": "John Doe"
}
}
}
}
3. Schemas and Types
A GraphQL API is defined by a schema that outlines the types of data available and how clients can interact with them. The schema serves as a contract between the client and server, specifying the types of data that can be queried or mutated. These types can include custom objects that represent different entities in your application, such as User
, Post
, or Comment
. Each type can have its fields, and you can define relationships between types, making it clear how different pieces of data connect and interact within your application.
In addition to defining types and schemas, we also define how mutation and query types. Here’s an example:
type User {
id: ID!
name: String!
email: String!
posts: [Post!]!
}
type Post {
id: ID!
title: String!
content: String!
user: User!
}
type Query {
user(id: ID!): User
post(id: ID!): Post
}
type Mutation {
createPost(userId: ID!, title: String!, content: String!): Post
createUser(id: ID!, name: String!, email: String!): User
}
We define a
User
type with fields likeid
,name
,email
, and a list ofposts
(represented by thePost
type) and aPost
the type has fields likeid
,title
,content
, and a reference to theuser
who created the post.The
Query
type allows clients to query users or posts.The
Mutation
type defines thecreatePost
mutation, which takes inuserId
,title
, andcontent
as arguments and returns a new post. The same goes forcreateUser
mutation.
4. Resolvers
Resolvers are functions responsible for fetching the data for each field in a query or mutation. When a query is executed, GraphQL uses resolvers to determine how to fetch the requested data. Each field in the query is linked to a resolver that knows how to retrieve that specific piece of information, whether it’s from a database, an external API, or some other source. This decouples the data-fetching logic from the API structure, allowing for more modular and maintainable code. Resolvers ensure that the right data is fetched and returned in the format specified by the query.
const resolvers = {
Query: {
user: (parent, args, context, info) => {
// Fetch the user by id from a database
return context.db.findUserById(args.id);
},
post: (parent, args, context, info) => {
// Fetch the post by id from a database
return context.db.findPostById(args.id);
}
},
Mutation: {
createPost: (parent, args, context, info) => {
// Create a new post and associate it with a user
return context.db.createPost({
userId: args.userId,
title: args.title,
content: args.content
});
},
createUser: (parent, args, context, info) => {
// Create a new post and associate it with a user
return context.db.createUser({
Id: args.Id,
name: args.name,
email: args.email
});
}
},
User: {
userPosts: (parent, args, context, info) => {
// Fetch all posts for a given user
return context.db.findPostsByUserId(parent.id);
}
},
Post: {
user: (parent, args, context, info) => {
// Fetch the user who created the post
return context.db.findUserById(parent.userId);
}
}
};
Mapping GraphQL’s features with REST makes learning easier since they are different technologies for the same use case.
So, GraphQL has been making its way into the industry, it is becoming more popular, and more people use it in their projects(even my next project uses graphQL). Thus, we can assume that in the coming years, graphQL will become or maybe already has become an alternative to REST. Alr Goodbye that was it for this one.
Subscribe to my newsletter
Read articles from Shikhar Upadhyay directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Shikhar Upadhyay
Shikhar Upadhyay
I am computer science student with a special interest in Backend Engineering!!!