Easily restore your project to a previous version with our new Instant One-click Backup Recovery

Why GraphQL is a must for your content delivery

Benefits of using GraphQL and how Hygraph uses GraphQL for content delivery.
Joel Olawanle

Joel Olawanle

Apr 12, 2024
Why GraphQL is ideal for content delivery

Content delivery involves transmitting digital content (text, images, and videos) from its point of creation to the end user's device efficiently, reliably, and in a scalable manner.

Before GraphQL(GQL) was developed, the major way of delivering content was through REST APIs. This had so many shortcomings, especially in terms of over-fetching and under-fetching. The rise of GraphQL in 2015 provided an innovative approach to data querying and manipulation for modern content delivery needs.

This article delves into the numerous benefits of using GraphQL for content delivery. It also explores how Hygraph, the first GraphQL-native headless content management system (CMS), uses GraphQL for content delivery.

#Why is GraphQL ideal for content delivery?

GraphQL was developed by Meta (previously Facebook) in 2012 as a response to the evolving requirements of modern web and mobile applications. At the time, Facebook was transforming significantly, shifting from a primarily web-based platform to a mobile-first approach.

This transition highlighted several limitations with the traditional REST API approach, which struggled to efficiently handle modern social applications' complex interconnected data models, especially in mobile environments where network performance and data efficiency are critical.

The 2024 GraphQL Report provides insights into GraphQL usage trends and how developers build and consume GraphQL APIs. This comprehensive analysis underscores the advantages of GraphQL in contemporary development practices, reinforcing its ideal status for content delivery and API management.

Let’s explore the top reasons that make GraphQL ideal.

#Efficiency in data retrieval

This is a cornerstone of GraphQL's design, directly addressing the challenges of bandwidth usage and the speed of data fetching in web and mobile applications.

This efficiency is achieved through GraphQL's ability to let users specify exactly what data they need, no more, no less, in a single query. This approach contrasts with traditional REST APIs, which often return fixed data structures, sometimes containing more information than required (over-fetching) or necessitating additional requests for missing data (under-fetching).

By reducing unnecessary network traffic and data processing, GraphQL enhances application performance and user experience, especially on mobile devices or in environments with limited bandwidth.

Consider an application that displays a user profile. With a REST API, fetching this profile might require calling an endpoint that returns extensive user information, including data not needed for the current view, such as the user's posts, friends list, and more.

GET /api/user/123
// Response
{
"id": "123",
"name": "John Doe",
"email": "john@example.com",
"posts": [...],
"friendsList": [...]
// Potentially more unneeded data
}

With GraphQL, you can query only the needed data, such as the user's name and email, avoiding over-fetching posts and friends lists.

query GetUserProfile {
user(id: "123") {
name
email
}
}
// Response
{
"data": {
"user": {
"name": "John Doe",
"email": "john@example.com"
}
}
}

#Using a single request for multiple resources

In a RESTful architecture, obtaining related resources often requires separate requests to different endpoints.

For instance, if you need information that requires data from multiple sources (e.g., user details, recent posts, and notifications), it might involve making several separate requests to different endpoints.

GET /api/user/123
GET /api/user/123/posts?limit=5
GET /api/user/123/notifications

This not only increases the load time but also complicates client-side data management.

In contrast, GraphQL combines these requests into a single query, significantly reducing the number of network round-trips and streamlining data retrieval.

query GetUserDashboard {
user(id: "123") {
name
email
recentPosts(limit: 5) {
title
content
}
notifications {
message
createdAt
}
}
}

The response will look like this:

{
"data": {
"user": {
"name": "John Doe",
"email": "john@example.com",
"recentPosts": [
// Array of the 5 most recent posts
],
"notifications": [
// Array of recent notifications
]
}
}
}

Also, consider an application that displays user profiles, recent posts, and comments. A typical GraphQL query for this data might look like this:

query GetUserProfile {
user(id: "123") {
name
email
profilePicture(size: 100)
posts(limit: 5) {
title
content
comments(limit: 2) {
content
author {
name
}
}
}
}
}

In this example, the query requests a user's name, email, profile picture, and the titles and contents of their last five posts, including the first two comments on each post with the comment authors' names.

Achieving this in a RESTful API would typically require multiple requests: one for the user, one for their posts, and additional requests for each post's comments. GraphQL's ability to handle this in a single request significantly simplifies data fetching logic and reduces latency.

You can also merge multiple GraphQL schemas into one and query them with one request through schema stitching. This means a client can query a single GraphQL endpoint and retrieve data from multiple services, databases, or APIs as if they were a single source.

For Hygraph, combining multiple APIs and resources to query their content is called Content Federation. In your Hygraph project, you can add a remote source (could be a REST API) and create a remote field, and then you’d be able to request these resources alongside others in one request.

For example, let’s clone and explore the Hygraphlix project from Hygraph’s marketplace. You will notice a movies schema with a Federate Movie field plugged into it. This accesses a remote source API to receive information about each movie, like the title, year, writer, actors, etc.

query Movies {
movies {
createdAt
id
imdbId
moviePlayer
publishedAt
slug
title
updatedAt
federateMovie {
data {
Title
Writer
Genre
Country
}
}
}
}

This will return an array of movies with an object containing the federated content.

#Strongly-typed schema

This foundational aspect ensures data consistency and integrity across an application. This system requires that every piece of data queried and manipulated through a GraphQL API be associated with a specific type, such as String, Int, Boolean, or a custom object type.

This strong typing enforces a contract between the client and server, ensuring data conforms to a predefined structure. As a result, developers can build more reliable and maintainable applications, with the GraphQL schema serving as a form of documentation and validation mechanism.

