PHP e API RESTful: gestire gli errori con risposte JSON coerenti

by theArchitect
SHARE
PHP e API RESTful: gestire gli errori con risposte JSON coerenti
© Guida-HTML5.it

Introduzione

Quando si sviluppa un’API RESTful in PHP, non basta restituire dati corretti: è fondamentale gestire gli errori in modo chiaro, prevedibile e coerente. Un client frontend, un’app mobile o un altro servizio backend devono poter capire subito cosa è andato storto, senza dover interpretare messaggi vaghi o pagine HTML di errore.

Un sotto-argomento molto utile, spesso sottovalutato, è proprio la gestione centralizzata degli errori con risposte JSON standardizzate. Questo approccio migliora la qualità dell’API, semplifica il debug e rende il codice più manutenibile. In questo tutorial vedremo come costruire una piccola API RESTful in PHP che espone un endpoint per ottenere un ordine e, in caso di problemi, restituisce risposte JSON coerenti con codici HTTP corretti.

L’obiettivo non è solo mostrare un esempio funzionante, ma anche evidenziare una buona pratica fondamentale: ogni errore deve avere una struttura prevedibile, così il client può gestirlo facilmente.

Codice completo

<?php
declare(strict_types=1);

/**
 * Esempio di API RESTful in PHP con gestione centralizzata degli errori.
 * Endpoint:
 *   GET /api/orders.php?id=123
 *
 * Risposte:
 *   - 200 OK con ordine trovato
 *   - 400 Bad Request se l´id è mancante o non valido
 *   - 404 Not Found se l´ordine non esiste
 *   - 500 Internal Server Error per errori inattesi
 */

header(´Content-Type: application/json; charset=utf-8´);

/**
 * In un progetto reale questi dati arriverebbero da un database.
 * Qui usiamo un array per semplificare l´esempio.
 */
$orders = [
    101 => [
        ´id´ => 101,
        ´customer´ => ´Mario Rossi´,
        ´status´ => ´pending´,
        ´total´ => 49.90
    ],
    102 => [
        ´id´ => 102,
        ´customer´ => ´Giulia Bianchi´,
        ´status´ => ´shipped´,
        ´total´ => 89.50
    ]
];

/**
 * Funzione per inviare una risposta JSON standard.
 */
function jsonResponse(array $data, int $statusCode = 200): void
{
    http_response_code($statusCode);
    echo json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
    exit;
}

/**
 * Funzione per inviare un errore in formato JSON.
 * Mantiene una struttura coerente in tutta l´API.
 */
function jsonError(string $message, int $statusCode, ?array $details = null): void
{
    $payload = [
        ´success´ => false,
        ´error´ => [
            ´message´ => $message,
            ´code´ => $statusCode
        ]
    ];

    if ($details !== null) {
        $payload[´error´][´details´] = $details;
    }

    jsonResponse($payload, $statusCode);
}

/**
 * In un´API RESTful, è importante verificare il metodo HTTP.
 * Questo endpoint accetta solo GET.
 */
if ($_SERVER[´REQUEST_METHOD´] !== ´GET´) {
    jsonError(´Metodo non consentito. Usa GET.´, 405);
}

/**
 * Recupero e validazione dell´ID.
 * filter_input aiuta a evitare input non validi.
 */
$orderId = filter_input(INPUT_GET, ´id´, FILTER_VALIDATE_INT);

if ($orderId === null || $orderId === false) {
    jsonError(
        ´Parametro "id" mancante o non valido.´,
        400,
        [´id´ => ´Deve essere un intero positivo.´]
    );
}

if ($orderId <= 0) {
    jsonError(
        ´Parametro "id" non valido.´,
        400,
        [´id´ => ´L´identificativo deve essere maggiore di zero.´]
    );
}

/**
 * Simuliamo la ricerca dell´ordine.
 * In un caso reale si userebbe una query SQL con prepared statement.
 */
if (!isset($orders[$orderId])) {
    jsonError(
        ´Ordine non trovato.´,
        404,
        [´id´ => $orderId]
    );
}

/**
 * Risposta positiva.
 */
jsonResponse([
    ´success´ => true,
    ´data´ => $orders[$orderId]
], 200);

Spiegazione

Vediamo il codice passo per passo. La prima cosa importante è l’header:

