Brook Preloader

Costruire una Semplice API per una Lista della Spesa con Express e MySQL

Ciao a tutti, appassionati di codice! Oggi voglio guidarvi attraverso un interessante progettino su cui ho lavorato: un’API per una Lista della Spesa realizzata con Express.js e MySQL.

Che tu sia uno sviluppatore esperto o un principiante alle prime armi, questo progetto offre spunti interessanti sulla semplicità e potenza dell’uso di Express accanto a un database MySQL.

Da dove partiamo: Express.js

Express è un framework web minimale e flessibile per Node.js, che offre un solido set di funzionalità (sarebbe troppo chiamarlo Framework) per applicazioni web e mobile. Uno dei suoi punti di forza è la semplicità nella creazione di API.

Configurazione e Dipendenze:

All’inizio del nostro codice, importiamo le librerie necessarie:

const express = require('express');
const bodyParser = require('body-parser');
const cors = require('cors');
const mysql = require('mysql');
const dotenv = require('dotenv');

Ecco una breve descrizione:

  • express: Il framework principale.
  • body-parser: Middleware per gestire i dati POST.
  • cors: Middleware per abilitare la condivisione di risorse tra origini diverse, essenziale per molte applicazioni web.
  • mysql: Driver Node.js per MySQL.
  • dotenv: Per caricare le variabili di ambiente da un file .env.

Configurare l’Ambiente:

Utilizzando dotenv, possiamo facilmente configurare le variabili di ambiente:

dotenv.config();

Questa linea carica le variabili da un file .env, che potrebbe apparire così:

DB_HOST=tuo_host_database
DB_USER=tuo_utente_database
DB_PASSWORD=tua_password_database
DB_NAME=nome_tuo_database

Configurazione di Express:

La configurazione della nostra applicazione Express è di facile comprensione:

const app = express();
const port = 3000;

app.use(cors());
app.use(bodyParser.json());

Stiamo permettendo tutte le richieste CORS e analizzando i dati JSON in arrivo.

Inizializzazione del Database MySQL

MySQL è un affidabile e robusto sistema di database relazionali. Abbinarlo a Express è logico per molte applicazioni web. Ecco la configurazione del database:

const db = mysql.createConnection({
  host: process.env.DB_HOST,
  user: process.env.DB_USER,
  password: process.env.DB_PASSWORD,
  database: process.env.DB_NAME
});

Dopo aver stabilito i parametri di configurazione della connessione dobbiamo assicurarci che questa sia correttamente stabilita:

db.connect(err => {
    if (err) {
        console.error('Errore di connessione al database:', err);
    } else {
        console.log('Connessione al database stabilita');
    }
});

Lo SCHEMA del Database con DDL e DML (i dati di esempio)

La nostra API ruota attorno a una semplice tabella shopping_list, contenente un id, un item, e una quantity. Ecco la funzione che crea questa tabella se non esiste:

function createTableIfNotExists() {
    const createTableQuery = `
        CREATE TABLE IF NOT EXISTS shopping_list (
            id INT AUTO_INCREMENT PRIMARY KEY,
            item VARCHAR(255) NOT NULL,
            quantity INT
        )
    `;

    db.query(createTableQuery, (err, result) => {
        if (err) {
        console.error('Table creation error:', err);
        } else {
        console.log('Table creation successful');
        insertSampleData();
        }
    });
}

Una vota creata la tabella vengono inserite 4 righe di esempio:

function insertSampleData() {
    const sampleData = [
        { item: 'Eggs', quantity: 2 },
        { item: 'Bread', quantity: 1 },
        { item: 'Milk', quantity: 3 },
        { item: 'Cafe', quantity: 6 }
    ];

    const insertQuery = 'INSERT INTO shopping_list (item, quantity) VALUES ?';

    db.query(insertQuery, [sampleData.map(item => [item.item, item.quantity])], (err, result) => {
        if (err) {
          console.error('Error while inserting example data:', err);
        } else {
          console.log('Example data insertion success!');
        }
    });
}

Endpoint della API:

1. Recupero della Lista della Spesa:

app.get('/shopping-list', (req, res) => {
    db.query('SELECT * FROM shopping_list', (err, result) => {
        if (err) {
        console.error(err);
        res.status(500).send('Server error');
        } else {
        res.send(result);
        }
    });
});

Questo endpoint recupera tutta la lista della spesa restituendo un Array di oggetti JSON contenenti i dettagli dei singoli oggetti.

Un esempio di richiamo di questo endpoint potrebbe essere:

http://localhost:3000/shopping-list

2. Dettaglio di un Singolo Elemento della Lista:

// API to retrieve a single item from the shopping list
app.get('/shopping-list/:id', (req, res) => {
    const itemId = req.params.id;
    const query = 'SELECT * FROM shopping_list WHERE id = ?';
    db.query(query, [itemId], (err, result) => {
        if (err) {
            console.error(err);
            res.status(500).send('Server Error');
        } else {
            if (result.length > 0) {
                res.send(result[0]);
            } else {
                res.status(404).send('Item not found');
            }
        }
    });
});

Questo blocco di codice si occupa di recuperare un singolo oggetto all’interno del database utilizzando il suo “id”, un esempio di richiamo del end-point è questo:

http://localhost:3000/shopping-list/2

3. Eliminazione, Aggiornamento ed Inserimento

Per queste funzionalità avrete bisogno di un simulatore di richieste come “postman”, il codice non è direttamente accessibile dal browser perché quest’ultimo è in grado di effettuare solo delle chiamate GET.


// API for adding a new item to the shopping list
app.post('/shopping-list', (req, res) => {
    const { item, quantity } = req.body;
    const query = 'INSERT INTO shopping_list (item, quantity) VALUES (?, ?)';
    db.query(query, [item, quantity], (err, result) => {
        if (err) {
        console.error(err);
        res.status(500).send('Server error');
        } else {
        res.send('Item successfully added');
        }
    });
});
  
  // API for updating an item existing in the shopping list
app.put('/shopping-list/:id', (req, res) => {
    const itemId = req.params.id;
    const { item, quantity } = req.body;
    const query = 'UPDATE shopping_list SET item = ?, quantity = ? WHERE id = ?';
    db.query(query, [item, quantity, itemId], (err, result) => {
        if (err) {
        console.error(err);
        res.status(500).send('Server error');
        } else {
        res.send('Item successfully updated');
        }
    });
});
  
// API for deleting an element existing in the shopping list
app.delete('/shopping-list/:id', (req, res) => {
    const itemId = req.params.id;
    const query = 'DELETE FROM shopping_list WHERE id = ?';
    db.query(query, [itemId], (err, result) => {
        if (err) {
        console.error(err);
        res.status(500).send('Server error');
        } else {
        res.send('Item successfully deleted');
        }
    });
});

Avvio del server:

app.listen(port, () => {
  console.log(`Server in esecuzione sulla porta ${port}`);
});

In questo blocco di codice si richiede l’avvio del server sulla porta selezionata.