Creare un Endpoint RESTful per la Ricerca e il Filtraggio dei Dati in PHP

by theArchitect
SHARE
Creare un Endpoint RESTful per la Ricerca e il Filtraggio dei Dati in PHP
© Guida-HTML5.it

Introduzione

Quando si sviluppa una API RESTful in PHP, uno degli aspetti più utili e richiesti è la possibilità di cercare e filtrare i dati in modo efficiente. Questo tipo di endpoint è fondamentale in applicazioni reali come cataloghi prodotti, dashboard amministrative, sistemi di ticketing, archivi documentali o gestionali interni.

Un endpoint di ricerca ben progettato permette al client di inviare parametri come query testuale, categoria, stato, intervallo di date o ordinamento, ottenendo solo i dati realmente necessari. Questo migliora sia l’esperienza utente sia le prestazioni del sistema, perché evita di scaricare insiemi di dati troppo grandi.

In questo tutorial vedremo come costruire in PHP un endpoint RESTful che supporta:

  • ricerca per testo libero
  • filtri multipli tramite query string
  • ordinamento dei risultati
  • protezione di base contro SQL injection con PDO e query preparate
  • risposta JSON pulita e coerente

L’esempio sarà semplice ma realistico: un endpoint GET /api/tickets per cercare ticket di assistenza in un database.

Codice completo

<?php
declare(strict_types=1);

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

