close icon
daily.dev platform

Discover more from daily.dev

Personalized news feed, dev communities and search, much better than what’s out there. Maybe ;)

Start reading - Free forever
Start reading - Free forever
Continue reading >

Apollo Link Basics for Beginners

Apollo Link Basics for Beginners
Author
Nimrod Kramer
Related tags on daily.dev
toc
Table of contents
arrow-down

🎯

Learn about Apollo Link basics for beginners, setting up Apollo Link, creating custom links, managing local state, and more. Explore how Apollo Link can enhance data handling in GraphQL applications.

If you're starting with GraphQL and want to know how Apollo Link can make data handling smoother in your applications, you're in the right place. Apollo Link is a powerful tool designed to manage the way data moves around in your apps when using GraphQL. Here's a quick overview:

  • Apollo Link acts as a middleware, allowing you to perform actions on requests before they're sent and after responses are received.
  • It provides features like error handling, request retries, and managing local state alongside server data.
  • Setting up Apollo Link involves installing necessary packages and configuring Apollo Client to use different links for tasks like HTTP requests.
  • You can create custom links for specific functionalities, such as adding timestamps to requests or handling authentication.
  • Apollo Link supports managing local state in your app, offering a streamlined way to handle UI state with GraphQL.

This introduction aims to give you a clear and concise understanding of Apollo Link basics, ensuring you have the knowledge to start integrating it into your GraphQL applications.

What is Apollo Link?

Apollo Link is like a handy tool that helps you manage how data moves around when you're using GraphQL, which is a smart way to ask for data from servers. Imagine it as a middleman that can check, change, or even redo requests for data before they reach their final destination or come back to you. This tool is all about making sure everything goes smoothly when you're asking for or getting data.

Apollo Client is a tool that helps your app talk to GraphQL servers. It's pretty good on its own but can't do everything. Sometimes, you need extra features like fixing errors in a special way, trying again if a request fails, keeping an eye on what's happening with your data requests, tweaking data a bit before it's sent or after it's received, managing data saved on your device, or even using different ways to connect like through websockets.

Apollo Link is like a box of LEGO pieces for handling data with Apollo Client. You can pick and choose which pieces you need to add extra functions without having to mess with the main tool. It's a way to make Apollo Client even better by letting you add on all sorts of useful features easily.

Prerequisites

Before diving into Apollo Link, make sure you have:

  • React or a similar frontend framework that can use GraphQL
  • A backend setup with a GraphQL server ready to process requests
  • apollo-link and apollo-client packages installed in your project

You might also find these packages useful:

  • react-apollo for connecting Apollo to React
  • apollo-cache-inmemory for storing data efficiently
  • apollo-link-http for making HTTP requests

Installation

First, you need to add the main apollo-link package to your project:

npm install apollo-link

Don't forget to install apollo-client and any other Apollo packages you'll need:

npm install apollo-client apollo-cache-inmemory apollo-link-http

After installing, set up Apollo Client with Apollo Link like this:

import { ApolloClient } from 'apollo-client';
import { InMemoryCache } from 'apollo-cache-inmemory';
import { HttpLink } from 'apollo-link-http';

const link = new HttpLink({uri: '/graphql'}); 

const client = new ApolloClient({
  link,
  cache: new InMemoryCache()
});

With these steps, Apollo Client is ready to go, using Apollo Link to manage HTTP requests to your GraphQL server. You can add more links anytime to expand its capabilities.

Core Functionalities

Apollo Link acts like a helpful assistant between Apollo Client and the GraphQL server. It's there to tweak GraphQL requests before they're sent out and manage responses before they get to your app's screens.

Here are some key things Apollo Link can do:

Request Pipeline

Apollo Link helps you set up a request pipeline - a series of steps that your request goes through one by one.

Each step in this series is called a link. These links can look at the request and change it or add extra info using something called the context.

For example, you might have one link that adds a security header to the request, another that keeps track of any errors, and so on.

Afterware

Besides working on requests, Apollo Link can also handle responses with afterware - steps that process the server's response before your app sees it.

Afterware links can change the data, manage errors, and more. For instance, you could have a link that looks for specific errors and shows custom messages to the user.

Caching

Apollo Link works closely with Apollo Client's caching system. You can use links to set how the cache works, like turning it off for some requests.

Links can also interact with the cache, reading and writing data when dealing with requests and responses.

Error Handling

Apollo Link takes errors seriously. The apollo-link-error package gives you an onError function that runs for both network and GraphQL errors.