For example, consider a blog platform where you have posts and authors. The GraphQL schema for this platform might look something like this:

type Post {
id: ID!
title: String!
content: String!
author: Author!
}
type Author {
id: ID!
name: String!
posts: [Post!]!
}

In this schema, the Author type has ID, String, and the array notation [Post!]! which represent the types of the fields. The ! indicates that the field is non-nullable, meaning it must return a value in a query.

Given the above schema, if you wanted to retrieve the name of an author and the titles of their posts, your GraphQL query would look like this:

query {
author(id: "1") {
name
posts {
title
}
}
}

This query explicitly states what data it expects in return based on the types defined in the schema. The server then validates this query against the schema before execution, ensuring that only valid queries are processed.

If the query asks for a field that doesn't exist or provides a data type that doesn't match the schema, GraphQL will return an error before data processing happens.

#Low maintenance

One of the standout features of GraphQL is its approach to API maintenance, particularly the elimination of the need for versioning commonly found in REST APIs.

In a traditional REST setup, introducing changes or new features often requires creating new API versions to avoid breaking existing clients. This process can lead to a proliferation of versions that developers must maintain and clients must navigate, complicating the development and use of the API.

GraphQL addresses this challenge by allowing APIs to evolve without requiring versioning. This is achieved through its flexible query structure, which lets clients specify the exact data they need.

New fields and types can be added to a GraphQL API without impacting existing queries. Unused fields can be deprecated rather than removed, providing clear guidance to developers about the current state of the API while maintaining backward compatibility.

For example, suppose you initially have a GraphQL type for a user:

type User {
id: ID!
name: String!
email: String!
}

Subsequently, if you decide to add a new field, birthdate, to provide more information, the updated type might look like this:

type User {
id: ID!
name: String!
email: String!
birthdate: String
}

Clients that do not need the birthdate can continue querying User objects without including it, ensuring their existing queries remain unaffected. This seamless introduction of new features without breaking changes exemplifies GraphQL's advantage in API evolution.

#Transformations and mutations

GraphQL's flexibility extends beyond just fetching data; it also revolutionizes how we can manipulate and transform that data, especially in content delivery.

This capability is particularly valuable when dealing with media assets, such as images or files, allowing for dynamic adjustments based on the requirements of different platforms or user preferences.

Transformations are particularly useful in content delivery scenarios where the data consumed by the client may need to be presented differently depending on the context, such as resizing images for mobile devices or converting document formats for compatibility purposes.

Consider a scenario where you're working with a GraphQL API that returns information about products, including images. You might want the images to be a specific size when displayed on a product detail page. A transformation in the query could look like this:

query GetProductImage($productId: ID!) {
product(id: $productId) {
name
image {
url
resizedImage: url(transformation: {width: 100, height: 100})
}
}
}

In this example, the resizedImage field applies a transformation to the original image URL, requesting a version of the image that's 100x100 pixels. This transformation is defined directly within the query, allowing for dynamic adjustments based on the application's requirements.

While transformations adjust how data is presented in the response, mutations are about changing the data on the server. In GraphQL, a mutation is an operation that allows clients to modify server-side data—adding, updating, or deleting records.

Mutations are defined in the GraphQL schema and are essential for any application that requires interactive features, such as creating user profiles, posting comments, or updating settings. Here’s how a mutation might be structured to update a user's profile information:

mutation UpdateUserProfile($id: ID!, $email: String, $name: String) {
updateUser(id: $id, email: $email, name: $name) {
id
email
name
}
}

This mutation, UpdateUserProfile, takes the user's ID and the new values for the email and name fields as input. It updates the user's profile with the provided values and returns the updated user data.

When using Hygraph, its projects come equipped with an Asset model, integral for managing a wide array of file types, from images and videos to PDFs and .zip files. This model is customizable, localized by default, and extends system fields, providing a robust foundation for asset management.

Consider a scenario where you need to display product images on a website but require them to fit specific dimensions without distorting their aspect ratio. Hygraph's GraphQL API enables you to request these transformations directly within your query:

{
product(where: { slug: "example-product" }) {
images {
url(transformation: {
image: { resize: { width: 100, height: 100, fit: "clip" } }
})
}
}
}

This query fetches the images related to a product. It applies a transformation to resize each image to 100x100 pixels, using the clip method to preserve the original aspect ratio.

Hygraph's asset transformation capabilities are not limited to resizing images. You can also convert files from one format to another, supporting many file types. This feature is invaluable for content delivery platforms that must serve content in different formats across various channels.

{
assets {
url(transformation: {
document: { output: { format: "pdf" } }
})
}
}

Hygraph also allows for combining multiple transformation arguments in a single query, providing a granular level of control over how assets are manipulated and delivered. Additionally, with the validateOptions: true argument, you can ensure that your transformation requests are valid and supported, avoiding runtime errors and ensuring a smooth user experience.

{
assets {
url(transformation: {
image: { resize: { width: 50, height: 50, fit: "clip" } }
document: { output: { format: "png" } }
validateOptions: true
})
}
}

#Conclusion

Incorporating GraphQL into your content delivery strategy, especially through a powerful platform like Hygraph, offers unparalleled advantages. From querying precisely what you need and stitching together multiple data sources to ensuring data consistency and reducing maintenance overhead, GraphQL is the future of efficient content delivery.

The GraphQL Report 2024

Statistics and best practices from prominent GraphQL users.

Check out the report

Resources

Blog Author

Joel Olawanle

Joel Olawanle

Joel Olawanle is a Frontend Engineer and Technical writer based in Nigeria who is interested in making the web accessible to everyone by always looking for ways to give back to the tech community. He has a love for community building and open source.