GraphQL - Cache
Cache é o processo de armazenamento de dados em uma área de armazenamento temporário chamada cache. Quando você retorna a uma página que visitou recentemente, o navegador pode obter esses arquivos do cache em vez do servidor original. Isso economiza seu tempo e rede da carga de tráfego adicional.
Os aplicativos cliente que interagem com o GraphQL são responsáveis pelo armazenamento em cache dos dados em sua extremidade. Um padrão possível para isso é reservar um campo, como id, para ser um identificador globalmente exclusivo.
Cache InMemory
InMemoryCache é um armazenamento de dados normalizado comumente usado em aplicativos cliente GraphQL sem o uso de outra biblioteca como Redux.
O código de amostra para usar InMemoryCache com ApolloClient é fornecido abaixo -
import {ApolloClient, HttpLink, InMemoryCache} from 'apollo-boost'
const cache = new InMemoryCache();
const client = new ApolloClient({
   link: new HttpLink(),
   cache
});
O construtor InMemoryCache usa um objeto de configuração opcional com propriedades para personalizar seu cache.
| Sr. Não. | Parâmetro e Descrição | 
|---|---|
| 1 | addTypename Um booleano para determinar se deve ser adicionado __typename ao documento (padrão: verdadeiro)  | 
| 2 | dataIdFromObject Uma função que pega um objeto de dados e retorna um identificador único para ser usado ao normalizar os dados na loja  | 
| 3 | fragmentMatcher Por padrão, o InMemoryCache usa um matcher de fragmento heurístico  | 
| 4 | cacheRedirects Um mapa de funções para redirecionar uma consulta para outra entrada no cache antes que uma solicitação ocorra.  | 
Ilustração
Criaremos um aplicativo de página única no ReactJS com duas guias - uma para a guia inicial e outra para alunos. A guia de alunos carregará dados de uma API do servidor GraphQL. O aplicativo consultará os dados dos alunos quando o usuário navegar da guia inicial para a guia dos alunos. Os dados resultantes serão armazenados em cache pelo aplicativo.
Também consultaremos o tempo do servidor usando getTimecampo para verificar se a página está em cache. Se os dados forem retornados do cache, a página exibirá a hora da primeira solicitação enviada ao servidor. Se os dados forem resultado de uma nova solicitação feita ao servidor, ele sempre mostrará a hora mais recente do servidor.
Configurando o Servidor
A seguir estão as etapas para configurar o servidor -
Etapa 1 - Baixe e instale as dependências necessárias para o projeto
Crie uma pasta cache-server-app. Mude seu diretório para cache-server-app do terminal. Siga as etapas 3 a 5 explicadas no capítulo Configuração do ambiente.
Etapa 2 - Criar um esquema
Adicionar schema.graphql arquivo na pasta do projeto cache-server-app e adicione o seguinte código -
type Query {
   students:[Student]
   getTime:String
}
type Student {
   id:ID!
   firstName:String
   lastName:String
   fullName:String
}
Etapa 3 - Adicionar resolvedores
Crie um arquivo resolvers.js na pasta do projeto e adicione o seguinte código -
const db = require('./db')
const Query = {
      students:() => db.students.list(),
      getTime:() => {
      const today = new Date();
      var h = today.getHours();
      var m = today.getMinutes();
      var s = today.getSeconds();
      return `${h}:${m}:${s}`;
   }
}
module.exports = {Query}
Etapa 4 - Executar o aplicativo
Crie um arquivo server.js. Consulte a etapa 8 no capítulo Configuração de ambiente. Execute o comando npm start no terminal. O servidor estará instalado e funcionando na porta 9000. Aqui, usaremos GraphiQL como um cliente para testar o aplicativo.
Abra o navegador e digite o URL http://localhost:9000/graphiql. Digite a seguinte consulta no editor -
{
   getTime
   students {
      id
      firstName
   }
}
O exemplo de resposta mostra os nomes dos alunos e o horário do servidor.
{
   "data": {
      "getTime": "22:18:42",
      "students": [
         {
            "id": "S1001",
            "firstName": "Mohtashim"
         },
         {
            "id": "S1002",
            "firstName": "Kannan"
         },
         {
            "id": "S1003",
            "firstName": "Kiran"
         }
      ]
   }
}
Configurando o ReactJS Client
Abra um novo terminal para o cliente. O terminal do servidor deve ser mantido em execução antes de executar o aplicativo cliente. O aplicativo React será executado na porta número 3000 e o aplicativo do servidor na porta número 9000.
Etapa 1 - Criar um aplicativo React
No terminal do cliente, digite o seguinte comando -
npx create-react-app hello-world-client
Isso instalará tudo o que é necessário para um aplicativo típico de reação. onpx utility e create-react-appferramentas criam um projeto com o nome hello-world-client. Assim que a instalação for concluída, abra o projeto no VSCode.
Instale os módulos do roteador para reagir usando o seguinte comando - npm install react-router-dom.
Etapa 2 - Iniciar o cliente hello-world
Altere o caminho da pasta atual no terminal para hello-world-client. Digite npm start para iniciar o projeto. Isso executará um servidor de desenvolvimento na porta 3000, abrirá automaticamente o navegador e carregará a página de índice.
Isso é mostrado na imagem abaixo -
                Etapa 3 - Instale as bibliotecas cliente Apollo
