This website uses cookies to better the user experience of its visitors. Where applicable, this website uses a cookie control system, allowing users to allow or disallow the use of cookies on their computer/device on their first visit to the website. This complies with recent legislative requirements for websites to obtain explicit consent from users before leaving behind or reading files such as cookies on a user’s computer/device. To learn more click Cookie Policy.

Privacy preference center

Cookies are small files saved to a user’s computer/device hard drive that track, save, and store information about the user’s interactions and website use. They allow a website, through its server, to provide users with a tailored experience within the site. Users are advised to take necessary steps within their web browser security settings to block all cookies from this website and its external serving vendors if they wish to deny the use and saving of cookies from this website to their computer’s/device’s hard drive. To learn more click Cookie Policy.

Manage consent preferences

These cookies are necessary for the website to function and cannot be switched off in our systems. They are usually only set in response to actions made by you which amount to a request for services, such as setting your privacy preferences, logging in or filling in forms. You can set your browser to block or alert you about these cookies, but some parts of the site will not then work. These cookies do not store any personally identifiable information.
These cookies allow us to count visits and traffic sources so we can measure and improve the performance of our site. They help us to know which pages are the most and least popular and see how visitors move around the site. If you do not allow these cookies we will not know when you have visited our site, and will not be able to monitor its performance.
Cookies list
Name _rg_session
Provider rubygarage.org
Retention period 2 days
Type First party
Category Necessary
Description The website session cookie is set by the server to maintain the user's session state across different pages of the website. This cookie is essential for functionalities such as login persistence, ensuring a seamless and consistent user experience. The session cookie does not store personal data and is typically deleted when the browser is closed, enhancing privacy and security.
Name m
Provider m.stripe.com
Retention period 1 year 1 month
Type Third party
Category Necessary
Description The m cookie is set by Stripe and is used to help assess the risk associated with attempted transactions on the website. This cookie plays a critical role in fraud detection by identifying and analyzing patterns of behavior to distinguish between legitimate users and potentially fraudulent activity. It enhances the security of online transactions, ensuring that only authorized payments are processed while minimizing the risk of fraud.
Name __cf_bm
Provider .pipedrive.com
Retention period 1 hour
Type Third party
Category Necessary
Description The __cf_bm cookie is set by Cloudflare to support Cloudflare Bot Management. This cookie helps to identify and filter requests from bots, enhancing the security and performance of the website. By distinguishing between legitimate users and automated traffic, it ensures that the site remains protected from malicious bots and potential attacks. This functionality is crucial for maintaining the integrity and reliability of the site's operations.
Name _GRECAPTCHA
Provider .recaptcha.net
Retention period 6 months
Type Third party
Category Necessary
Description The _GRECAPTCHA cookie is set by Google reCAPTCHA to ensure that interactions with the website are from legitimate human users and not automated bots. This cookie helps protect forms, login pages, and other interactive elements from spam and abuse by analyzing user behavior. It is essential for the proper functioning of reCAPTCHA, providing a critical layer of security to maintain the integrity and reliability of the site's interactive features.
Name __cf_bm
Provider .calendly.com
Retention period 30 minutes
Type Third party
Category Necessary
Description The __cf_bm cookie is set by Cloudflare to distinguish between humans and bots. This cookie is beneficial for the website as it helps in making valid reports on the use of the website. By identifying and managing automated traffic, it ensures that analytics and performance metrics accurately reflect human user interactions, thereby enhancing site security and performance.
Name __cfruid
Provider .calendly.com
Retention period During session
Type Third party
Category Necessary
Description The __cfruid cookie is associated with websites using Cloudflare services. This cookie is used to identify trusted web traffic and enhance security. It helps Cloudflare manage and filter legitimate traffic from potentially harmful requests, thereby protecting the website from malicious activities such as DDoS attacks and ensuring reliable performance for genuine users.
Name OptanonConsent
Provider .calendly.com
Retention period 1 year
Type Third party
Category Necessary
Description The OptanonConsent cookie determines whether the visitor has accepted the cookie consent box, ensuring that the consent box will not be presented again upon re-entry to the site. This cookie helps maintain the user's consent preferences and compliance with privacy regulations by storing information about the categories of cookies the user has consented to and preventing unnecessary repetition of consent requests.
Name OptanonAlertBoxClosed
Provider .calendly.com
Retention period 1 year
Type Third party
Category Necessary
Description The OptanonAlertBoxClosed cookie is set after visitors have seen a cookie information notice and, in some cases, only when they actively close the notice. It ensures that the cookie consent message is not shown again to the user, enhancing the user experience by preventing repetitive notifications. This cookie helps manage user preferences and ensures compliance with privacy regulations by recording when the notice has been acknowledged.
Name referrer_user_id
Provider .calendly.com
Retention period 14 days
Type Third party
Category Necessary
Description The referrer_user_id cookie is set by Calendly to support the booking functionality on the website. This cookie helps track the source of referrals to the booking page, enabling Calendly to attribute bookings accurately and enhance the user experience by streamlining the scheduling process. It assists in managing user sessions and preferences during the booking workflow, ensuring efficient and reliable operation.
Name _calendly_session
Provider .calendly.com
Retention period 21 days
Type Third party
Category Necessary
Description The _calendly_session cookie is set by Calendly, a meeting scheduling tool, to enable the meeting scheduler to function within the website. This cookie facilitates the scheduling process by maintaining session information, allowing visitors to book meetings and add events to their calendars seamlessly. It ensures that the scheduling workflow operates smoothly, providing a consistent and reliable user experience.
Name _gat_UA-*
Provider rubygarage.org
Retention period 1 minute
Type First party
Category Analytics
Description The _gat_UA-* cookie is a pattern type cookie set by Google Analytics, where the pattern element in the name contains the unique identity number of the Google Analytics account or website it relates to. This cookie is a variation of the _gat cookie and is used to throttle the request rate, limiting the amount of data collected by Google Analytics on high traffic websites. It helps manage the volume of data recorded, ensuring efficient performance and accurate analytics reporting.
Name _ga
Provider rubygarage.org
Retention period 1 year 1 month 4 days
Type First party
Category Analytics
Description The _ga cookie is set by Google Analytics to calculate visitor, session, and campaign data for the site's analytics reports. It helps track how users interact with the website, providing insights into site usage and performance.
Name _ga_*
Provider rubygarage.org
Retention period 1 year 1 month 4 days
Type First party
Category Analytics
Description The _ga_* cookie is set by Google Analytics to store and count page views on the website. This cookie helps track the number of visits and interactions with the website, providing valuable data for performance and user behavior analysis. It belongs to the analytics category and plays a crucial role in generating detailed usage reports for site optimization.
Name _gid
Provider rubygarage.org
Retention period 1 day
Type First party
Category Analytics
Description The _gid cookie is set by Google Analytics to store information about how visitors use a website and to create an analytics report on the website's performance. This cookie collects data on visitor behavior, including pages visited, duration of the visit, and interactions with the website, helping site owners understand and improve user experience. It is part of the analytics category and typically expires after 24 hours.
Name _dc_gtm_UA-*
Provider rubygarage.org
Retention period 1 minute
Type First party
Category Analytics
Description The _dc_gtm_UA-* cookie is set by Google Analytics to help load the Google Analytics script tag via Google Tag Manager. This cookie facilitates the efficient loading of analytics tools, ensuring that data on user behavior and website performance is accurately collected and reported. It is categorized under analytics and assists in the seamless integration and functioning of Google Analytics on the website.

