Here's a quick summary of everything we released in Q1 2024.

GraphQL

Fragments

In this tutorial, we will explore Fragments, how to use them, and best practices for working with them.

One of the powerful features of GraphQL is Fragments, which allows you to define reusable pieces of query logic.

Prerequisites

To follow along with this tutorial, the following prerequisites are required:

  • Basic understanding of GraphQL and its concepts, such as Queries and Mutations.
  • A GraphQL endpoint, get one here.

In addition, this tutorial assumes that you have a working knowledge of a programming language and a web development framework. The examples in this tutorial use JavaScript and the Apollo Client library, but the concepts should also apply to other languages and libraries.

What are Fragments?

Fragments in GraphQL are a way to define a set of fields that can be reused in multiple queries. Instead of repeating the same fields in each query, you can define a fragment that includes the fields you need and then include that fragment in your queries. This reduces duplication and makes queries more maintainable.

For instance, consider a scenario where you have a user profile page that displays the user's name, profile picture, and a list of their recent posts. Without fragments, you might have to write a query that looks like this:

query {
user(id: "123") {
name
profile_picture {
url
dimensions {
width
height
}
}
posts {
title
content
created_at
}
}
}

This query is already becoming complex, and if you add more fields or nested objects, it could quickly become unmanageable. Instead, you can use fragments to define smaller, reusable pieces of the query logic.

fragment UserProfileFields on User {
name
profile_picture {
url
dimensions {
width
height
}
}
}
fragment PostFields on Post {
title
content
created_at
}
query {
user(id: "123") {
...UserProfileFields
posts {
...PostFields
}
}
}

With fragments, you can easily reuse the UserProfileFields and PostFields fragments in other queries, reducing duplication and making your queries more maintainable.

How to Use Fragments

Fragments are defined using the fragment keyword followed by a name and a set of fields. For example:

fragment UserFields on User {
id
name
email
}

This defines a fragment named UserFields that includes the id, name, and email fields for a User object.

To use a fragment in a query, simply include the fragment name preceded by ... and followed by any additional fields you need. For example:

query {
allUsers {
...UserFields
address
phone
}
}

This includes the UserFields fragment along with the address and phone fields for each user.

Fragments can also be nested, allowing you to define more complex structures that can be reused across queries. For example:

fragment AddressFields on Address {
street
city
state
zip
}
fragment UserFields on User {
id
name
email
address {
...AddressFields
}
}
query {
allUsers {
...UserFields
phone
}
}

This defines two fragments: AddressFields for address information, and UserFields that includes the AddressFields fragment. The query then includes the UserFields fragment along with the phone field.

Collocating Fragments

GraphQL allows defining fragments either inline within a query or as standalone GraphQL operations. However, defining fragments as standalone operations enables a technique called collocating fragments.

Collocating fragments is a pattern where fragments are defined alongside the components that use them and can be shared with other components. This approach can make your application components and GraphQL queries more self-contained and easier to understand.

For example, imagine that you have a React component that renders a list of posts. You can define the fragment that fetches the necessary data for the component alongside the component itself like this:

import { gql, useQuery } from "@apollo/client";
const ALL_POSTS_FRAGMENT = gql`
fragment AllPosts on Post {
id
title
}
`;
const POST_QUERY = gql`
query {
posts {
...AllPosts
excerpt
}
}
${ALL_POSTS_FRAGMENT}
`;
export const ListPosts = () => {
const { loading, error, data } = useQuery(POST_QUERY);
if (loading) return <p>Loading...</p>;
if (error) return <p>Error :</p>;
return (
<div>
{data.posts.map((post) => (
<div key={post.id}>
<h3>{post.title}</h3>
<p>{post.excerpt}</p>
</div>
))}
</div>
);
};
ListPosts.fragments = {
allPosts: ALL_POSTS_FRAGMENT,
};

Here, we define the AllPosts fragment alongside the POST_QUERY query and ListPosts component. Additionally, we are also sharing the AllPosts fragment via the code below:

ListPosts.fragments = {
allPosts: ALL_POSTS_FRAGMENT,
};

So that we can import and re-use this fragment in any parent component that accesses it like this:

import { AllPosts } from "./AllPosts";
const SOME_QUERY = gql`
query QueryName {
...
}
${AllPosts.fragments.allPosts}
`;
export const ParentComponent = ({ user }) => {
return <div>{/* ... */}</div>;
};

In this way, we can easily reuse fragments across multiple queries and components without redefining them each time. This approach also helps to keep our code organized and maintainable, especially as our application grows in complexity.

Using Fragments with Unions

Unions in GraphQL allow combining multiple types into a single type, which can be used in a query. Fragments can be used with Unions to define fields specific to each type. This is particularly useful because you can define a fragment that includes fields from all possible types in the Union.

For example, suppose you have a SearchResult type that can represent either a User or a Product:

union SearchResult = User | Product

You can define fragments for each type and then use those fragments in a query that returns SearchResult objects:

fragment UserFields on User {
id
name
email
}
fragment ProductFields on Product {
id
name
price
}
query {
search(query: "iphone") {
... on User {
...UserFields
}
... on Product {
...ProductFields
}
}
}

Here, the SearchResult Union can represent either a User or a Product. We define a fragment for each type (UserFields and ProductFields) and then include those fragments in the search query using the ... on syntax.

Using fragments with Union types can help you write more flexible queries and handle situations where a field can return multiple types. It's a powerful feature that can help you write cleaner, more concise GraphQL queries.

Best Practices for Fragments

When working with fragments, it's important to follow some best practices to keep your queries maintainable:

  • Use descriptive names for fragments, and include the object type in the name (e.g., UserFields instead of just Fields).
  • Keep fragments small and focused, defining only the fields needed for a particular use case.
  • Consider collocating fragments with the components that use them to keep related code together.
  • Avoid duplicating fragments that have the same fields. Instead, use one fragment and include it in all relevant queries.

By following these best practices, you can create maintainable queries that are easy to understand and modify as your application evolves.

Conclusion

Fragments are a powerful feature of GraphQL that allow you to define reusable pieces of query logic. By using fragments, you can reduce duplication in your queries and make them more maintainable. In this tutorial, we've covered fragments, how to use them, and best practices for working with them. Following these guidelines, you can create maintainable and efficient GraphQL queries for your application.