Para instalar um cliente Apollo, abra um novo terminal e esteja no caminho da pasta do projeto atual. Digite o seguinte comando -
npm install apollo-boost graphql
Isso fará o download das bibliotecas Graphql para o lado do cliente e também do pacote Apollo Boost. Podemos verificar isso digitando npm view apollo-boost dependencies. Isso terá muitas dependências, conforme mostrado abaixo -
{ 
   'apollo-cache': '^1.1.15',
   'apollo-cache-inmemory': '^1.2.8',
   'apollo-client': '^2.4.0',
   'apollo-link': '^1.0.6',
   'apollo-link-error': '^1.0.3',
   'apollo-link-http': '^1.3.1',
   'apollo-link-state': '^0.4.0',
   'graphql-tag': '^2.4.2' 
}
Podemos ver claramente que a biblioteca cliente-apollo está instalada.
Etapa 4 - Modificar o componente do aplicativo no arquivo index.js
Para uma aplicação simples de reação, você só precisa manter o index.js dentro src pasta e index.htmlem pasta pública; todos os outros arquivos gerados automaticamente podem ser removidos.
A estrutura do diretório é fornecida abaixo -
hello-world-client /
   -->node_modules
   -->public
      index.html
   -->src
      index.js
      students.js
   -->package.json
Adicione um arquivo adicional students.js que conterá o componente Students. Os detalhes do aluno são obtidos por meio do Componente do aluno. No componente de aplicativo, estamos usando um HashRouter.
A seguir está o index.js na aplicação de reação -
import React, {Component} from 'react';
import ReactDOM from 'react-dom';
import {HashRouter, Route, Link} from 'react-router-dom'
//components
import Students from './students'
class App extends Component {
   render() {
      return(
         <div><h1>Home !!</h1>
         <h2>Welcome to React Application !! </h2>
         </div>
      )
   }
}
function getTime() {
   var d = new Date();
   return d.getHours()+":"+d.getMinutes()+":"+d.getSeconds()
}
const routes = <HashRouter>
   <div>
      <h4>Time from react app:{getTime()}</h4>
      <header>
         <h1>  <Link to="/">Home</Link> 
         <Link to = "/students">Students</Link>  </h1>
      </header>
      <Route exact path = "/students" component = {Students}></Route>
      <Route exact path = "/" component = {App}></Route>
   </div>