When, Why, and How to Use GraphQL with Apollo Client in React

  • 1163222 views
  • 15 min
  • Feb 04, 2020
Daria R.

Daria R.

Copywriter

Vlad H.

Vlad H.

Head of Frontend Department

Share

GraphQL is a new API standard that’s a more effective, powerful, and agile substitute for the REST standard. GraphQL was developed as an open-source project in 2015 by Facebook. Today, the GraphQL language has a massive community of fans all over the world. 

This language provides declarative data fetching, meaning a client can specify exactly what data they need from an API. GraphQL is a query language for APIs, not a query language for databases. A GraphQL server provides only one endpoint and responds with exactly the data the client has requested instead of providing several endpoints that return fixed data structures. Additionally, GraphQL simplifies the aggregation of data from different sources and uses specific types to describe queries and data.

In this article, we’ll walk you through the main terms you need to know to work with GraphQL and show you problems we’ve faced with GraphQL in our projects and ways to solve them.

GraphQL architecture 

To understand the architecture of GraphQL, we need to know its main components.

Schema 

A schema is the only thing that defines an API’s capabilities and determines how clients can request data.

Resolvers

Resolvers are methods that return data for the current field.

Here’s how a schema with a resolve method looks in GraphQL.

Types

A type is a way to describe data fields in GraphQL. This is what the main types in the GraphQL architecture look like:

