Italiano

Esplora le Route API di Next.js e sblocca le capacità di sviluppo full-stack nelle tue applicazioni React. Impara pattern, best practice e strategie di deployment.

Route API di Next.js: Pattern di Sviluppo Full-Stack

Next.js ha rivoluzionato lo sviluppo con React fornendo un framework robusto per creare applicazioni web performanti e scalabili. Una delle sue caratteristiche principali sono le Route API, che consentono agli sviluppatori di creare funzionalità di backend direttamente all'interno dei loro progetti Next.js. Questo approccio semplifica lo sviluppo, facilita il deployment e sblocca potenti capacità full-stack.

Cosa sono le Route API di Next.js?

Le Route API di Next.js sono funzioni serverless scritte direttamente nella tua directory /pages/api. Ogni file in questa directory diventa un endpoint API, instradando automaticamente le richieste HTTP alla sua funzione corrispondente. Ciò elimina la necessità di un server backend separato, semplificando l'architettura della tua applicazione e riducendo l'overhead operativo.

Pensa a loro come a funzioni serverless in miniatura che vivono all'interno della tua app Next.js. Rispondono a richieste HTTP come GET, POST, PUT, DELETE e possono interagire con database, API esterne e altre risorse lato server. Fondamentalmente, vengono eseguite solo sul server, non nel browser dell'utente, garantendo la sicurezza di dati sensibili come le chiavi API.

Vantaggi Chiave delle Route API

Iniziare con le Route API

Creare una route API in Next.js è semplice. Basta creare un nuovo file all'interno della directory /pages/api. Il nome del file determinerà il percorso della route. Ad esempio, la creazione di un file chiamato /pages/api/hello.js creerà un endpoint API accessibile a /api/hello.

Esempio: Una Semplice API di Saluto

Ecco un esempio di base di una route API che restituisce una risposta JSON:


// pages/api/hello.js

export default function handler(req, res) {
  res.status(200).json({ message: 'Ciao dalla Route API di Next.js!' });
}

Questo codice definisce una funzione asincrona handler che riceve due argomenti:

La funzione imposta il codice di stato HTTP a 200 (OK) e restituisce una risposta JSON con un messaggio.

Gestire Diversi Metodi HTTP

Puoi gestire diversi metodi HTTP (GET, POST, PUT, DELETE, ecc.) all'interno della tua route API controllando la proprietà req.method. Questo ti permette di creare API RESTful con facilità.


// pages/api/todos.js

export default async function handler(req, res) {
  if (req.method === 'GET') {
    // Recupera tutti i todo dal database
    const todos = await fetchTodos();
    res.status(200).json(todos);
  } else if (req.method === 'POST') {
    // Crea un nuovo todo
    const newTodo = await createTodo(req.body);
    res.status(201).json(newTodo);
  } else {
    // Gestisci i metodi non supportati
    res.status(405).json({ message: 'Metodo non consentito' });
  }
}

Questo esempio dimostra come gestire le richieste GET e POST per un ipotetico endpoint /api/todos. Include anche la gestione degli errori per i metodi non supportati.

Pattern di Sviluppo Full-Stack con le Route API

Le Route API di Next.js abilitano vari pattern di sviluppo full-stack. Ecco alcuni casi d'uso comuni:

1. Recupero e Manipolazione dei Dati

Le Route API possono essere utilizzate per recuperare dati da database, API esterne o altre fonti di dati. Possono anche essere utilizzate per manipolare dati, come creare, aggiornare o eliminare record.

Esempio: Recupero Dati Utente da un Database


// pages/api/users/[id].js
import { query } from '../../../lib/db';

export default async function handler(req, res) {
  const { id } = req.query;

  try {
    const results = await query(
      'SELECT * FROM users WHERE id = ?',
      [id]
    );

    if (results.length === 0) {
      return res.status(404).json({ message: 'Utente non trovato' });
    }

    res.status(200).json(results[0]);
  } catch (error) {
    console.error(error);
    res.status(500).json({ message: 'Errore interno del server' });
  }
}

Questo esempio recupera i dati di un utente da un database in base all'ID utente fornito nell'URL. Utilizza una libreria per le query al database (presumibilmente in lib/db) per interagire con il database. Nota l'uso di query parametrizzate per prevenire vulnerabilità di SQL injection.

2. Autenticazione e Autorizzazione

Le Route API possono essere utilizzate per implementare logiche di autenticazione e autorizzazione. Puoi usarle per verificare le credenziali dell'utente, generare token JWT e proteggere risorse sensibili.

