GraphQL-update cache and network fetch policies
Tags: javascript, react, graphql
Published: 2021-07-08 17:24:14

I expect the readers to have basic graphql knowledge, how to setup a graphql server, how to mutate and query from a reactjs application using a gql library like apollo-client. We will move ahead with react apollo client library. Apollo client is a declarative data fetching and management library for your reactjs applications wherein different states of fetching data from an API or from a remote server can be managed. Traditional ways of doing the same thing can be achieved using RESTful webservice. In RESTful webservice, we expect the webAPI XMLHttpRequest to listen to various events based on which we can alter the UI. For example, when a XMLHttpRequest is made, we can show up a loader to indicate the request has been made and is been processed by the server.Once we receive the data from the server, we can render the result instead of showing up a loader. There are many libraries which can take care of all the events occuring in a promisified way like axios,superagent or the fetch api itself. So if all these events can be managed by such good well coded libraries, why do we opt for graphql?









 **Advantages of GQL over RESTful webservice:**
* Instead of working with fixed rigid server-defined endpoints,you can make a single query request to a gql server demanding only those parts of data you need.
* GQL reduces the number of endpoints your application makes request to. A single resolver can be used to handle multiple request formats
* In REST, each request calls exactly one request handler whereas in gql,one query may call many resolvers to construct a nested response.
* In REST, you define the structure of the response, whereas in graphql  the shape of the response is built up by the GraphQL execution library to match the shape of the query.




**Understand how to update cache**
In order to implement caching in GQL, one needs to figure it out which one of the following scenarios covers your requirement:

Consider the following code snippet of a gql server:

``` 
import {ApolloServer,gql} from 'apollo-server';

const typeDefs=gql`
type Book{
  id:ID!
  title:String!
  author:String!
}
type Mutation{
  createBook(title:String!,author:String!):Book!
  updateBook(id:String!,title:String!,author:String!):Book!
  deleteBook(id:String!):Boolean!
}
type Query{
  books:[Book!]!
  searchBook(searchKey:String!):[Book!]!
}
`;

const resolvers={
  Mutation:{
    createBook:(_,{title,author})=>{
    const book={id:`${books.length+1}`,title,author}
    books.push(book);
    return book;
  },
  updateBook:(_,Book){
    books=books.map(x=>x.id===book.id?book:x)
    return book;
  },
  deleteBook:(_,{id}){
    books=books.filter(x=>x.id!==id);
    return true;
  }
},
Query:{
  books:()=>books,
  searchBooks:(_,{searchKey})=>{
    const searchedBooks=books.filter((book)=>{
    return book.title.includes(searchey)
    }
    return searchBooks;
  }
}
```

This is a book repository backend application where you can create,read,update and delete a book.Also searchBooks query is used to search books from the repository based on a searchKey.

Now what we want is to show the user a created book without he/she refreshing a page, a delete book should be removed from UI without refreshing a page, a book should be update and again without refreshing the page.This is where caching comes into play. What gql does is it updates the cache based on a unique and __typename returned by the gql server.For eg, when we create a book, the response would be :

{
id,
title,
author
__typename:Book
}

Your web browser cache is a lookup table or a hashtable to be precise.GQL combines id and __typename to assign a key as a hash and the response as it's corresponding value.This key-value pair is responsible for fetching data from your browser's cache in a constant time O(1) which we will be looking at once we understand network fetch-policies.


**Scenario 1 : creating a book**

This case has two sub cases whereby you can update your UI without refreshing the page.


```
 createBook({
      variables: {
        title: "Megastructures",
        author: "Discovery",
      },
      refetchQueries:[{query:Q_FETCH_BOOKS}]
    });
```


```
createBook({
      variables: {
        title: "Malaysian Dreams",
        author: "travel and living",
      },
      update: (store, { data }) => {            //data is response from api
        const bookData = store.readQuery({ query: Q_FETCH_BOOKS });
        store.writeQuery({
          query: Q_FETCH_BOOKS,
          data: {
            books: [...bookData.books, data.createBook],
          },
        });
      },
    });
```



refetch is basically going to fetch the updated db and return it to the client once the mutation is completed whereas in the second case we manually update the cache.GQL makes use of the id and __typename of update the cache and UI automatically. A frontend developer need not do anything  else other than updating the cache the cache manually and the rest is taken care by the apollo-client. 



**Scenario 2 : update a book**:

```
updateBook({
      variables: {
        id: "1",
        title: "Banged up abroad",
        author: "National Geographic",
      },
    });
```

This is very much similar to scenario 1, except for the fact that we do not need to update the cache manually.Apollo client will map the updated data to the hashtable based on the combination of id+__typename


**Scenario 3: Deleting a book**

Delete is similar to the subcase 2 of scenario 1. Send a mutation to the server, once it is confirmed that the book is deleted in the server, update the cache manually.



**Scenario 4: Searching a book**

```
const [searchBook, { loading, data, error }] = useLazyQuery(Q_SEARCH_BOOKS, {
    onCompleted: (data) => {
      console.log(" search books onCompleted", data);
    },
    fetchPolicy: "cache-and-network",
  });
```


**Fetch Policies:**

**cache-first**
1. default policy
2. cache is checked first. If requested data is present,the data is returned. Else network request is made to api & cache is updated
3. Better option to update the cache

**cache-and-network**
1. cache is checked first. Regardless of whether data is found or not, a network request is made to get upto date data
2. updates the cache wrt to network response
3. can be useful when an operation is performed in one of the sub-component and you need updated data in it's sibling component.

**network-only**
1. always makes a network request. Will update the cache for other queries

**no-cache**
1. similar to network-only. Does not update cache

**cache-only**
1. never makes a network request,always returns data from the cache.