Output

Input

Enum

Interface

Unions

Custom scalars

Let’s talk about the GraphQL architecture and how it works. A client requests resources from a GraphQL server using a GraphQL query. Then the query is compared to the schema on the server according to its type. The GraphQL server analyzes the query, passes it recursively through the graph, and performs its resolver function for each field. When all requested data has been collected, the GraphQL server returns a response.

Graphql api

If you want to use third-party UI libraries to work with a server, the process will be similar. First, you’ll generate a query using a tool like Apollo Client. Then GraphQL will start to aggregate data from entirely different sources (database, microservices, cache, etc.) based on this query. Here’s a diagram of how it looks:

Graphql tutorial
Interaction between client and server

Apollo Client

There are a lot of libraries you can use to work with GraphQL, including Relay, Prisma, URQL, and Apollo Client. We prefer to work with Apollo, as it has a large community of supporters, is frequently updated, and is compatible with iOS, Android, Angular, Ember, Vue, and React.

Apollo Client is a convenient client library for working with GraphQL. It can send queries, cache requested data, and update the state of UI components.

The Apollo Client library has a range of benefits:

  • Declarative data selection. You can write a request and get data without needing to manually monitor downloads. 
  • Convenient instruments for development. You can take advantage of tools such as Chrome Apollo DevTools and VS Code plugins.
  • Supports modern React and Hooks APIs
  • Universal compatibility. You can use any build settings and any GraphQL API. 
  • Strong community support. This library is very popular and has a lot of committers who improve it all the time.

Now that we’ve checked out the architecture of GraphQL and chosen this library to work with, let’s review the types of queries in GraphQL.

Types of queries in GraphQL

GraphQL has some specific types of requests for different actions:

  1. Query — request to read data
  2. Mutation — request to change data
  3. Subscription — request that receives or sends real-time event data

Let’s take a look at each of these request types in detail.

1. Query

A query has a string structure that can contain parameters sent in the body of POST requests to the GraphQL endpoint. In response, we get a JSON file that contains either a data field with data we requested or an “error” field if something went wrong. For one request, we get one response.

Now let’s see how we can make requests to Apollo Client.

1.1 Query with client object 

A query with a client object is convenient as an additional query in render mode. You can create a method in a component that will call a query and return a response. In the example below, the argument of a client function is the property of a query component in Apollo Client.

A client query can be executed as a side effect in a life cycle component. Apollo Client has a higher-order component (HOC) called withApollo, in which a client is the props of the wrapped component, as in the example below:

In this example, SOME_QUERY is a query string to fetch data.

Now let’s look at a request with a declarative description of query as a component.

1.2 Query with a declarative description of query as a component

As you can see, the query in the code above returns three properties: data, loading, and error. In our project, we also used the refetch property, which allows us to refetch an existing query and get updated data. However, these aren’t all the parameters the query can return. You can read more about this in the useQuery API section of the Apollo Docs. 

In the code snippet above, we showed a simple example of using queries. But what if we have a more complex and interactive page? Imagine we have a page that contains a complex form for editing and is divided into sections, where each change is a commit to a database. As a result, you’ll have nesting according to the following structure.

This structure is extremely unreadable, especially because of the layout and custom component. We need to break this form into subcomponents. By doing so, we'll make the code more testable and readable. When taking a declarative approach, it’s better to use a hierarchy with at most two layers of nesting. Can we limit ourselves with the declarative approach to components? If you need to use a query in the lifecycle of React components, or if you need to pass requested data to a function that runs before the component is rendered, or if you have a composition of queries and mutations for one component, we recommend using high-order components. 

1.3 Query with high-order components 

In the example below, we show the concept of using GraphQL with a single query.

And here’s an example of using options, name methods, and config objects:

Here, COMPANY is a string to fetch data. There are also skip, props, withRef, and alias methods that can be described with a similar approach. You can read more about these methods in the Apollo Docs

For us, it’s more interesting to take a look at the composition of queries and mutations. To do this, we need to import the compose method. Here’s how we do it:

Bear in mind that the compose method will be removed in React Apollo Client 3.0. That’s why it’s better to use the flowRight method from the lodash library. Here’s the proof

Fetching data from the query looks like props of your components. Here’s an example:

