Using GraphQL apollo client in Redux-Thunks actions

demily_clement

Demily Clément

Posted on March 13, 2020

Using GraphQL apollo client in Redux-Thunks actions

Hi everyone 👋

React-Apollo is the go to library to use graphQL alongside React. Their documentation is really cool and comprehensive, but they promote the usage of React Hooks to perform all your requests.
Regarding your frontend architecture, you may not be thrill by the idea of letting all your React components handling these kind of responsibility.
In my case, we were integrating GraphQL within an existing frontend app with React, React-redux and redux-thunk. The code is written the way that all network API calls are executed via redux actions (using redux thunk).

Assuming you have knowledge of redux-thunk and React-Apollo, I will show some basic example of actions.

For these examples, I will use a public GraphQL API :

import ApolloClient from "apollo-client";
import { InMemoryCache } from "apollo-cache-inmemory";
import { HttpLink } from "apollo-link-http";
import { setContext } from "apollo-link-context";
import * as UserUtils from "../utils/user";

const cache = new InMemoryCache();
const link = new HttpLink({
  uri: `https://directions-graphql.herokuapp.com/graphql`
});

const authLink = setContext((_, { headers }) => {
  const token = UserUtils.getTokenFromLocalStorage();

  return {
    headers: {
      ...headers,
      authorization: token
    }
  };
});

const client = new ApolloClient({
  cache,
  link: authLink.concat(link)
});

export default client;
Enter fullscreen mode Exit fullscreen mode
import gql from 'graphql-tag';
import graphQlClient from "client"

export const signUp = (username = "johndoe", email = "john.doe@test.com", password = "mypassword") => (dispatch, getState) => {
  dispatch(setLoading(true))

  graphQlClient
    .mutate({
      mutation: gql`
        mutation($username: String!, $email: String!, $password: String!) {
          signUp(username: $username, email: $email, password: $password) {
            user {
              id,
              username,
              email
            }
          }
        }
      `,
      variables: { username, email, password },
      update: (_cache, result) => {
        const { data: { signUp: { user: { username, email } } } } = result
        dispatch(signIn(email, password))
      },
    })
    .catch((error) => {
      console.log('error', error)
    })
    .finally(() => {
      dispatch(setLoading(false))
    })
}

const setTokenToLocalStorage = (token) => {
  localStorage.setItem('token', token)
}

const getTokenFromLocalStorage = () =>
  localStorage.getItem("token") || null;

export const signIn = (email, password) => (dispatch, getState) => {
  dispatch(setLoading(true))

  graphQlClient
    .mutate({
      mutation: gql`
        mutation($email: String!, $password: String!) {
          signIn(userIdentifier: $email, password: $password") {
              token
          }
        }
      `,
      variables: { email, password },
      update: (_cache, result) => {
        const { data: { signIn: { token} }} = result
        dispatch(setTokenToLocalStorage(token))
      },
    })
    .catch((error) => {
      console.log('error', error)
    })
    .finally(() => {
      dispatch(setLoading(false))
    })
}

export const direction = (coordinates = {startLat: 50.6333, startLng: 3.0667, endLat: 48.8534, endLng: 2.3488} , travelMode = "driving" ) => (dispatch, getState) => {
  dispatch(setLoading(true))

  graphQlClient.
    graphQlClient.query({
      query: gql`
        input PlaceCoordinatesInput {
          startLat: Float!
          startLng: Float!
          endLat: Float!
          endLng: Float
        }

        enum AllowTravelModes {
          transit
          driving
          walking
        }

        query($coordinates: PlaceCoordinatesInput!, $travelMode: AllowTravelModes!) {
          direction(coordinates: $coordinates, travelMode: $travelMode) {
            steps {
              stepInstruction
            }
          }
        }
      `,
      variables: { coordinates , travelMode },
    }).then((result) => {
      const { data: { direction } } = result
      dispatch(doSomethingWithDirection(direction))
    })    
    .catch((error) => {
      console.log('error', error)
    })
    .finally(() => {
      dispatch(setLoading(false))
    })
}
Enter fullscreen mode Exit fullscreen mode

For the sake of the example I used default values for the actions parameters.
As you can see, you easily manipulate graphql apollo client inside redux thunks actions.

To conclude, I will share you some links to help you during your journey of learning GraphQL and react-apollo as well as the repository containing the source code of these examples.

Documentation :

Further reads :

Source code :

💖 💪 🙅 🚩
demily_clement
Demily Clément

Posted on March 13, 2020

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related