try {
    // Connessione al database
    $pdo = new PDO(
        ´mysql:host=localhost;dbname=helpdesk;charset=utf8mb4´,
        ´root´,
        ´´,
        [
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        ]
    );

    // Lettura dei parametri dalla query string
    $search   = trim($_GET[´search´] ?? ´´);
    $status   = trim($_GET[´status´] ?? ´´);
    $priority = trim($_GET[´priority´] ?? ´´);
    $from     = trim($_GET[´from´] ?? ´´);
    $to       = trim($_GET[´to´] ?? ´´);
    $sort     = trim($_GET[´sort´] ?? ´created_at´);
    $order    = strtoupper(trim($_GET[´order´] ?? ´DESC´));

    // Validazione sort e order per evitare valori non ammessi
    $allowedSortFields = [´created_at´, ´updated_at´, ´priority´, ´status´];
    if (!in_array($sort, $allowedSortFields, true)) {
        $sort = ´created_at´;
    }

    if (!in_array($order, [´ASC´, ´DESC´], true)) {
        $order = ´DESC´;
    }

    // Costruzione dinamica della query
    $sql = "SELECT id, title, status, priority, created_at, updated_at
            FROM tickets
            WHERE 1=1";

    $params = [];

    if ($search !== ´´) {
        $sql .= " AND (title LIKE :search OR description LIKE :search)";
        $params[´:search´] = ´%´ . $search . ´%´;
    }

    if ($status !== ´´) {
        $sql .= " AND status = :status";
        $params[´:status´] = $status;
    }

    if ($priority !== ´´) {
        $sql .= " AND priority = :priority";
        $params[´:priority´] = $priority;
    }

    if ($from !== ´´) {
        $sql .= " AND created_at >= :from_date";
        $params[´:from_date´] = $from . ´ 00:00:00´;
    }

    if ($to !== ´´) {
        $sql .= " AND created_at <= :to_date";
        $params[´:to_date´] = $to . ´ 23:59:59´;
    }

    $sql .= " ORDER BY {$sort} {$order}";

    $stmt = $pdo->prepare($sql);
    $stmt->execute($params);

    $tickets = $stmt->fetchAll();

    echo json_encode([
        ´success´ => true,
        ´count´ => count($tickets),
        ´data´ => $tickets
    ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);

} catch (Throwable $e) {
    http_response_code(500);

    echo json_encode([
        ´success´ => false,
        ´error´ => ´Errore interno del server´
    ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
}

Spiegazione

Il codice sopra implementa un endpoint GET che restituisce ticket filtrati in base ai parametri passati nella query string. Vediamo i punti principali.

1. Connessione al database con PDO

Usiamo PDO perché offre un accesso sicuro e flessibile al database. Impostare PDO::ATTR_ERRMODE su PDO::ERRMODE_EXCEPTION ci permette di intercettare gli errori tramite eccezioni, mentre PDO::ATTR_DEFAULT_FETCH_MODE impostato su FETCH_ASSOC restituisce array associativi più comodi da serializzare in JSON.

2. Lettura dei parametri di ricerca

I parametri vengono letti con $_GET, perché in una REST API i filtri e i criteri di ricerca sono tipicamente passati nella query string. Ad esempio:

  • /api/tickets?search=login
  • /api/tickets?status=open&priority=high
  • /api/tickets?from=2026-01-01&to=2026-01-31

Ogni valore viene ripulito con trim() per eliminare spazi inutili.

3. Validazione di ordinamento e direzione

Il campo di ordinamento non può essere passato direttamente in una query preparata, quindi va validato in modo esplicito. Per questo usiamo una lista di campi consentiti:

  • created_at
  • updated_at
  • priority
  • status

Lo stesso vale per ASC e DESC. Se il valore non è valido, usiamo un default sicuro.

4. Costruzione dinamica della query

La query parte da WHERE 1=1, una tecnica semplice che semplifica l’aggiunta condizionale di ulteriori filtri con AND. In questo modo possiamo concatenare i criteri solo quando sono presenti.

Per i valori testuali e date usiamo query preparate con parametri nominati, ad esempio :search o :status. Questo protegge da SQL injection e separa chiaramente struttura della query e dati.

5. Risposta JSON coerente

La risposta restituisce un oggetto JSON con tre proprietà:

  • success: indica se l’operazione è andata a buon fine
  • count: numero di record trovati
  • data: elenco dei ticket

In caso di errore, il server risponde con codice HTTP 500 e un messaggio generico. In produzione è meglio non esporre dettagli tecnici sensibili al client.

Best practice

Un endpoint di ricerca e filtraggio è molto utile, ma va progettato con attenzione. Ecco alcune best practice da seguire.

  • Usa sempre query preparate per i valori dinamici, specialmente quando provengono dall’utente.
  • Valida i campi di ordinamento con una whitelist, non con input libero.
  • Limita il numero di risultati con paginazione, soprattutto se il dataset può crescere molto.
  • Normalizza i parametri prima di usarli: trim, cast, controllo formato date.
  • Restituisci risposte coerenti con struttura JSON stabile, utile per il frontend o per altri servizi.
  • Documenta i filtri disponibili per rendere l’API facile da integrare.
  • Evita filtri troppo costosi se non hai indici adeguati nel database.

Dal punto di vista delle prestazioni, è importante creare indici sulle colonne usate più spesso nei filtri, come status, priority e created_at. Senza indici, una ricerca su tabelle grandi può diventare lenta.

Un altro aspetto utile è separare la logica di accesso ai dati in una classe o repository. Nel codice di esempio tutto è in un unico file per semplicità didattica, ma in un progetto reale conviene organizzare meglio il codice.

Riepilogo

In questo tutorial abbiamo visto come creare in PHP un endpoint RESTful dedicato alla ricerca e al filtraggio dei dati. L’esempio ha mostrato come:

  • leggere parametri dalla query string
  • costruire una query SQL dinamica in modo sicuro
  • usare PDO e query preparate
  • validare ordinamento e direzione
  • restituire una risposta JSON pulita

Questa tecnica è molto comune nelle API moderne e rappresenta una base solida per costruire endpoint più avanzati, ad esempio con paginazione, filtri combinati, ricerca full-text o integrazione con framework come Laravel o Symfony.

Approfondisci con risorse ufficiali

  • PHP Manual - PDO: https://www.php.net/manual/it/book.pdo.php
  • PHP Manual - json_encode: https://www.php.net/manual/it/function.json-encode.php
  • PHP Manual - $_GET: https://www.php.net/manual/it/reserved.variables.get.php
  • MySQL Reference - Indexes: https://dev.mysql.com/doc/refman/8.0/en/mysql-indexes.html
  • MDN - HTTP Methods: https://developer.mozilla.org/it/docs/Web/HTTP/Methods

SHARE