GraphQL - Almacenamiento en caché

El almacenamiento en caché es el proceso de almacenar datos en un área de almacenamiento temporal llamada cache. Cuando regresa a una página que ha visitado recientemente, el navegador puede obtener esos archivos del caché en lugar del servidor original. Esto le ahorra tiempo y a la red la carga del tráfico adicional.

Las aplicaciones cliente que interactúan con GraphQL son responsables de almacenar en caché los datos al final. Un patrón posible para esto es reservar un campo, como id, para que sea un identificador único global.

Caché de InMemory

InMemoryCache es un almacén de datos normalizado que se usa comúnmente en aplicaciones cliente GraphQL sin el uso de otra biblioteca como Redux.

El código de muestra para usar InMemoryCache con ApolloClient se proporciona a continuación:

import {ApolloClient, HttpLink, InMemoryCache} from 'apollo-boost'
const cache = new InMemoryCache();

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

El constructor InMemoryCache toma un objeto de configuración opcional con propiedades para personalizar su caché.

No Señor. Descripción de parámetros
1

addTypename

Un booleano para determinar si agregar __typename al documento (predeterminado: verdadero)

2

dataIdFromObject

Una función que toma un objeto de datos y devuelve un identificador único que se utilizará al normalizar los datos en la tienda.

3

fragmentMatcher

De forma predeterminada, InMemoryCache usa un comparador de fragmentos heurístico

4

cacheRedirects

Un mapa de funciones para redirigir una consulta a otra entrada en la caché antes de que se realice una solicitud.

Ilustración

Crearemos una aplicación de una sola página en ReactJS con dos pestañas, una para la pestaña de inicio y otra para los estudiantes. La pestaña de estudiantes cargará datos de una API de servidor GraphQL. La aplicación consultará los datos de los estudiantes cuando el usuario navegue desde la pestaña de inicio a la pestaña de estudiantes. Los datos resultantes serán almacenados en caché por la aplicación.

También consultaremos la hora del servidor usando getTimecampo para verificar si la página está almacenada en caché. Si se devuelven datos de la caché, la página mostrará la hora de la primera solicitud enviada al servidor. Si los datos son el resultado de una nueva solicitud realizada al servidor, siempre mostrará la última hora del servidor.

Configurar el servidor

Los siguientes son los pasos para configurar el servidor:

Paso 1: descargue e instale las dependencias necesarias para el proyecto

Crea una carpeta cache-server-app. Cambie su directorio a cache-server-app desde la terminal. Siga los pasos 3 a 5 explicados en el capítulo Configuración del entorno.

Paso 2: crea un esquema

Añadir schema.graphql archivo en la carpeta del proyecto cache-server-app y agregue el siguiente código -

type Query {
   students:[Student]
   getTime:String
}

type Student {
   id:ID!
   firstName:String
   lastName:String
   fullName:String
}

Paso 3: agregar resolutores

Cree un archivo resolvers.js en la carpeta del proyecto y agregue el siguiente 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}

Paso 4: ejecutar la aplicación

Cree un archivo server.js. Consulte el paso 8 del capítulo Configuración del entorno. Ejecute el comando npm start en la terminal. El servidor estará funcionando en el puerto 9000. Aquí, usaremos GraphiQL como cliente para probar la aplicación.

Abra el navegador e ingrese la URL http://localhost:9000/graphiql. Escriba la siguiente consulta en el editor:

{
   getTime
   students {
      id
      firstName
   }
}

La respuesta de muestra muestra los nombres de los estudiantes y la hora del servidor.

{
   "data": {
      "getTime": "22:18:42",
      "students": [
         {
            "id": "S1001",
            "firstName": "Mohtashim"
         },
         {
            "id": "S1002",
            "firstName": "Kannan"
         },
         {
            "id": "S1003",
            "firstName": "Kiran"
         }
      ]
   }
}

Configuración del cliente ReactJS

Abra una nueva terminal para el cliente. El terminal del servidor debe seguir funcionando antes de ejecutar la aplicación cliente. La aplicación React se ejecutará en el puerto número 3000 y la aplicación del servidor en el puerto número 9000.

Paso 1: crea una aplicación React

En la terminal del cliente, escriba el siguiente comando:

npx create-react-app hello-world-client