Here’s how it looks for class components:

Or if you’re using functional components:

The list of returned parameters is similar to declarative Query from subsection 1.2

1.4 Queries with useQuery React Hooks

The new version of Apollo Client provides support for describing all query operations with the Hooks API. Hooks reduce the amount of code we need to work with data and make components cleaner. As a result, our code is much easier to understand. Developers don’t need to figure out how high-order components or nested declarative components and their hierarchies are arranged. For greater consistency with hook components, we recommend using Hook APIs if your project supports them.

The options contain all methods from the “query with the declarative description of Query as a component” subsection. If you need to add parameters to the request, it will look like this:

Here, NEW_EMAIL_REQUEST is a data query. 

1.5 Delayed useLazyQuery query

We’re going to show you how to use a delay with the Hook API. Unlike useQuery, which is called when components are mounted, a request with a delayed call calls the request function only when an action is performed. For instance:

According to this code, when all users are loaded, the getNewUser function is called, and a new user is requested when we click the button. We can compare this with earlier versions of Apollo Client:

In earlier versions of the Apollo Client library, we additionally needed to use the ApolloConsumer client object. As you can see from the code snippets, hooks simplify this implementation. 

2. Mutation

A mutation is a request to change data that has the structure of a string. This string can be with or without parameters. It’s sent in the body of POST requests to the GraphQL endpoint.

As a response, we get a JSON file that contains either requested data in the data field or an error field. For one request, we get one response.

2.1 Mutation request with client

In this example, the argument of the client function is a Mutation property of the Apollo Client component. We can also access a client object using the withApollo HOC or the mutation properties. We’ll talk more about mutation options and properties in the next section. 

2.2 Declarative description of a mutation

A declarative description is convenient and readable (in terms of the structure of the render props hierarchy) only at the first or maximum second level. This means we have a major mutation that confirms the form, and one element of this form contains one mutation. In all other cases, it’s better to use a mutation composition or Hook API. We’ll get back to this later.

We also want to show you the options for refetchQuery, which updates the Apollo Client cache after the mutation.

You can find a full list of mutation options and properties in the Mutation section of the Apollo Docs. 

2.3 Mutation with high-order components

In the previous section, we saw that if we have more than three levels of nesting for declarative components, it’s better to use НОС to implement queries. Similar to Queries, Mutation requests also can be configured with an options object, like variables, name, and refetchQueries. Here’s an example of a mutation:

options.name

options.variables

options.refetchQueries

2.4 Request with the useMutation hook

The useMutation hook in React is the main API for performing mutations in an Apollo Client app. To start a mutation, we declare useMutation at the beginning of the React component and pass the GraphQL string (which represents the mutation) to the React component. When rendering a component, useMutation returns a function that we can call at any time to perform the mutation along with an object with fields that represent the current state of mutation execution. For example:

In our projects, in the mutation options, we also use the onCompleted and onError callbacks to resolve successful and unsuccessful mutations.

3. Subscription

The third type of operation available in GraphQL is a subscription. There are cases when a client may want to get real-time updates from a server. A subscription allows us to catch GraphQL API events so we can modify data in real time. Data changes that clients can track are defined in the API as fields with a subscription type. Writing a GraphQL query to track a subscription is similar to defining other operations. 

3.1 Description of a client subscription

In the example above, the argument of a client function is a subscription property of the Apollo Client component. 

3.2 Declarative description of a subscription

Subscriptions are just listeners; they don’t request any data when they’re first connected, but they open a channel of connection for receiving data. Here’s how we can visualize data:

For a full list of all subscription sections, options, and properties, check the Subscription section of the Apollo Docs. 

3.3 Subscriptions with the useSubscription hook

Visualizing the subscription model with hooks is more concise than declarative descriptions.

4. Request composition with the Hooks API

When we execute multiple requests in one component, the use of high-order components or the render props mechanism can make our code difficult to understand. The fact that we use the render prop API and create structures with nested Mutation and Query components gives the deceptive feeling that our code is well-structured and has a clear hierarchy. We can avoid using НОС graphQL and additional methods like flowRight by declaring a Mutation at the beginning of components. The new useMutation and useQuery hooks allow us to completely solve problems with a confusing hierarchy of render structures and eliminate the need to use HOCs

Here, we used additional methods such as flowRight, graphql hoc, and Query imported from different dependencies in package.json. The code gets more complex and less readable if the actual contents of the return method are added. We can make the code cleaner and simpler with useQuery and useMutation.