Esempio: Autenticazione Utente


// pages/api/login.js
import bcrypt from 'bcryptjs';
import jwt from 'jsonwebtoken';
import { query } from '../../lib/db';

export default async function handler(req, res) {
  if (req.method === 'POST') {
    const { email, password } = req.body;

    try {
      const results = await query(
        'SELECT * FROM users WHERE email = ?',
        [email]
      );

      if (results.length === 0) {
        return res.status(401).json({ message: 'Credenziali non valide' });
      }

      const user = results[0];

      const passwordMatch = await bcrypt.compare(password, user.password);

      if (!passwordMatch) {
        return res.status(401).json({ message: 'Credenziali non valide' });
      }

      const token = jwt.sign(
        { userId: user.id, email: user.email },
        process.env.JWT_SECRET,
        { expiresIn: '1h' }
      );

      res.status(200).json({ token });
    } catch (error) {
      console.error(error);
      res.status(500).json({ message: 'Errore interno del server' });
    }
  } else {
    res.status(405).json({ message: 'Metodo non consentito' });
  }
}

Questo esempio autentica gli utenti confrontando la password fornita con la password hashata salvata nel database. Se le credenziali sono valide, genera un token JWT e lo restituisce al client. Il client può quindi utilizzare questo token per autenticare le richieste successive.

3. Gestione dei Moduli e Invio Dati

Le Route API possono essere utilizzate per gestire l'invio di moduli e processare i dati inviati dal client. Questo è utile per creare moduli di contatto, moduli di registrazione e altri elementi interattivi.

Esempio: Invio Modulo di Contatto


// pages/api/contact.js
import { sendEmail } from '../../lib/email';

export default async function handler(req, res) {
  if (req.method === 'POST') {
    const { name, email, message } = req.body;

    try {
      await sendEmail({
        to: 'admin@example.com',
        subject: 'Nuovo invio dal modulo di contatto',
        text: `Nome: ${name}\nEmail: ${email}\nMessaggio: ${message}`,
      });

      res.status(200).json({ message: 'Email inviata con successo' });
    } catch (error) {
      console.error(error);
      res.status(500).json({ message: 'Invio email fallito' });
    }
  } else {
    res.status(405).json({ message: 'Metodo non consentito' });
  }
}

Questo esempio gestisce l'invio di un modulo di contatto inviando un'email all'amministratore. Utilizza una libreria per l'invio di email (presumibilmente in lib/email) per inviare l'email. Dovresti sostituire admin@example.com con l'indirizzo email del destinatario effettivo.

4. Webhook e Gestione degli Eventi

Le Route API possono essere utilizzate per gestire i webhook e rispondere a eventi da servizi esterni. Questo ti consente di integrare la tua applicazione Next.js con altre piattaforme e automatizzare le attività.

Esempio: Gestire un Webhook di Stripe


// pages/api/stripe-webhook.js
import Stripe from 'stripe';

const stripe = new Stripe(process.env.STRIPE_SECRET_KEY);

export const config = {
  api: {
    bodyParser: false, // Disabilita il parsing del corpo predefinito
  },
};

async function buffer(req) {
  const chunks = [];
  for await (const chunk of req) {
    chunks.push(chunk);
  }
  return Buffer.concat(chunks).toString();
}

export default async function handler(req, res) {
  if (req.method === 'POST') {
    const sig = req.headers['stripe-signature'];

    let event;

    try {
      const buf = await buffer(req);
      event = stripe.webhooks.constructEvent(buf, sig, process.env.STRIPE_WEBHOOK_SECRET);
    } catch (err) {
      console.log(`Errore Webhook: ${err.message}`);
      res.status(400).send(`Errore Webhook: ${err.message}`);
      return;
    }

    // Gestisci l'evento
    switch (event.type) {
      case 'payment_intent.succeeded':
        const paymentIntent = event.data.object;
        console.log(`PaymentIntent per ${paymentIntent.amount} riuscito!`);
        // Quindi definisci e chiama un metodo per gestire l'intento di pagamento riuscito.
        // handlePaymentIntentSucceeded(paymentIntent);
        break;
      case 'payment_method.attached':
        const paymentMethod = event.data.object;
        // Quindi definisci e chiama un metodo per gestire l'allegato riuscito di un PaymentMethod.
        // handlePaymentMethodAttached(paymentMethod);
        break;
      default:
        // Tipo di evento inaspettato
        console.log(`Tipo di evento non gestito ${event.type}.`);
    }

    // Restituisci una risposta 200 per confermare la ricezione dell'evento
    res.status(200).json({ received: true });
  } else {
    res.setHeader('Allow', 'POST');
    res.status(405).end('Metodo non consentito');
  }
}

