Les consultes persistents són una tècnica avançada en GraphQL que permet millorar el rendiment i la seguretat de les aplicacions. En lloc d'enviar consultes de GraphQL directament des del client al servidor, les consultes es guarden (persisten) al servidor i el client només envia un identificador de la consulta. Això redueix la càrrega de treball del servidor i minimitza els riscos de seguretat associats amb l'execució de consultes arbitràries.
Avantatges de les consultes persistents
-
Millora del rendiment:
- Redueix la mida de les peticions HTTP, ja que només s'envia un identificador en lloc de la consulta completa.
- Permet la precompilació i optimització de les consultes al servidor.
-
Seguretat:
- Evita l'execució de consultes arbitràries, ja que només es poden executar les consultes predefinides.
- Redueix el risc d'injecció de codi maliciós.
-
Gestió de versions:
- Facilita la gestió de versions de les consultes, ja que es poden actualitzar les consultes persistents sense canviar el codi del client.
Implementació de consultes persistents
Pas 1: Definir les consultes
Primer, definim les consultes que volem persistir. Aquestes consultes es poden escriure en fitxers separats o en un sol fitxer JSON.
# Fitxer: queries.graphql
query GetUser {
user(id: 1) {
id
name
email
}
}
query GetPosts {
posts {
id
title
content
}
}Pas 2: Assignar identificadors a les consultes
Assignem identificadors únics a cada consulta. Això es pot fer manualment o utilitzant una eina automatitzada.
{
"GetUser": "query GetUser { user(id: 1) { id name email } }",
"GetPosts": "query GetPosts { posts { id title content } }"
}Pas 3: Emmagatzemar les consultes al servidor
Les consultes es guarden al servidor en una estructura de dades adequada, com ara un objecte JavaScript o una base de dades.
const persistedQueries = {
"GetUser": "query GetUser { user(id: 1) { id name email } }",
"GetPosts": "query GetPosts { posts { id title content } }"
};Pas 4: Configurar el servidor per utilitzar consultes persistents
Modifiquem el servidor GraphQL per acceptar identificadors de consultes en lloc de consultes completes.
const { ApolloServer, gql } = require('apollo-server');
const typeDefs = gql`
type User {
id: ID!
name: String!
email: String!
}
type Post {
id: ID!
title: String!
content: String!
}
type Query {
user(id: ID!): User
posts: [Post]
}
`;
const resolvers = {
Query: {
user: (_, { id }) => ({ id, name: "John Doe", email: "john@example.com" }),
posts: () => [
{ id: 1, title: "Post 1", content: "Content 1" },
{ id: 2, title: "Post 2", content: "Content 2" }
]
}
};
const server = new ApolloServer({
typeDefs,
resolvers,
context: ({ req }) => {
const queryId = req.headers['x-query-id'];
if (queryId && persistedQueries[queryId]) {
req.body.query = persistedQueries[queryId];
}
}
});
server.listen().then(({ url }) => {
console.log(`Server ready at ${url}`);
});Pas 5: Enviar peticions des del client
El client envia peticions utilitzant els identificadors de les consultes en lloc de les consultes completes.
const fetch = require('node-fetch');
const queryId = "GetUser";
const response = await fetch('http://localhost:4000/graphql', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-query-id': queryId
},
body: JSON.stringify({ variables: { id: 1 } })
});
const data = await response.json();
console.log(data);Exercici pràctic
Exercici
- Defineix una nova consulta
GetCommentsque recuperi una llista de comentaris amb els campsid,textiauthor. - Assigna un identificador únic a la consulta
GetCommentsi emmagatzema-la al servidor. - Modifica el servidor per acceptar l'identificador de la consulta
GetComments. - Envia una petició des del client utilitzant l'identificador de la consulta
GetComments.
Solució
- Definició de la consulta
GetComments:
- Assignació d'identificador:
{
"GetUser": "query GetUser { user(id: 1) { id name email } }",
"GetPosts": "query GetPosts { posts { id title content } }",
"GetComments": "query GetComments { comments { id text author } }"
}- Emmagatzematge al servidor:
const persistedQueries = {
"GetUser": "query GetUser { user(id: 1) { id name email } }",
"GetPosts": "query GetPosts { posts { id title content } }",
"GetComments": "query GetComments { comments { id text author } }"
};- Modificació del servidor:
const { ApolloServer, gql } = require('apollo-server');
const typeDefs = gql`
type Comment {
id: ID!
text: String!
author: String!
}
type Query {
comments: [Comment]
}
`;
const resolvers = {
Query: {
comments: () => [
{ id: 1, text: "Comment 1", author: "Author 1" },
{ id: 2, text: "Comment 2", author: "Author 2" }
]
}
};
const server = new ApolloServer({
typeDefs,
resolvers,
context: ({ req }) => {
const queryId = req.headers['x-query-id'];
if (queryId && persistedQueries[queryId]) {
req.body.query = persistedQueries[queryId];
}
}
});
server.listen().then(({ url }) => {
console.log(`Server ready at ${url}`);
});- Petició des del client:
const fetch = require('node-fetch');
const queryId = "GetComments";
const response = await fetch('http://localhost:4000/graphql', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-query-id': queryId
}
});
const data = await response.json();
console.log(data);Conclusió
Les consultes persistents són una tècnica poderosa per millorar el rendiment i la seguretat de les aplicacions GraphQL. En aquest tema, hem après com definir, emmagatzemar i utilitzar consultes persistents tant al servidor com al client. Aquesta tècnica és especialment útil en entorns de producció on la seguretat i l'eficiència són crucials.
Curs de GraphQL
Mòdul 1: Introducció a GraphQL
- Què és GraphQL?
- GraphQL vs REST
- Configuració d'un servidor GraphQL
- Conceptes bàsics de l'esquema de GraphQL
Mòdul 2: Conceptes bàsics
Mòdul 3: Disseny avançat d'esquemes
Mòdul 4: Treballant amb dades
- Connexió a una base de dades
- Estratègies de recuperació de dades
- Agrupació i emmagatzematge en memòria cau
- Gestió d'errors
Mòdul 5: Rendiment i seguretat
Mòdul 6: Eines i ecosistema
Mòdul 7: Proves i desplegament
- Proves unitàries de resolvers
- Proves d'integració
- Integració contínua
- Desplegament de servidors GraphQL