</HashRouter>
ReactDOM.render(routes, document.querySelector("#root"))
Etapa 5 - Editar Alunos de Componente em Students.js
No Componente de alunos, usaremos as duas abordagens a seguir para carregar dados -
Fetch API (loadStudents_noCache) - Isso irá disparar uma nova solicitação toda vez que clicar na guia do aluno.
Apollo Client (loadWithApolloclient) - Isso irá buscar dados do cache.
Adicionar uma função loadWithApolloclientquais consultas para alunos e tempo do servidor. Esta função habilitará o cache. Aqui, usamos uma função gql para analisar a consulta.
async loadWithApolloclient() {
   const query = gql`{
      getTime
      students {
         id
         firstName
      }
   }`;
   const {data} = await  client.query({query})
   return data;
}
o Fetch APIé uma interface simples para buscar recursos. Fetch torna mais fácil fazer solicitações da web e lidar com respostas do que com o XMLHttpRequest mais antigo. O método a seguir mostra o carregamento de dados diretamente usando fetch api -
async  loadStudents_noCache() {
      const response = await fetch('http://localhost:9000/graphql', {
      method:'POST',
      headers:{'content-type':'application/json'},
      body:JSON.stringify({query:`{
         getTime
         students {
            id
            firstName
         }
      }`})
   })
   const rsponseBody = await response.json();
   return rsponseBody.data;
}
No construtor de StudentsComponent, chame o loadWithApolloClientmétodo. O completo Student.js o arquivo está abaixo -
import React, {Component} from 'react';
import { Link} from 'react-router-dom'
//Apollo Client
import {ApolloClient, HttpLink, InMemoryCache} from 'apollo-boost'
import gql from 'graphql-tag'
const client = new ApolloClient({
   link: new HttpLink({uri:`http://localhost:9000/graphql`}),
   cache:new InMemoryCache()
})
class Students extends Component {
   constructor(props) {
      super(props);
      this.state = {
         students:[{id:1,firstName:'test'}],
         serverTime:''
      }
      this.loadWithApolloclient().then(data => {
         this.setState({
            students:data.students,
            serverTime:data.getTime
         })
      })
   }
   
   async  loadStudents_noCache() {
      const response = await fetch('http://localhost:9000/graphql', {
         method:'POST',
         headers:{'content-type':'application/json'},
         body:JSON.stringify({query:`{
            getTime
            students {
               id
               firstName
            }
         }`})
      })
      const rsponseBody =  await response.json();
      return rsponseBody.data;
   }
   
   async loadWithApolloclient() {
      console.log("inside apollo client function")
      const query = gql`{
         getTime
         students {
            id
            firstName
         }
      }`;
      const {data} = await  client.query({query})
      return data;
   }
   
   render() {
      return(
         <div>
            <h3>Time from GraphQL server :{this.state.serverTime}</h3>
            <p>Following Students Found </p>
            <div>
               <ul>
                  {
                     this.state.students.map(s => {
                        return(
                           <li key = {s.id}>
                              {s.firstName}
                           </li>
                        )
                     })
                  }
               </ul>
            </div>
         </div>
      )
   }
}
export default Students
Etapa 6 - Executar o aplicativo React com npm start
Você pode testar o aplicativo Rea, alternando da guia inicial para a guia alunos. Assim que a guia de alunos for carregada com os dados do servidor. Ele armazenará os dados em cache. Você pode testá-lo alternando da guia casa para a guia de alunos várias vezes. A saída será como mostrado abaixo -
                Se você carregou a página dos alunos primeiro digitando o URL, http://localhost:3000/#/students, você pode ver que o tempo de carregamento para o app react e GraphQL seria aproximadamente o mesmo. Depois disso, se você alternar para a visualização inicial e retornar ao servidor GraphQL, a hora não mudará. Isso mostra que os dados estão armazenados em cache.
Etapa 7 - Alterar a chamada loadWithApolloclient para loadStudents_noCache
Se você alterar o método de carregamento para loadStudents_noCacheno construtor de StudentComponent, a saída não armazenará os dados em cache. Isso mostra a diferença entre armazenamento em cache e não armazenamento em cache.
this.loadStudents_noCache().then(data => {
   this.setState({
      students:data.students,
      serverTime:data.getTime
   })
})
                
                A partir da saída acima, fica claro que se você alternar entre as guias, o tempo do servidor graphql será sempre o mais recente, o que significa que os dados não são armazenados em cache.