Introducción
Las consultas persistidas son una técnica avanzada en GraphQL que permite almacenar consultas en el servidor y referenciarlas mediante un identificador único. Esto puede mejorar la seguridad, el rendimiento y la eficiencia de las aplicaciones GraphQL.
¿Por qué usar Consultas Persistidas?
- Seguridad: Al usar consultas persistidas, se reduce el riesgo de inyección de consultas maliciosas, ya que solo se permiten las consultas predefinidas.
- Rendimiento: Las consultas persistidas pueden reducir la carga en el servidor al evitar la necesidad de analizar y validar consultas repetitivas.
- Eficiencia: Al enviar solo un identificador en lugar de la consulta completa, se reduce el tamaño de las solicitudes y respuestas, lo que puede ser beneficioso en entornos con ancho de banda limitado.
Implementación de Consultas Persistidas
Paso 1: Definir y Almacenar Consultas
Primero, definimos las consultas que queremos persistir y las almacenamos en el servidor. Esto puede hacerse en un archivo JSON o en una base de datos.
{ "getUser": "query getUser($id: ID!) { user(id: $id) { id name email } }", "getPosts": "query getPosts { posts { id title content } }" }
Paso 2: Configurar el Servidor para Consultas Persistidas
En el servidor, necesitamos configurar un mecanismo para manejar las consultas persistidas. Aquí hay un ejemplo usando Apollo Server:
const { ApolloServer, gql } = require('apollo-server'); const persistedQueries = require('./persistedQueries.json'); // Archivo JSON con consultas persistidas const typeDefs = gql` type User { id: ID! name: String! email: String! } type Query { user(id: ID!): User posts: [Post] } type Post { id: ID! title: String! content: String! } `; const resolvers = { Query: { user: (parent, args, context, info) => { // Lógica para obtener el usuario }, posts: (parent, args, context, info) => { // Lógica para obtener los posts } } }; const server = new ApolloServer({ typeDefs, resolvers, plugins: [ { requestDidStart(requestContext) { const { queryHash } = requestContext.request.extensions; if (queryHash && persistedQueries[queryHash]) { requestContext.request.query = persistedQueries[queryHash]; } } } ] }); server.listen().then(({ url }) => { console.log(`🚀 Server ready at ${url}`); });
Paso 3: Enviar Consultas Persistidas desde el Cliente
En el cliente, en lugar de enviar la consulta completa, enviamos el identificador de la consulta persistida.
const queryHash = 'getUser'; // Identificador de la consulta persistida const variables = { id: '123' }; fetch('http://localhost:4000/graphql', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ extensions: { queryHash }, variables }) }) .then(response => response.json()) .then(data => console.log(data));
Ejercicio Práctico
Ejercicio 1: Implementar una Consulta Persistida
- Definir una nueva consulta persistida: Añade una nueva consulta para obtener los comentarios de un post en el archivo
persistedQueries.json
.
{ "getComments": "query getComments($postId: ID!) { comments(postId: $postId) { id content author { id name } } }" }
- Actualizar el servidor: Modifica el servidor para manejar la nueva consulta persistida.
const typeDefs = gql` type User { id: ID! name: String! email: String! } type Comment { id: ID! content: String! author: User! } type Post { id: ID! title: String! content: String! comments: [Comment] } type Query { user(id: ID!): User posts: [Post] comments(postId: ID!): [Comment] } `; const resolvers = { Query: { user: (parent, args, context, info) => { // Lógica para obtener el usuario }, posts: (parent, args, context, info) => { // Lógica para obtener los posts }, comments: (parent, args, context, info) => { // Lógica para obtener los comentarios } } };
- Enviar la consulta desde el cliente: Envía la nueva consulta persistida desde el cliente.
const queryHash = 'getComments'; // Identificador de la consulta persistida const variables = { postId: '456' }; fetch('http://localhost:4000/graphql', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ extensions: { queryHash }, variables }) }) .then(response => response.json()) .then(data => console.log(data));
Solución
- Definir la consulta persistida: Añadimos la consulta en
persistedQueries.json
.
{ "getComments": "query getComments($postId: ID!) { comments(postId: $postId) { id content author { id name } } }" }
- Actualizar el servidor: Modificamos el servidor para manejar la nueva consulta.
const typeDefs = gql` type User { id: ID! name: String! email: String! } type Comment { id: ID! content: String! author: User! } type Post { id: ID! title: String! content: String! comments: [Comment] } type Query { user(id: ID!): User posts: [Post] comments(postId: ID!): [Comment] } `; const resolvers = { Query: { user: (parent, args, context, info) => { // Lógica para obtener el usuario }, posts: (parent, args, context, info) => { // Lógica para obtener los posts }, comments: (parent, args, context, info) => { // Lógica para obtener los comentarios } } };
- Enviar la consulta desde el cliente: Enviamos la consulta persistida desde el cliente.
const queryHash = 'getComments'; // Identificador de la consulta persistida const variables = { postId: '456' }; fetch('http://localhost:4000/graphql', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ extensions: { queryHash }, variables }) }) .then(response => response.json()) .then(data => console.log(data));
Conclusión
Las consultas persistidas son una herramienta poderosa para mejorar la seguridad, el rendimiento y la eficiencia de las aplicaciones GraphQL. Al almacenar consultas en el servidor y referenciarlas mediante identificadores únicos, podemos reducir la carga en el servidor y minimizar el riesgo de inyección de consultas maliciosas. En este módulo, hemos aprendido cómo implementar consultas persistidas en un servidor GraphQL y cómo enviar estas consultas desde un cliente.
En el próximo módulo, exploraremos herramientas y ecosistemas que pueden mejorar aún más nuestra experiencia con GraphQL.
Curso de GraphQL
Módulo 1: Introducción a GraphQL
- ¿Qué es GraphQL?
- GraphQL vs REST
- Configuración de un Servidor GraphQL
- Conceptos Básicos del Esquema de GraphQL
Módulo 2: Conceptos Fundamentales
Módulo 3: Diseño Avanzado de Esquemas
Módulo 4: Trabajando con Datos
Módulo 5: Rendimiento y Seguridad
Módulo 6: Herramientas y Ecosistema
Módulo 7: Pruebas y Despliegue
- Pruebas Unitarias de Resolvers
- Pruebas de Integración
- Integración Continua
- Despliegue de Servidores GraphQL