We’ve gotten rid of unnecessary dependencies from other libraries, and the return method is clearer. The code is now far more structured and logical. 

Bear in mind that in the official documentation for Apollo Client 3.0, HOC and Components (<Mutation/> and <Query/>) will have a note that they’re deprecated. 

5. Queries with HTTP

Besides using canonical query types for receiving data, you can get data with the help of HTTP queries to GraphQL endpoints. Here’s how that looks:

We’ve described a query for fetching data in the query variable. The URL is the link by which the request will be executed. The variable opts contains options with which the request will be executed. 

6. Mutation with HTTP

The variable mutate makes a request for getting a new accessToken. The variable URL is the link by which the request will be executed. The variable opts contains options with which the request will be executed.

Customization

In this section, we describe problems we’ve faced in our projects and demonstrate the solutions we’ve come up with when implementing different features. 

Customization of HttpLink

In our project, we needed to customize an HttpLink object when implementing authorization and updating the user session token. The HttpLink object has a fetch method, which, by default, performs an HTTP request to receive or change data. We had to change the standard implementation of the fetch method. We can send mutations in the form of HTTP, as we mentioned, and thereby request or update an accessToken.

The implementation of our customFetch method looks like this:

While implementing this method, it was impossible to use the client object with a mutation because of a loop caused by the customFetch method of the HttpLink object.

Customization of FragmentMatcher

We needed to customize FragmentMatcher due to problems caused by queries of the Union type. In the console, we detected a “heuristic fragment matching going on!” warning.

How to use graphql

Before digging into the cause of this problem, we need to realize that Apollo Client doesn’t know our remote GraphQL schema and therefore can’t accurately display fragments. This means that in the console, we’ll see one more error: “You are using the simple (heuristic) fragment matcher, but your queries contain union or interface types.”

Common mistakes when working with Apollo GraphQl

Now let’s fix the cause of this warning. 

Steps to get a remote GraphQL schema locally

#1 Request a schema

We need to request a GraphQL schema from the back end and save it locally.

We saved the file as src/scheme/fetchScheme.js. We need this file because in package.json, we will execute the command to update the schema in order to maintain its relevance.

#2 Pass localGqlScheme to InMemoryCache

Now we need to pass the fragmentMatcher object to the ApolloClient constructor.

#3. Build and request the scheme in localGqlScheme.json

We use yarn and Next.js in our project, request a schema, and build the project.

#4. Testing after implementing fragmentMatcher

In the previous section, we successfully implemented fragmentMatcher. However, all our tests will fail because the testing environment doesn’t know the schema we put in the cache.

When you make all the changes shown above, your tests will be successful because MockedProvider will work with the relevant cache. Remember that in every case when you need to test cases with mock queries of the Union type, you need to add __typename. 

In all other cases without Union or Interface, the type name is optional. In the example above, you can see that the withTypeName properties can be configured. 

Final thoughts

In this article, we explained what GraphQL is, demonstrated the popularity of Apollo Client for working with GraphQL, showed how Apollo Client interacts with the UI and GraphQL, and, what’s most important, demonstrated various methods for describing requests and subscriptions in Apollo React Client. We shared with you not only numerous ways to describe types of operations but also our own ideas and experience gained in our projects. 

If you have any comments or suggestions, start a conversation below.

CONTENTS

Authors:

Daria R.

Daria R.

Copywriter

Vlad H.

Vlad H.

Head of Frontend Department

Rate this article!

Nay
So-so
Not bad
Good
Wow
20 rating, average 4.95 out of 5

Share article with

Comments (2)
Amr Hossam El-Din
Amr Hossam El-Din over 4 years ago
How can i make a subscription that works right after a query and changes its value when it is updated using the react hooks ? , there is an example in the documentation but sadly it is in the class components form and i've failed so far to convert it into hooks
Reply
Vlad H.
Vlad H. over 4 years ago Amr Hossam El-Din
Hello, Amr Hossam. To make a subscription work right after a query and change its value when it is updated, you need to get subscribeToMore from the hook useQuery like const { subscribeToMore } = useQuery(); After that, describe useEffect which will depend on the parameters. Inside useEffect you need to call subscribeToMore(params) like useEffect(() => subscribeToMore({ document: 'YOUR_GQL', variables: { param } }), [param])
Reply

Subscribe via email and know it all first!