🚀 Nuova versione beta disponibile! Feedback o problemi? Contattaci

Definizione di Mutations in GraphQL: Guida Completa

Codegrind Team•Aug 28 2024

Le mutations in GraphQL sono operazioni che permettono di creare, aggiornare o eliminare dati nel sistema. A differenza delle query, che sono utilizzate per leggere i dati, le mutations vengono utilizzate per modificarli, rendendole essenziali per le applicazioni che richiedono operazioni di scrittura. In questa guida, esploreremo come definire e implementare mutations in GraphQL, con esempi pratici e best practices per garantire che siano scalabili e manutenibili.

Cosa Sono le Mutations in GraphQL?

Le mutations sono operazioni che eseguono modifiche sui dati del sistema. Ogni mutation può essere paragonata a un’operazione HTTP POST, PUT, PATCH o DELETE in un’API REST. La differenza principale rispetto alle query è che le mutations possono avere effetti collaterali, come l’aggiornamento di un database o l’invio di una notifica.

1. Definire una Mutation nello Schema GraphQL

1.1. Creare lo Schema di Base

Per iniziare, definiamo uno schema di base che include tipi e una mutation semplice. Supponiamo di avere un’applicazione di blog, con tipi Post e Author.

Crea un file schema.js:

const { gql } = require("apollo-server");

const typeDefs = gql`
  type Post {
    id: ID!
    title: String!
    content: String!
    author: Author!
  }

  type Author {
    id: ID!
    name: String!
    posts: [Post!]!
  }

  type Query {
    posts: [Post!]!
    post(id: ID!): Post
  }

  type Mutation {
    createPost(title: String!, content: String!, authorId: ID!): Post!
  }
`;

module.exports = typeDefs;

1.2. Definire una Mutation

Nell’esempio sopra, abbiamo definito una mutation chiamata createPost che accetta tre argomenti: title, content, e authorId. Questa mutation crea un nuovo post associato a un autore esistente.

type Mutation {
  createPost(title: String!, content: String!, authorId: ID!): Post!
}

1.3. Tipi Input per Mutations Complesse

Per le mutations che richiedono più parametri, è consigliabile utilizzare tipi input per migliorare la leggibilità e la manutenibilità.

input PostInput {
  title: String!
  content: String!
  authorId: ID!
}

type Mutation {
  createPost(input: PostInput!): Post!
}

2. Implementare i Resolvers per le Mutations

I resolvers sono funzioni che eseguono la logica delle mutations, come la creazione di un nuovo record nel database.

Crea un file resolvers.js:

const { PubSub } = require("apollo-server");
const pubsub = new PubSub();

let posts = [];
let authors = [
  { id: "1", name: "Alice" },
  { id: "2", name: "Bob" },
];

const resolvers = {
  Query: {
    posts: () => posts,
    post: (parent, args) => posts.find((post) => post.id === args.id),
  },
  Mutation: {
    createPost: (parent, { input }) => {
      const author = authors.find((author) => author.id === input.authorId);
      if (!author) {
        throw new Error("Author not found");
      }

      const post = {
        id: `${posts.length + 1}`,
        title: input.title,
        content: input.content,
        author: author,
      };

      posts.push(post);
      pubsub.publish("POST_CREATED", { postCreated: post });

      return post;
    },
  },
  Author: {
    posts: (author) => posts.filter((post) => post.author.id === author.id),
  },
};

module.exports = resolvers;

In questo esempio, il resolver createPost:

  1. Trova l’autore nel sistema.
  2. Crea un nuovo oggetto Post.
  3. Aggiunge il nuovo post all’array posts.
  4. Restituisce il post creato.

3. Gestione degli Errori nelle Mutations

Le mutations possono fallire per vari motivi, come la mancanza di autorizzazioni o la violazione di vincoli sui dati. È essenziale gestire correttamente questi errori.

Esempio di Gestione degli Errori

Nel resolver createPost, abbiamo già gestito un errore quando l’autore non viene trovato. In caso di errori più complessi, potresti voler restituire errori più dettagliati utilizzando ApolloError.

const { ApolloError } = require("apollo-server");

const resolvers = {
  Mutation: {
    createPost: (parent, { input }) => {
      const author = authors.find((author) => author.id === input.authorId);
      if (!author) {
        throw new ApolloError("Author not found", "AUTHOR_NOT_FOUND");
      }

      // Logica per creare il post...

      return post;
    },
  },
};

4. Best Practices per Definire Mutations

4.1. Utilizzare Tipi Input

Come accennato, utilizzare tipi input per mutations complesse rende le operazioni più leggibili e manutenibili.

input UpdatePostInput {
  id: ID!
  title: String
  content: String
}

type Mutation {
  updatePost(input: UpdatePostInput!): Post!
}

4.2. Restituire i Dati Aggiornati

Dopo una mutation, è utile restituire i dati aggiornati. Questo permette al client di aggiornare l’interfaccia utente senza eseguire ulteriori query.

type Mutation {
  updatePost(id: ID!, title: String, content: String): Post!
}

4.3. Gestire le Relazioni in Mutations

Assicurati che le mutations gestiscano correttamente le relazioni tra i dati, come l’aggiornamento dei riferimenti tra un post e un autore.

4.4. Documentare le Mutations

Aggiungi descrizioni chiare alle mutations per facilitare la comprensione da parte degli sviluppatori che utilizzano la tua API.

"""
Crea un nuovo post associato a un autore esistente.
"""
type Mutation {
  createPost(title: String!, content: String!, authorId: ID!): Post!
}

5. Testare le Mutations

5.1. Test Manuale

Usa Apollo Studio Explorer o GraphQL Playground per testare manualmente le mutations. Assicurati di testare tutti i casi, inclusi i casi limite e le condizioni di errore.

5.2. Test Automatizzati

Scrivi test automatizzati per le mutations utilizzando framework come Jest o Mocha. Testa le operazioni con vari input e verifica che i risultati siano corretti.

Conclusione

Definire mutations in GraphQL è fondamentale per creare API potenti e flessibili che permettono ai client di interagire e modificare i dati nel sistema. Seguendo le best practices e implementando correttamente i resolvers, puoi garantire che le mutations siano sicure, efficienti e facili da mantenere. Con l’esperienza acquisita in questa guida, sei pronto a definire mutations che migliorano l’usabilità e la scalabilità della tua API GraphQL.