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