This function can be used to show errors to users, record them, or try requests again. And since it's part of the link chain, you have context and can interact with other links.

Composition

A big part of Apollo Link is how you can mix and match different links to manage GraphQL operations just the way you need.

You can use the concat function to put links in a sequence, or from to chain a bunch of links together.

This flexibility means you can customize how requests are handled to fit your app perfectly.

Let's start by making a simple setup with Apollo Link. Imagine you're putting together a team where each member has a special job. In this case, our team has two members:

  • An ErrorLink that takes care of any mistakes.
  • An HttpLink that talks to the server.

The ErrorLink is up first because it needs to catch any mistakes before they reach the HttpLink. Here’s how you put the team together:

import { ApolloClient } from 'apollo-client';
import { InMemoryCache } from 'apollo-cache-inmemory';
import { HttpLink } from 'apollo-link-http';
import { onError } from 'apollo-link-error';

// Error link handles mistakes
const errorLink = onError(({ graphQLErrors, networkError }) => {
  if (graphQLErrors) {
    console.log('GraphQL Errors:', graphQLErrors);
  }
  if (networkError) { 
    console.log('Network Error:', networkError);  
  }
});

// HTTP link talks to the server
const httpLink = new HttpLink({
  uri: 'http://localhost:4000/graphql'  
});

// Putting the team together
const link = ApolloLink.from([
  errorLink,
  httpLink 
]);

// Setting up Apollo Client
const client = new ApolloClient({
  link,
  cache: new InMemoryCache()
});

Now, Apollo Client will use this team for handling data. If there are any errors, the ErrorLink will take care of them before passing things over to the HttpLink, which then communicates with the server.

This is just the start. You can add more members to the team for more tasks, like logging in users, keeping track of data, or trying again if something doesn’t work the first time. But this simple setup is your first step into Apollo Link!

Apollo Link lets you make your own special links for your app. Here's how you can make a new kind of link from scratch.

Overview

To make your own link, you need to:

  • Use the ApolloLink class as a starting point
  • Write a function that handles requests
  • Create an instance of your new link

For instance, we can create a TimeStampLink that adds the current time to each request.

Here's how you can make a TimeStampLink:

import { ApolloLink } from '@apollo/client';

class TimeStampLink extends ApolloLink {

  request(operation, forward) {

    // Add the current time to the request
    operation.setContext({
      timestamp: Date.now() 
    });

    // Move the request along to the next link
    return forward(operation);

  }

}

// How to use it
const link = new TimeStampLink();

This code shows how to add a timestamp to each request. setContext lets us attach the current time. This info can be used by other links in the chain if needed.

Custom Logic Ideas

Here are some things you could do with custom links:

  • Authentication - Add security info to headers
  • Logging - Keep track of requests
  • Error handling - Show errors in a specific way
  • Retry logic - Try again if a request fails
  • Caching - Change how data is saved

With your own links, you can make Apollo Client do exactly what your app needs. You can mix and match these custom links to handle data in a way that's perfect for your app.

Handling Responses

Apollo Link lets you tweak the answers you get back from the GraphQL server before they show up in your React app. Here are some straightforward ways to work with those responses using Apollo Link:

Logging Response Times

You can track how long it takes for GraphQL operations to complete. This helps you spot any slow spots.

Here's a simple roundTripLink that notes how long each operation takes:

const roundTripLink = new ApolloLink((operation, forward) => {

  // Note the start time before sending the operation
  operation.setContext({ start: Date.now() });

  return forward(operation).map(data => {

    // Note the end time when the response comes back
    const time = Date.now() - operation.getContext().start;

    console.log(`Operation ${operation.operationName} took ${time}ms`);

    return data;
  });

});

This link keeps track of the start time. When the answer comes back, it figures out and logs how much time passed.

Modifying Results

You can change the GraphQL response before it gets to your components. Here's how:

const addTimestampLink = new ApolloLink((operation, forward) => {

  return forward(operation).map(result => {

    result.timestamp = Date.now();
    
    return result;

  });

});

This addTimestampLink sticks a new timestamp field onto every response with the current time.

You could also change data in other ways, add extra info, or manage errors this way.

Conditional Logic

You can choose to only work on responses for certain types of operations:

const debugLink = new ApolloLink((operation, forward) => {

  // Only look at query operations
  if (operation.operationName.includes('Query')) {
    return forward(operation).map(result => {
      console.log('Query Response:', result);
      return result;
    });
  }

  // Skip mutations
  return forward(operation);

});

