Creazione di uno Schema GraphQL: Guida Passo-Passo
Lo schema GraphQL è il cuore di ogni API GraphQL. Definisce la struttura dei dati, le query che possono essere eseguite, le mutazioni per modificare i dati e le subscription per gestire aggiornamenti in tempo reale. Creare uno schema solido e ben strutturato è fondamentale per costruire un’API scalabile, efficiente e facile da manutenere.
In questa guida, esploreremo passo-passo come creare uno schema GraphQL, dalla definizione dei tipi alla gestione delle operazioni complesse.
Cos’è uno Schema GraphQL?
Uno schema GraphQL è una rappresentazione del modello di dati che l’API espone. Definisce i tipi di dati, le relazioni tra di essi, e le operazioni che possono essere eseguite (query, mutazioni e subscription). Lo schema è scritto in un linguaggio di definizione del tipo chiamato SDL (Schema Definition Language).
1. Creazione di un Nuovo Progetto
Iniziamo creando un nuovo progetto Node.js e installando le dipendenze necessarie:
mkdir my-graphql-api
cd my-graphql-api
npm init -y
npm install apollo-server graphql
2. Definizione dello Schema di Base
2.1. Definire i Tipi di Dati
I tipi di dati (o types) rappresentano le entità del dominio dell’applicazione. Per esempio, in un sistema di gestione dei contenuti (CMS), potresti avere tipi come Post
, Author
, e Comment
.
Crea un file chiamato schema.js
:
const { gql } = require("apollo-server");
const typeDefs = gql`
type Post {
id: ID!
title: String!
content: String!
author: Author!
comments: [Comment!]!
}
type Author {
id: ID!
name: String!
posts: [Post!]!
}
type Comment {
id: ID!
content: String!
post: Post!
author: Author!
}
`;
module.exports = typeDefs;
2.2. Definire le Query
Le query sono operazioni che permettono di leggere i dati. Ogni query può restituire uno o più tipi definiti nello schema.
const typeDefs = gql`
# ... (tipi giĂ definiti)
type Query {
posts: [Post!]!
post(id: ID!): Post
authors: [Author!]!
author(id: ID!): Author
}
`;
In questo esempio, abbiamo definito alcune query per ottenere la lista dei post, un singolo post per ID, la lista degli autori, e un singolo autore per ID.
2.3. Definire le Mutazioni
Le mutazioni sono operazioni che permettono di creare, aggiornare o eliminare dati.
const typeDefs = gql`
# ... (tipi e query giĂ definiti)
type Mutation {
createPost(title: String!, content: String!, authorId: ID!): Post!
updatePost(id: ID!, title: String, content: String): Post!
deletePost(id: ID!): Boolean!
}
`;
Queste mutazioni consentono di creare un nuovo post, aggiornare un post esistente e cancellare un post.
2.4. Definire le Subscription
Le subscription permettono ai client di iscriversi a eventi in tempo reale, come quando un nuovo post viene creato.
const typeDefs = gql`
# ... (tipi, query e mutazioni giĂ definiti)
type Subscription {
postCreated: Post!
}
`;
3. Implementazione dei Resolvers
I resolvers sono funzioni che risolvono le query, le mutazioni e le subscription definite nello schema, fornendo i dati effettivi.
Crea un file chiamato resolvers.js
:
const { PubSub } = require("apollo-server");
const pubsub = new PubSub();
const posts = [];
const authors = [];
const resolvers = {
Query: {
posts: () => posts,
post: (parent, args) => posts.find((post) => post.id === args.id),
authors: () => authors,
author: (parent, args) => authors.find((author) => author.id === args.id),
},
Mutation: {
createPost: (parent, args) => {
const post = {
id: `${posts.length + 1}`,
title: args.title,
content: args.content,
author: authors.find((author) => author.id === args.authorId),
};
posts.push(post);
pubsub.publish("POST_CREATED", { postCreated: post });
return post;
},
updatePost: (parent, args) => {
const post = posts.find((post) => post.id === args.id);
if (!post) throw new Error("Post not found");
if (args.title) post.title = args.title;
if (args.content) post.content = args.content;
return post;
},
deletePost: (parent, args) => {
const postIndex = posts.findIndex((post) => post.id === args.id);
if (postIndex === -1) return false;
posts.splice(postIndex, 1);
return true;
},
},
Subscription: {
postCreated: {
subscribe: () => pubsub.asyncIterator(["POST_CREATED"]),
},
},
};
module.exports = resolvers;
4. Configurazione del Server Apollo
Ora che abbiamo definito lo schema e i resolvers, possiamo configurare il server Apollo per esporre la nostra API GraphQL.
Crea un file chiamato index.js
:
const { ApolloServer } = require("apollo-server");
const typeDefs = require("./schema");
const resolvers = require("./resolvers");
const server = new ApolloServer({ typeDefs, resolvers });
server.listen().then(({ url }) => {
console.log(`Server pronto su ${url}`);
});
5. Eseguire il Server
Avvia il server Node.js:
node index.js
Il server sarà disponibile all’indirizzo http://localhost:4000/
. Puoi utilizzare Apollo Studio Explorer per testare le query, le mutazioni e le subscription.
6. Best Practices per la Creazione dello Schema
6.1. Organizzare lo Schema in Moduli
Per mantenere lo schema manutenibile, suddividilo in moduli separati per tipi, query, mutazioni e subscription. Questo rende più facile la gestione e l’evoluzione dello schema nel tempo.
6.2. Utilizzare Tipi Input per le Mutazioni Complesse
Quando le mutazioni accettano molti parametri, utilizza tipi input per migliorare la leggibilitĂ e la manutenibilitĂ .
input PostInput {
title: String!
content: String!
authorId: ID!
}
type Mutation {
createPost(input: PostInput!): Post!
}
6.3. Documentare lo Schema
Aggiungi descrizioni ai tipi, campi e operazioni nello schema per migliorare la comprensione e la facilità d’uso dell’API.
"""
Rappresenta un post nel blog.
"""
type Post {
id: ID!
title: String!
content: String!
author: Author!
}
Conclusione
La creazione di uno schema GraphQL è un passo fondamentale nello sviluppo di un’API. Con un design accurato e l’implementazione di best practices, puoi costruire uno schema scalabile e facile da mantenere, che offre una solida base per l’evoluzione della tua applicazione. Seguendo questa guida passo-passo, hai imparato come definire tipi, query, mutazioni e subscription, e come implementare i resolvers per gestire le operazioni.