Esto instalará todo lo necesario para una aplicación típica de reacción. losnpx utility y create-react-appLas herramientas crean un proyecto con el nombre hello-world-client. Una vez que se complete la instalación, abra el proyecto en VSCode.

Instale los módulos del enrutador para reaccionar usando el siguiente comando: npm install react-router-dom.

Paso 2: iniciar hello-world-client

Cambie la ruta de la carpeta actual en la terminal a hello-world-client. Escriba npm start para iniciar el proyecto. Esto ejecutará un servidor de desarrollo en el puerto 3000 y automáticamente abrirá el navegador y cargará la página de índice.

Esto se muestra en la captura de pantalla que se muestra a continuación:

Paso 3: instalar las bibliotecas cliente de Apollo

Para instalar un cliente Apollo, abra una nueva terminal y esté en la ruta de la carpeta del proyecto actual. Escriba el siguiente comando:

npm install apollo-boost graphql

Esto descargará las bibliotecas graphql del lado del cliente y también el paquete Apollo Boost. Podemos verificar esto de forma cruzada escribiendo npm view apollo-boost dependencies. Esto tendrá muchas dependencias como se muestra a continuación:

{ 
   '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 la biblioteca apollo-client está instalada.

Paso 4: modificar el componente de la aplicación en el archivo index.js

Para una aplicación de reacción simple, solo necesita mantener el index.js en src carpeta y index.htmlen carpeta pública; todos los demás archivos que se generan automáticamente se pueden eliminar.

La estructura del directorio se da a continuación:

hello-world-client /
   -->node_modules
   -->public
      index.html
   -->src
      index.js
      students.js
   -->package.json

Agregue un archivo adicional Students.js que contendrá el componente Students. Los detalles de los estudiantes se obtienen a través del Componente de estudiantes. En el componente de la aplicación, estamos usando un HashRouter.

Lo siguiente es el index.js en la aplicación de reacción -

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"))

Paso 5: Edite los estudiantes del componente en Students.js

En el Componente de estudiantes, usaremos los siguientes dos enfoques para cargar datos:

  • Fetch API (loadStudents_noCache) - Esto activará una nueva solicitud cada vez que haga clic en la pestaña del estudiante.

  • Apollo Client (loadWithApolloclient) - Esto obtendrá datos de la caché.

Agregar una función loadWithApolloclientqué consultas para los estudiantes y el tiempo del servidor. Esta función habilitará el almacenamiento en caché. Aquí usamos una función gql para analizar la consulta.

async loadWithApolloclient() {
   const query = gql`{
      getTime
      students {
         id
         firstName
      }
   }`;

   const {data} = await  client.query({query})
   return data;
}

los Fetch APIes una interfaz simple para buscar recursos. Fetch hace que sea más fácil realizar solicitudes web y manejar respuestas que con XMLHttpRequest anterior. El siguiente método muestra la carga de datos directamente 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;
}

En el constructor de StudentsComponent, llame al loadWithApolloClientmétodo. El completo Student.js el archivo está debajo -

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

Paso 6 - Ejecute la aplicación React con npm start

Puede probar la aplicación de reacción cambiando de la pestaña de inicio a la pestaña de estudiantes. Una vez que la pestaña de estudiantes está cargada con datos del servidor. Guardará los datos en caché. Puede probarlo cambiando de la pestaña de inicio a la de estudiantes varias veces. La salida será como se muestra a continuación:

Si ha cargado la página de los estudiantes primero escribiendo la URL, http://localhost:3000/#/students, puede ver que el tiempo de carga para la aplicación de reacción y GraphQL sería aproximadamente el mismo. Después de eso, si cambia a la vista de inicio y regresa al servidor GraphQL, la hora no cambiará. Esto muestra que los datos están almacenados en caché.

Paso 7: cambie la llamada loadWithApolloclient a loadStudents_noCache

Si cambia el método de carga a loadStudents_noCacheen el constructor de StudentComponent, la salida no almacenará en caché los datos. Esto muestra la diferencia entre almacenamiento en caché y sin almacenamiento en caché.

this.loadStudents_noCache().then(data => {
   this.setState({
      students:data.students,
      serverTime:data.getTime
   })
})

De la salida anterior, está claro que si cambia de una pestaña a otra, el tiempo del servidor graphql siempre será el último, lo que significa que los datos no se almacenan en caché.