Questo esempio gestisce un webhook di Stripe verificando la firma ed elaborando i dati dell'evento. Disabilita il parser del corpo predefinito e utilizza una funzione buffer personalizzata per leggere il corpo grezzo della richiesta. È fondamentale disabilitare il parser del corpo predefinito perché Stripe richiede il corpo grezzo per la verifica della firma. Ricorda di configurare il tuo endpoint webhook di Stripe nella tua dashboard Stripe e di impostare la variabile d'ambiente STRIPE_WEBHOOK_SECRET.

Best Practice per le Route API

Per garantire la qualità e la manutenibilità delle tue Route API, segui queste best practice:

1. Modularizza il Tuo Codice

Evita di scrivere route API grandi e monolitiche. Invece, suddividi il tuo codice in moduli più piccoli e riutilizzabili. Questo rende il tuo codice più facile da capire, testare e mantenere.

2. Implementa la Gestione degli Errori

Gestisci correttamente gli errori nelle tue route API. Usa blocchi try...catch per catturare le eccezioni e restituire risposte di errore appropriate al client. Registra gli errori per aiutare nel debug e nel monitoraggio.

3. Valida i Dati di Input

Valida sempre i dati di input provenienti dal client per prevenire vulnerabilità di sicurezza e garantire l'integrità dei dati. Usa librerie di validazione come Joi o Yup per definire schemi di validazione e applicare vincoli sui dati.

4. Proteggi i Dati Sensibili

Salva i dati sensibili, come chiavi API e credenziali del database, in variabili d'ambiente. Non committare mai dati sensibili nel tuo repository di codice.

5. Implementa il Rate Limiting

Proteggi le tue route API dagli abusi implementando il rate limiting. Questo limita il numero di richieste che un client può fare in un dato periodo di tempo. Usa librerie di rate limiting come express-rate-limit o limiter.

6. Rendi Sicure le Chiavi API

Non esporre le chiavi API direttamente nel codice lato client. Usa sempre le tue route API come proxy per le richieste per proteggere le tue chiavi API da accessi non autorizzati. Conserva le chiavi API in modo sicuro nelle variabili d'ambiente sul tuo server.

7. Utilizza le Variabili d'Ambiente

Evita di inserire valori di configurazione direttamente nel codice. Invece, utilizza le variabili d'ambiente per memorizzare le impostazioni di configurazione. Questo rende più facile gestire la tua applicazione in ambienti diversi (sviluppo, staging, produzione).

8. Logging e Monitoraggio

Implementa logging e monitoraggio per tracciare le prestazioni delle tue route API. Registra eventi importanti, come errori, avvisi e richieste riuscite. Usa strumenti di monitoraggio per tracciare metriche come la latenza delle richieste, i tassi di errore e l'utilizzo delle risorse. Servizi come Sentry, Datadog o New Relic possono essere utili.

Considerazioni sul Deployment

Le Route API di Next.js sono progettate per essere distribuite su piattaforme serverless. Le opzioni di deployment più popolari includono:

Quando effettui il deployment della tua applicazione Next.js con Route API, assicurati che le tue variabili d'ambiente siano configurate correttamente sulla piattaforma di deployment. Inoltre, considera il tempo di avvio a freddo (cold start) delle funzioni serverless, che può influire sul tempo di risposta iniziale delle tue route API. Ottimizzare il codice e utilizzare tecniche come la concorrenza predisposta (provisioned concurrency) può aiutare a mitigare i problemi di cold start.

Conclusione

Le Route API di Next.js offrono un modo potente e comodo per creare applicazioni full-stack con React. Sfruttando le funzioni serverless, puoi semplificare lo sviluppo, ridurre l'overhead operativo e migliorare le prestazioni dell'applicazione. Seguendo le best practice delineate in questo articolo, puoi creare Route API robuste e manutenibili che alimentano le tue applicazioni Next.js.

Sia che tu stia costruendo un semplice modulo di contatto o una complessa piattaforma di e-commerce, le Route API di Next.js possono aiutarti a ottimizzare il tuo processo di sviluppo e a offrire esperienze utente eccezionali.

Approfondimenti