29
GraphQL-update cache and network fetch policies
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:
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:
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
}
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
cache-and-network
network-only
no-cache
cache-only
29