Si recientemente comenzó a trabajar con GraphQL o revisó sus pros y contras, sin duda ha escuchado cosas como “GraphQL no admite el almacenamiento en caché” o “GraphQL no se preocupa por el almacenamiento en caché”. Y para la mayoría, eso es un gran problema.
La documentación oficial de GraphQL se refiere a técnicas de almacenamiento en caché, por lo que, claramente, la gente detrás de ella se preocupa por el almacenamiento en caché y sus beneficios de rendimiento.
La percepción de que GraphQL está en desacuerdo con el almacenamiento en caché es algo que quiero abordar en esta publicación. Quiero recorrer diferentes técnicas de almacenamiento en caché y cómo aprovechar la caché para consultas GraphQL.
Conseguir GraphQL en caché automáticamente
Considere la siguiente consulta para buscar una publicación y el autor de la publicación:
query getPost {
post(slug: "working-with-graphql-caching") {
id
title
author {
id
name
avatar
}
}
}
El único “truco de magia” que hace que el almacenamiento en caché automático de GraphQL funcione es el __typename
meta campo que exponen todas las API de GraphQL.
Como el nombre sugiere, __typename
devuelve el nombre del tipo de objeto. Este campo incluso se puede agregar manualmente a consultas existentes, y la mayoría de las veces, un cliente GraphQL o CDN lo hará por usted. urql es uno de esos clientes GraphQL. El servidor puede recibir una consulta como esta:
query getPost {
post(slug: "working-with-graphql-caching") {
__typename
id
title
author {
__typename
id
name
}
}
}
La respuesta con __typename
podría verse algo así:
{
data: {
__typename: "Post",
id: 5,
title: "Working with GraphQL Caching",
author: {
__typename: "User",
id: 1,
name: "Jamie Barton"
}
}
}
El __typename
es una pieza crítica del rompecabezas de almacenamiento en caché GraphQL porque ahora podemos almacenar en caché este resultado y saber que contiene el ID de publicación 5 y el ID de usuario 1.
Luego están las bibliotecas como Apollo y Relay, que también tienen algún nivel de almacenamiento en caché incorporado que podemos usar para el almacenamiento en caché automático. Como ya saben lo que hay en la caché, pueden remitirse a la caché en lugar de a las API remotas para obtener lo que el cliente solicita en una consulta.
Invalide automáticamente la caché cuando hay cambios
Imagina que el autor de la publicación edita el título de la publicación con la editPost
mutación:
mutation {
editPost(input: { id: 5, title: "Working with GraphQL Caching" }) {
id
title
}
}
Dado que el cliente GraphQL agrega automáticamente el __typename
, el resultado de esta mutación le dice inmediatamente a la caché que el ID de publicación 5 ha cambiado, y cualquier resultado de la consulta almacenada en caché que contenga esa publicación debe invalidarse:
{
data: {
__typename: "Post",
id: 5,
title: "Working with GraphQL Caching"
}
}
La próxima vez que un usuario envía la misma consulta, la consulta obtiene los nuevos datos del origen en lugar de entregar el resultado obsoleto de la caché. ¡Magia!
Almacenamiento en caché GraphQL normalizado
Muchos clientes GraphQL no almacenan en caché los resultados completos de las consultas.
En cambio, normalizan los datos almacenados en caché en dos estructuras de datos; uno que asocia cada objeto con sus datos (p. ej. Post #5: { … }
, User #1: { … }
, etc.); y uno que asocie cada consulta con los objetos que contiene (p. ej. getPost: { Post #5, User #1}
, etc.).
Consulte la documentación de urql sobre el almacenamiento en caché normalizado o la “Desmitificación de la normalización de la caché” de Apollo para ver ejemplos específicos y casos de uso.
Almacenamiento en caché de casos extremos con GraphQL
El caso extremo principal que las cachés GraphQL no pueden manejar automáticamente es agregar elementos a una lista. Entonces, si un createPost
La mutación pasa a través del caché, no sabe a qué lista específica agregar ese elemento.
La “solución” más fácil para esto es consultar el tipo principal en la mutación si existe. Por ejemplo, en la consulta siguiente, consultamos el community
relación en post
:
query getPost {
post(slug: "working-with-graphql-caching") {
id
title
author {
id
name
avatar
}
# Also query the community of the post
community {
id
name
}
}
}
Entonces también podemos consultar esa comunidad desde el createPost
mutación e invalidar cualquier resultado de consulta almacenado en caché que contenga esa comunidad:
mutation createPost {
createPost(input: { ... }) {
id
title
# Also query and thus invalidate the community of the post
community {
id
name
}
}
}
Si bien es imperfecto, el esquema escrito y __typename
El campo meta son las claves que hacen que las API GraphQL sean ideales para el almacenamiento en caché.
Es posible que a estas alturas esté pensando que todo esto es un truco y que GraphQL todavía no es compatible con el almacenamiento en caché tradicional. Y no te equivocarías. Dado que GraphQL opera a través de un POST
solicitud, deberá descargar al cliente de la aplicación y utilizar los “trucos” anteriores para aprovechar el almacenamiento en caché del navegador moderno con GraphQL.
Dicho esto, este tipo de cosas no siempre es posible, ni tiene mucho sentido para administrar la caché en el cliente. Los clientes GraphQL hacen que actualice manualmente la caché para casos aún más complicados, pero un servicio como GraphCDN proporciona una experiencia de almacenamiento en caché “similar a un servidor”, que también expone una API de purga manual que le permite hacer cosas como esta para un mayor control de la caché:
# Purge all occurrences of a specific object
mutation {
purgeUser(id: [5])
}
# Purge by query name
mutation {
_purgeQuery(queries: [listUsers, listPosts])
}
# Purge all occurrences of a type
mutation {
purgeUser
}
Ahora, no importa dónde consuma su punto final GraphCDN, ya no es necesario volver a implementar estrategias de caché en toda su lógica del lado del cliente en dispositivos móviles, web, etc. El almacenamiento en caché de borde hace que su API se sienta súper rápida y reduce la carga en compartir el caché entre sus usuarios y mantenerlo alejado de cada uno de sus clientes.
Habiendo usado GraphCDN recientemente en un proyecto, se encargó de configurar un caché en el cliente o servidor por mí, lo que me permitió continuar con mi proyecto. Por ejemplo, puedo cambiar mi punto final con GraphCDN y obtener la complejidad de las consultas (que llegará pronto), análisis y más de forma gratuita.
Entonces, ¿GraphQL se preocupa por el almacenamiento en caché? ¡Ciertamente lo hace! No solo proporciona algunos métodos de almacenamiento en caché automáticos incorporados, sino que varias bibliotecas GraphQL ofrecen formas adicionales de hacerlo e incluso administrarlo.
Esperamos que este artículo le haya dado una idea de la historia del almacenamiento en caché de GraphQL y cómo implementarlo en el cliente, además de aprovechar las CDN para hacerlo todo por usted. Mi objetivo aquí no es venderle el uso de GraphQL en todos sus proyectos ni nada, pero si elige entre lenguajes de consulta y el almacenamiento en caché es una gran preocupación, sepa que GraphQL está más que preparado para la tarea.