This debugLink will show you details for Query operations but not for Mutations.

By picking and choosing like this, you avoid slowing things down unnecessarily.

With these simple Apollo Link strategies for changing, tracking, and selectively working on responses, you get more control over how data is handled in your React apps.

sbb-itb-bfaad5b

Apollo Link lets you put links together in two main ways:

Additive Composition

Additive composition is like stringing beads on a necklace. You line up multiple links one after the other. Each link does its job on the request and then hands it off to the next link.

For example:

const link = ApolloLink.from([
  firstLink,
  secondLink,
  thirdLink
]);

Here, you have three links working one by one, in the order you put them.

This approach is great when you want to:

  • Do several different things to each request (like logging, checking who's asking, or saving things for later)
  • Make sure things happen in a specific order

Directional Composition

Directional composition is like a fork in the road. It lets you choose one of two paths based on what you need at the moment:

const link = ApolloLink.split(
  operation => operation.getContext().useWebSocket,
  webSocketLink, 
  httpLink
);

This means if useWebSocket is true, it uses the webSocketLink; otherwise, it goes down the httpLink path.

Use this method when you need to:

  • Decide between two different ways of doing things based on the request
  • Switch between ways to connect, like using WebSocket instead of HTTP

In both ways of putting links together, everything ends up going through one final link.

When to Use Each Approach

Additive is best for when you're adding general steps that apply to every request, like:

  • Keeping logs
  • Managing errors
  • Checking user access

Directional is for when you need to make a choice based on the situation, like:

  • Switching to WebSocket for live updates
  • Using mock data for testing
  • Handling requests differently based on the user's location or device

By mixing these two ways of putting links together, you can make a setup that's just right for what your app needs.

Advanced Topics

Managing Context

Apollo Link uses a neat trick called context to let links share info without bothering the server with extra details. Think of context as a secret handshake between links. They can pass along useful bits like who's logged in or how fast something needs to run, all without making a peep to the server.

For instance, a link could check if you're logged in and add your details to the context. Then, other links can peek at this info and know you're there. Or, a link might keep track of how long something takes, letting others adjust based on that timing.

Context is the glue that helps links work together smoothly, keeping the server out of their private conversations.

Middleware and Afterware

Apollo Link uses middleware and afterware for tasks that need to happen before or after requests. Think of them as the helpers that prep your data for its journey or give it a warm welcome back.

Global Auth Token

const authLink = setContext((_, { headers }) => {
  return {
    headers: {
      ...headers,
      authorization: getAuthToken()
    }
  }
});

This authLink automatically sticks an auth token on every request, like a stamp of approval.

Handling Logout

const errorLink = onError(({ networkError }) => {
  if (networkError.statusCode === 401) {
    logoutUser();
  }
});

The errorLink watches for a "no entry" sign (401 code) and knows it's time to say goodbye, logging the user out.

Query Deduplication

The DedupLink stops you from sending the same question multiple times. It's like saying, "Hold up, didn't we just ask that?" before sending another request. This keeps things efficient and avoids asking the server the same thing over and over.

Here's a quick look at some other helpful Apollo Links:

  • WebSocketLink - keeps things real-time with live updates
  • BatchHttpLink - groups several questions (queries/mutations) together
  • BatchLink - similar to BatchHttpLink but with more customization
  • RetryLink - gives it another go if the first try doesn't work out
  • ThrottleLink - makes sure we're not asking too much, too fast

These tools help manage how we talk to the server, making sure we're efficient, polite, and getting the answers we need.

Apollo Link State is a tool that lets you handle local stuff in your app (like what buttons are clicked or what's typed into forms) right next to the data you get from the internet with GraphQL. It's like having a mini-database for your app's interface.

Overview

Here's the gist of Apollo Link State:

  • It keeps your app's local details (like UI state) in the same place as your GraphQL data.
  • You set it up similarly to how you might use Redux, with rules (reducers) that say how data should change.
  • Your components can ask for and update these local details using GraphQL just like they do with remote data.

This setup means you can manage all your data in one spot with Apollo.

Setup

Getting started with local state involves a few steps:

  1. Add the apollo-link-state package to your project.
  2. Set up your local state definitions.
  3. Hook up your local state to Apollo Client.

First, install the package:

npm install apollo-link-state

Then, define what your local state looks like:

// Example reducer for messages
const messages = (previousState, action) => {
  // Handle different actions here
};

// Initial state setup
const defaults = {
  messages: []  
};

// How to change state
const resolvers = {
  Mutation: {
    openMessage: (_, {text}, {cache}) => {
      // Code to add a message
    },
    closeMessage: (_, {id}, {cache}) => { /*...*/ } 
  }
};

Finally, connect it all to Apollo Client:

const client = new ApolloClient({
  cache,
  link: ApolloLink.from([
    new ApolloLinkState({
      resolvers,
      defaults  
    }),
    httpLink
  ])
});

Now, your app can handle local state!

Reading Local State

To see your local state in action, just use GraphQL queries in your components, like you do for data from the server.

Here's how to get messages:

const GET_MESSAGES = gql`
  query GetMessages {
    messages @client {
      id 
      text
      isOpen
    }
  }  
`;

function Messages() {
  const {data} = useQuery(GET_MESSAGES);

  return (
    <ul>
      {data.messages.map(msg => (
        <Message msg={msg} key={msg.id} />
      ))}
    </ul>
  )
}

Writing Local State

To change local state, just call mutations defined in your resolvers:

const OPEN_MESSAGE = gql`
  mutation OpenMessage($text: String!) {
    openMessage(text: $text) @client
  }
`;

function MessageInput() {
  const [text, setText] = useState('');

  const openMessage = useMutation(OPEN_MESSAGE, {
    variables: {text}
  })

  return (
    <form 
      onSubmit={e => {
        e.preventDefault();
        openMessage();
        setText('');  
      }}
    >
      <input 
        value={text}
        onChange={e => setText(e.target.value)}
      />
      <button type="submit">Send</button>
    </form>
  );
}

This way, updating your app's interface is easy and keeps everything in one place.

Async Resolvers

Sometimes, you might need to talk to an external API before updating your local state. You can do this with async resolvers:

Mutation: {
  approveMessage: async (_, {id}, {cache}) => {
    // Call an external API
    // Then update the cache
  }
}

This setup lets you sync up changes between your local state and external data smoothly.

By using Apollo Link State, you can manage your app's local UI state seamlessly alongside your GraphQL data, making your app more efficient and easier to work with.

Best Practices and Common Pitfalls

When using Apollo Link to manage how data moves in your GraphQL apps, it's smart to follow some good habits and steer clear of easy-to-make mistakes.

Make sure each link does just one job, like checking for errors, adding security info, or logging what's happening. Trying to do too much with one link can make your code messy and hard to fix when something goes wrong.

The sequence of your links is important because data passes through them one by one. Put links that change the data early on and links that deal with the data coming back later. For instance, a link that adds a security token should be placed before a link that sends off the HTTP request.

Use Additive Composition Judiciously

You can chain lots of links together, but having too many can slow things down and make your code harder to read. Think carefully if each link is really needed.

Handle Errors Gracefully

Errors, especially those from the network, need to be handled carefully. The apollo-link-error package lets you catch and manage errors in a way that makes sense for your app.

While you can put links inside other links, too much nesting can make your code confusing. Try to keep things straightforward.

Don't Fetch Unneeded Data

A common slip-up is asking for more data than you actually need. Keep your GraphQL queries and Mutations precise to avoid getting too much data.

Apollo Link State is great for managing simple UI states, but be careful when syncing it with external data to avoid issues. Use it wisely.

Links can change the way data is sent and received, so it’s important to test them well. Make sure they work as expected, both on their own and when used with other links.

By sticking to these guidelines, you'll make the most out of Apollo Link, keeping your data flow smooth and your app running well.

Conclusion

Apollo Link is a really helpful tool when you're working with GraphQL in your apps. It lets you control how data moves around by using different links for different tasks. This way, you can make sure your app handles data just right.

Here are the main points to remember:

  • Links are great for adjusting data requests and responses, fixing errors, and dealing with saved data.
  • Features like request pipelines and afterware help keep everything running smoothly.
  • Using context, links can share information and work together better.
  • You can make your own links to do exactly what your app needs.
  • There are ways to put links together so they work well as a team.
  • Apollo Link State is there to help manage the local data in your app, right alongside your GraphQL data.

When you're building apps with GraphQL and Apollo Client, try using Apollo Link to make data handling better. The Apollo documentation has lots of tips on how to get creative with links for your app's specific needs.

Apollo Link gives you a way to fully use GraphQL by managing how data is fetched, handled, and updated in your app.

Related posts

Why not level up your reading with

Stay up-to-date with the latest developer news every time you open a new tab.

Read more