🚀 Nuova versione beta disponibile! Feedback o problemi? Contattaci

Integrazione di Database Relazionali in un'API GraphQL con Apollo Server

Codegrind Team•Sep 03 2024

Integrare un database relazionale, come PostgreSQL o MySQL, in un’API GraphQL con Apollo Server consente di sfruttare la potenza dei database relazionali per gestire dati strutturati in modo efficiente. In questa guida, ti mostrerò come configurare e utilizzare un database relazionale con Apollo Server, utilizzando un ORM (Object-Relational Mapper) come TypeORM o Sequelize per interagire con il database in modo semplice e tipizzato.

Prerequisiti

Prima di iniziare, assicurati di avere:

  • Node.js installato
  • Un’istanza di PostgreSQL o MySQL in esecuzione (localmente o in cloud)
  • Conoscenza di base di GraphQL e Apollo Server

Step 1: Creazione del Progetto e Installazione delle Dipendenze

Inizia 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 typeorm reflect-metadata pg
  • apollo-server: La libreria per configurare il server GraphQL.
  • graphql: La libreria per definire e utilizzare GraphQL.
  • typeorm: Un ORM che semplifica l’interazione con database relazionali.
  • reflect-metadata: Necessario per la decorazione e la gestione delle classi con TypeORM.
  • pg: Il client Node.js per PostgreSQL (per MySQL, sostituisci con mysql2).

Step 2: Configurazione di TypeORM con PostgreSQL

Configurazione del Database

Crea un file ormconfig.json nella radice del progetto per configurare TypeORM:

{
  "type": "postgres",
  "host": "localhost",
  "port": 5432,
  "username": "your-username",
  "password": "your-password",
  "database": "your-database",
  "synchronize": true,
  "logging": true,
  "entities": ["src/entity/**/*.ts"]
}

Sostituisci i valori di username, password, e database con le tue credenziali e il nome del database.

Definizione di un’Entità

Le entità in TypeORM rappresentano le tabelle del database. Crea una directory src/entity e un file User.ts per definire l’entità User:

import { Entity, PrimaryGeneratedColumn, Column } from "typeorm";

@Entity()
export class User {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  name: string;

  @Column()
  email: string;
}

Questa entitĂ  User rappresenta una tabella nel database con tre colonne: id, name, e email.

Step 3: Configurazione di Apollo Server con GraphQL

Crea il file src/index.ts per configurare Apollo Server:

import "reflect-metadata";
import { ApolloServer, gql } from "apollo-server";
import { createConnection } from "typeorm";
import { User } from "./entity/User";

createConnection()
  .then(async (connection) => {
    // Definisci lo schema GraphQL
    const typeDefs = gql`
      type User {
        id: ID!
        name: String!
        email: String!
      }

      type Query {
        users: [User]
        user(id: ID!): User
      }

      type Mutation {
        createUser(name: String!, email: String!): User
        updateUser(id: ID!, name: String, email: String): User
        deleteUser(id: ID!): Boolean
      }
    `;

    // Definisci i resolver
    const resolvers = {
      Query: {
        users: async () => {
          return await connection.getRepository(User).find();
        },
        user: async (_: any, { id }: { id: number }) => {
          return await connection.getRepository(User).findOne(id);
        },
      },
      Mutation: {
        createUser: async (
          _: any,
          { name, email }: { name: string; email: string }
        ) => {
          const user = new User();
          user.name = name;
          user.email = email;
          return await connection.getRepository(User).save(user);
        },
        updateUser: async (
          _: any,
          { id, name, email }: { id: number; name?: string; email?: string }
        ) => {
          const user = await connection.getRepository(User).findOne(id);
          if (!user) throw new Error("User not found");
          if (name) user.name = name;
          if (email) user.email = email;
          return await connection.getRepository(User).save(user);
        },
        deleteUser: async (_: any, { id }: { id: number }) => {
          const result = await connection.getRepository(User).delete(id);
          return result.affected === 1;
        },
      },
    };

    // Configura Apollo Server
    const server = new ApolloServer({
      typeDefs,
      resolvers,
    });

    // Avvia il server
    server.listen().then(({ url }) => {
      console.log(`🚀 Server ready at ${url}`);
    });
  })
  .catch((error) => console.log(error));

Spiegazione del Codice

  • Schema GraphQL: Definiamo un tipo User, query per ottenere utenti (users, user), e mutazioni per creare, aggiornare e cancellare utenti (createUser, updateUser, deleteUser).
  • Resolvers: I resolver gestiscono l’interazione con PostgreSQL utilizzando TypeORM per eseguire operazioni CRUD (Create, Read, Update, Delete).

Step 4: Compilazione ed Esecuzione

Assicurati che TypeScript sia installato nel progetto:

npm install typescript ts-node @types/node --save-dev

Aggiungi uno script di avvio al package.json:

"scripts": {
  "start": "ts-node src/index.ts"
}

Esegui il server:

npm start

Il server Apollo sarà avviato e collegato al database PostgreSQL. Puoi accedere a GraphQL Playground all’indirizzo http://localhost:4000/.

Step 5: Test dell’API GraphQL

Esempio di Query per Ottenere Tutti gli Utenti

query {
  users {
    id
    name
    email
  }
}

Esempio di Mutazione per Creare un Nuovo Utente

mutation {
  createUser(name: "Alice", email: "alice@example.com") {
    id
    name
    email
  }
}

Esempio di Mutazione per Aggiornare un Utente

mutation {
  updateUser(id: 1, name: "Alice Updated", email: "alice.new@example.com") {
    id
    name
    email
  }
}

Esempio di Mutazione per Eliminare un Utente

mutation {
  deleteUser(id: 1)
}

Step 6: Best Practices

  1. Gestione degli Errori: Implementa una gestione robusta degli errori nei resolver per gestire eventuali problemi durante le operazioni con il database.
  2. Migrazioni: Usa il sistema di migrazioni di TypeORM per gestire i cambiamenti allo schema del database in modo sicuro e controllato.
  3. Validazione dei Dati: Utilizza decoratori TypeORM come @IsEmail, @Length, ecc., per convalidare i dati prima di salvarli nel database.
  4. Sicurezza: Proteggi le mutazioni sensibili implementando l’autenticazione e l’autorizzazione, specialmente per operazioni come la creazione e la cancellazione di record.

Conclusione

Integrare un database relazionale come PostgreSQL o MySQL in un’API GraphQL con Apollo Server è un processo potente e flessibile. Utilizzando TypeORM, puoi interagire con il database in modo semplice e tipizzato, semplificando le operazioni CRUD e migliorando la manutenibilità del codice. Questa configurazione ti permette di creare API scalabili e sicure, adatte a qualsiasi tipo di applicazione.