Direttive in GraphQL: Guida Completa
Le direttive in GraphQL sono uno strumento potente che consente di modificare il comportamento delle query, delle mutazioni e dello schema stesso in modo dinamico. Con le direttive, è possibile controllare quali campi devono essere inclusi in una risposta, gestire la cache, applicare logiche di autenticazione, e molto altro. In questa guida, esploreremo le direttive predefinite in GraphQL, come @include
e @skip
, e impareremo a creare direttive personalizzate per soddisfare esigenze specifiche.
1. Cosa Sono le Direttive in GraphQL?
Le direttive in GraphQL sono annotazioni speciali che possono essere applicate a campi, frammenti, query, mutazioni e tipi all’interno dello schema. Esse permettono di alterare il comportamento della richiesta o della definizione dello schema in base a determinate condizioni.
Le direttive possono essere utilizzate per:
- Condizionare l’inclusione di campi.
- Deprecare campi o tipi.
- Applicare logiche di validazione, caching o autorizzazione.
- Modificare lo schema a runtime.
2. Direttive Predefinite in GraphQL
GraphQL fornisce alcune direttive predefinite che sono supportate da qualsiasi implementazione GraphQL. Le due direttive più comuni sono @include
e @skip
.
2.1. Direttiva @include
La direttiva @include
consente di includere un campo in una query solo se una condizione specificata è vera.
Esempio di Uso
query getUser($withEmail: Boolean!) {
user(id: "1") {
id
name
email @include(if: $withEmail)
}
}
In questo esempio, il campo email
verrà incluso nella risposta solo se la variabile $withEmail
è true
.
2.2. Direttiva @skip
La direttiva @skip
è l’opposto di @include
e permette di saltare un campo in una query se una determinata condizione è vera.
Esempio di Uso
query getUser($withoutEmail: Boolean!) {
user(id: "1") {
id
name
email @skip(if: $withoutEmail)
}
}
Qui, il campo email
sarà omesso dalla risposta se la variabile $withoutEmail
è true
.
2.3. Direttiva @deprecated
La direttiva @deprecated
viene utilizzata per indicare che un campo o un tipo non dovrebbe più essere utilizzato. È utile per mantenere la compatibilità con versioni precedenti dell’API mentre si migrano i client verso nuovi campi o tipi.
Esempio di Uso
type User {
id: ID!
username: String! @deprecated(reason: "Use 'name' instead")
name: String!
}
In questo caso, username
è marcato come deprecato e il messaggio di avviso indica di usare name
al suo posto.
3. Creare Direttive Personalizzate
Oltre alle direttive predefinite, GraphQL permette di creare direttive personalizzate che possono essere applicate a livello di schema o query. Le direttive personalizzate sono molto potenti e possono essere utilizzate per implementare logiche specifiche, come l’autenticazione, la validazione, o la manipolazione dei dati.
3.1. Definire una Direttiva Personalizzata
Le direttive personalizzate sono definite nello schema GraphQL con la parola chiave directive
.
Esempio: Direttiva @auth
per l’Autenticazione
directive @auth(role: String) on FIELD_DEFINITION
type Query {
posts: [Post!]! @auth(role: "admin")
}
type Post {
id: ID!
title: String!
content: String!
}
In questo esempio, la direttiva @auth
è applicata alla query posts
, richiedendo che solo gli utenti con il ruolo di “admin” possano accedere ai post.
3.2. Implementare la Logica della Direttiva
Per implementare la logica dietro una direttiva personalizzata, è necessario creare un SchemaDirectiveVisitor
in Apollo Server.
Esempio di Implementazione in Apollo Server
const {
SchemaDirectiveVisitor,
AuthenticationError,
} = require("apollo-server");
const { defaultFieldResolver } = require("graphql");
class AuthDirective extends SchemaDirectiveVisitor {
visitFieldDefinition(field) {
const { resolve = defaultFieldResolver } = field;
const { role } = this.args;
field.resolve = async function (...args) {
const context = args[2];
if (context.user.role !== role) {
throw new AuthenticationError("Not authorized");
}
return resolve.apply(this, args);
};
}
}
const typeDefs = gql`
directive @auth(role: String) on FIELD_DEFINITION
type Query {
posts: [Post!]! @auth(role: "admin")
}
type Post {
id: ID!
title: String!
content: String!
}
`;
const resolvers = {
Query: {
posts: () => posts, // Assume "posts" è un array di oggetti Post
},
};
const server = new ApolloServer({
typeDefs,
resolvers,
schemaDirectives: {
auth: AuthDirective,
},
context: ({ req }) => {
// Simulazione di un utente autenticato
const user = { role: "admin" };
return { user };
},
});
server.listen().then(({ url }) => {
console.log(`Server ready at ${url}`);
});
In questo esempio, la direttiva @auth
controlla se l’utente ha il ruolo richiesto per accedere ai dati. Se l’utente non ha il ruolo corretto, viene lanciato un errore di autenticazione.
4. Best Practices per l’Uso delle Direttive
4.1. Evitare l’Abuso di Direttive
Sebbene le direttive siano potenti, è importante non abusarne. L’uso eccessivo di direttive può rendere lo schema difficile da leggere e manutenere. Utilizza le direttive solo quando offrono un chiaro vantaggio rispetto a soluzioni alternative.
4.2. Documentare le Direttive
Assicurati di documentare chiaramente le direttive personalizzate nel tuo schema, spiegando come e quando dovrebbero essere utilizzate. Questo aiuta gli altri sviluppatori a comprendere e utilizzare correttamente le direttive.
4.3. Testare Direttamente le Direttive
Le direttive personalizzate possono introdurre logiche complesse che necessitano di test approfonditi. Implementa test automatizzati per verificare che le direttive si comportino come previsto in tutte le situazioni.
4.4. Considerare l’Impatto sulle Performance
Alcune direttive, come quelle che coinvolgono operazioni di autenticazione o caching, possono avere un impatto sulle performance. Assicurati di misurare e ottimizzare l’uso delle direttive in produzione.
Conclusione
Le direttive in GraphQL sono un potente strumento per estendere e personalizzare il comportamento delle query, delle mutazioni e dello schema. Comprendendo come utilizzare le direttive predefinite e come creare direttive personalizzate, puoi aggiungere logiche avanzate al tuo schema GraphQL, migliorando la flessibilità e l’efficienza della tua API. Seguendo le best practices delineate in questa guida, sarai in grado di utilizzare le direttive in modo efficace e sicuro.