Content-Type: application/json; charset=utf-8. Questo comunica al client che la risposta è JSON e non HTML. In un’API RESTful è un dettaglio essenziale, perché evita ambiguità e problemi di parsing.

1. Risposta standardizzata

La funzione jsonResponse() centralizza l’invio delle risposte. Riceve un array PHP, imposta il codice HTTP e lo converte in JSON. Questo riduce la duplicazione del codice e rende più semplice mantenere uno stile uniforme in tutta l’API.

2. Gestione degli errori

La funzione jsonError() costruisce una struttura coerente per gli errori:

  • success: sempre false nei casi di errore
  • error.message: messaggio leggibile per il client
  • error.code: codice HTTP restituito
  • error.details: informazioni aggiuntive facoltative

Questa struttura è utile perché il frontend non deve interpretare formati diversi per ogni errore. Può invece controllare sempre gli stessi campi.

3. Controllo del metodo HTTP

L’endpoint accetta solo richieste GET. Se arriva un altro metodo, come POST o DELETE, restituiamo un errore 405 Method Not Allowed. Questo è un comportamento corretto in una REST API, perché ogni endpoint dovrebbe rispettare il proprio contratto.

4. Validazione dell’input

Il parametro id viene letto con filter_input() e validato come intero. Questo è meglio rispetto a usare direttamente $_GET[´id´], perché introduce un primo livello di controllo. Se il parametro è mancante o non valido, l’API risponde con 400 Bad Request.

La validazione è fondamentale: un’API robusta non deve fidarsi dell’input del client.

5. Risorsa non trovata

Se l’ordine non esiste, il server restituisce 404 Not Found. Anche questo è importante dal punto di vista REST: il codice HTTP deve descrivere correttamente la situazione. Non bisogna usare 200 con un messaggio di errore nel payload, perché sarebbe fuorviante.

6. Risposta positiva

Se tutto va bene, l’API restituisce success: true e i dati dell’ordine dentro data. Questo schema è semplice, leggibile e adatto a molti frontend moderni.

Best practice

La gestione degli errori nelle API RESTful non dovrebbe essere improvvisata. Ecco alcune buone pratiche da applicare in progetti reali:

  • Usa sempre codici HTTP corretti: 200, 400, 401, 403, 404, 405, 422, 500.
  • Restituisci JSON anche negli errori: evita pagine HTML di default del server.
  • Definisci una struttura fissa per le risposte, sia positive sia negative.
  • Non esporre dettagli sensibili negli errori interni, come query SQL o stack trace.
  • Valida sempre gli input prima di usarli in query o logica applicativa.
  • Usa prepared statement quando accedi al database, per prevenire SQL injection.
  • Centralizza la gestione degli errori in funzioni o classi dedicate, invece di ripetere codice in ogni endpoint.

Un altro consiglio utile è quello di distinguere tra errori di validazione e errori di sistema. Per esempio, un campo obbligatorio mancante può generare un 400 o un 422 Unprocessable Entity, mentre un problema di connessione al database deve diventare un 500 Internal Server Error.

Se il progetto cresce, conviene creare una piccola classe ApiResponse o un middleware per uniformare tutte le risposte. Questo rende il codice più pulito e più facile da testare.

Riepilogo

In questo tutorial abbiamo visto come gestire gli errori in una API RESTful PHP con risposte JSON coerenti. Abbiamo costruito un endpoint semplice per recuperare un ordine e abbiamo imparato a:

  • impostare correttamente l’header JSON;
  • centralizzare la generazione delle risposte;
  • restituire errori con codici HTTP appropriati;
  • validare gli input in modo sicuro;
  • mantenere una struttura uniforme per client e frontend.

Questo approccio è molto più professionale rispetto a restituire messaggi testuali casuali. Una buona API non è solo funzionale: è anche prevedibile, chiara e facile da integrare.

Approfondisci con risorse ufficiali

  • PHP Manual - header(): documentazione ufficiale per inviare header HTTP.
  • PHP Manual - http_response_code(): per impostare il codice di stato HTTP.
  • PHP Manual - json_encode(): conversione di array e oggetti in JSON.
  • PHP Manual - filter_input(): validazione sicura degli input.
  • MDN Web Docs - HTTP response status codes: panoramica completa sui codici HTTP.
  • RFC 9110: specifica ufficiale del protocollo HTTP semantico.

SHARE