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?

  1. Seguridad: Al usar consultas persistidas, se reduce el riesgo de inyección de consultas maliciosas, ya que solo se permiten las consultas predefinidas.
  2. Rendimiento: Las consultas persistidas pueden reducir la carga en el servidor al evitar la necesidad de analizar y validar consultas repetitivas.
  3. 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

  1. 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 } } }"
}
  1. 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
    }
  }
};
  1. 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

  1. Definir la consulta persistida: Añadimos la consulta en persistedQueries.json.
{
  "getComments": "query getComments($postId: ID!) { comments(postId: $postId) { id content author { id name } } }"
}
  1. 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
    }
  }
};
  1. 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.

© Copyright 2024. Todos los derechos reservados