Exploring GraphQL Clients: Apollo Client vs Relay vs URQL
What Is Apollo Client?
Querying data with Apollo Client
npm install --save @apollo/client graphql
//index.js
import {
ApolloClient,
InMemoryCache,
gql
} from "@apollo/client";
//index.js
const client = new ApolloClient({
uri: 'https://api.spacex.land/graphql/',
cache: new InMemoryCache()
});
- The URI specifies the GraphQL endpoint you want to retrieve data from. (We are using SpaceX's public GraphQL API for this example.)
- The cache is an instance of InMemoryCache, which allows you to cache query results and configure Apollo Client's caching strategies.
//index.js
client.query({
query: gql`
{
missions {
name
website
}
}
`,
}).then(result => console.log(result));
Pros of Apollo Client
- Apollo Client doubles as a caching and state management library: Apollo Client ships with a built-in caching and state management feature to help you manage local state, irrespective of whether you have a GraphQL API to connect to. Additionally, you can cache the state you receive the Remote API in and combine it with the local state, saving network bandwidth and time when dealing with data.
- Apollo Client ships with many built-in features: You get features such as error handling, pagination, data prefetching, and integration with React Hooks built-in. Having these features can accelerate development time and boost productivity.
- Apollo Client supports many frameworks: Apollo Client supports React, Angular, Vue, Ember, iOS, and Android—all of which can be advantageous if you use GraphQL in multiple projects as it saves you time and effort in switching between GraphQL projects.
- Apollo Client 3.0 features reactive variables: Reactive variables can store data of any type and can be accessed anywhere in the application. Reactive variables can be an advantageous mechanism for representing local states outside the Apollo Client cache.
When does Apollo Client not fit in?
- Large bundle size: One of the biggest downsides to adopting Apollo is the bundle size. The smallest version of Apollo which makes it usable, comes in at 30.7KB, twice the size of other GraphQL clients like URQL. This large bundle size could lead to poor app performance in bandwidth-constrained applications.
- Lack of extensive support for other front-end frameworks aside from React: Apollo Client was built with React in mind and ships with many custom features for React applications. Often, developers have to rely on unofficial third-party tooling for other front-end frameworks, which can be buggy and bloated.
What Is Relay?
Querying data with Relay
- A compiler (which is used at build time)
- A core runtime (that is React-agnostic)
- A React integration layer
npm install --save relay-runtime react-relay
npm install --save-dev relay-compiler graphql@^15.0.0 babel-plugin-relay
Configure the Relay Compiler
npm install -g graphqurl
// <your-app-name>/package.json
{
...
"scripts": {
...
"start": "npm run relay && react-scripts start",
"build": "npm run relay && react-scripts build",
"relay": "npm run relay-compiler --schema schema.graphql --src ./src/ --watchman false $@"
...
},
...
}
Configure the Relay runtime and environment
// <your-app-name>/src/RelayEnvironment.js
import { Environment, Network, RecordSource, Store } from "relay-runtime";
const store = new Store(new RecordSource());
const network = Network.create((operation, variables) => {
return fetch("https://api.spacex.land/graphql/", {
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json"
},
body: JSON.stringify({
query: operation.text,
variables
})
}).then(response => {
return response.json();
});
});
export default new Environment({
network,
store
});
//App.js
import React from "react";
import { QueryRenderer, graphql } from "react-relay";
import environment from './RelayEnvironment';
const query = graphql`
query AppRepositoryMissionQuery{
missions {
name
website
}
}
`;
export default function Root() {
return (
<QueryRenderer
environment={environment}
query={query}
render={({ error, props }) => {
if (error) {
return <p>{error.message}</p>;
} else if (props) {
return <p>Mission name is {props.name} with website {props.website}</p>;
}
return <p>Loading your Relay Mordern data...</p>;
}}
/>
);
}
What works for Relay
- Relay is designed for high performance and automatically scales as your app grows: Relay is heavily focused on application performance. Its incremental compiler keeps iteration speed fast as the application grows and optimizes queries ahead of time to make the runtime as fast and efficient as possible.
- Relay applies and relies on GraphQL best practices: Relay ensures GraphQL APIs are built according to their predefined schema format. For example, Relay relies on globally unique IDs across the entire schema type to provide reliable caching and data prefetching. This enforcement of strong patterns ensures API consistency.
- Relay supports declarative data fetching: With Relay, you can declare your data requirements and let Relay figure out how and when to fetch your data. This feature reduces the time and complexity required to consume GraphQL APIs in React applications.
- Relay reduces the probability of failure in front-end applications: Relay supports type safety and automatic schema consistency and forces developers to follow a strict convention. These features ensure a clean architecture and minimize breaking changes that could cause application failure.
What doesn't work for Relay
- Relay can be complex to set up and has a large bundle size: Because Relay is highly opinionated and conforms to a strict standard, the GraphQL API Relay connects to has to be built with a particular convention, which means less flexibility in GraphQL API design. Additionally, setting up Relay can be bulky and complex. It has a large bundle size, and you need to add a custom configuration when setting it up. This complexity, bulkiness, and lack of flexibility can be disadvantageous, especially when your team needs a quick, straightforward GraphQL client option.
- Relay can only be used with React and React Native applications: Relay only supports React and React Native applications. If your team uses other front-end languages aside from React, you will need a different GraphQL client to support it, leading to more time and effort learning about a new GraphQL client.
What Is URQL?
Querying data with URQL
npm install --save urql graphql
//index.js
import { createClient } from 'urql';
const client = createClient({
url: 'https://api.spacex.land/graphql/',
});
//index.js
const query = `
{
missions {
name
website
}
}`;
const results = await client.query(query).toPromise();
console.log(result);
Pros of URQL
- URQL is lightweight and easy to set up: URQL ships with a bundle size of just 12KB, which is incredibly lightweight, especially compared to other GraphQL clients like Apollo. URQL is also the easiest to set up among the three GraphQL clients, as shown in the example above. These two features are advantageous when building lightweight, performant applications.
- URQL is flexible and extensible: URQL provides an extensibility API that allows app developers to customize the URQL GraphQL library to suit their needs. This extensibility and flexibility allow developers to build custom implementations on top of URQL and tweak them to suit their custom scenarios.
- Caching in URQL is fully customizable through its exchanges. URQL supports document caching for content-heavy pages and normalized caching for dynamic and data-heavy applications. This flexibility allows developers to easily set up caching on your client applications based on your specific requirements.
- URQL provides first-class support for functionality, such as offline mode and file uploads. URQL has built-in support for additional functionality, such as offline mode. This first-class support means you spend less time implementing features such as offline mode and file uploads in your client application.
What can be better for URQL?
- A relatively new and small community when compared to other GraphQL clients: URQL was released in 2018 and currently has 157 contributors on GitHub. However, compared to Relay, which was released in 2015 and has 492 contributors, and Apollo, which was released in 2016 and has 644 contributors, it is noticeably smaller. URQL is relatively new, and its community is not as vibrant and mature as the Relay and Apollo communities.
- Lack of some built-in features: URQL lacks first-class support for features such as query batching, local state management, and pagination, which ship out of the box with Apollo and Relay. This means developers spend more time manually implementing these features in their applications.
Apollo vs. Relay vs. URQL: A Quick Overview
Apollo vs. Relay vs. URQL: Which of These GraphQL Clients Is Right for Your Needs?
Related reading