Torna al Blog

REST API Design: Le Best Practice che Nessuno Ti Ha Mai Insegnato

Le best practice per progettare REST API scalabili e manutenibili: naming conventions, versioning, error handling standardizzato, autenticazione e documentazione con OpenAPI/Swagger.

Introduzione: Progettare API è come Costruire Infrastrutture

Se progetti male una REST API, paga il prezzo per anni: clienti confusi, documentazione inesatta, versioning caotico. Ho visto aziende spendere migliaia di ore per aggiustare API progettate male.

Questo articolo condivide le 5 pilastri che ho utilizzato per progettare API che gestiscono milioni di richieste al giorno, mantenendo compatibilità retroattiva e documentazione sempre sincronizzata.

1. Naming Conventions: La Fondazione

La maggior parte degli sviluppatori sottovaluta i nomi. Ecco le regole che uso:

// ✓ CORRETTO: Nomi chiari e consistenti
GET /api/v1/users                    # Ottieni lista utenti
GET /api/v1/users/{id}               # Ottieni un utente
POST /api/v1/users                   # Crea nuovo utente
PUT /api/v1/users/{id}               # Aggiorna utente
DELETE /api/v1/users/{id}            # Elimina utente

// ✗ SBAGLIATO: Inconsistente e confuso
GET /api/getUsers                    # Mismatch con stile
GET /api/user/{id}                   # Singular vs plural
POST /api/create_user                # Ridondante (POST lo dice)
PATCH /api/v1/users/{id}             # Quando usare PATCH vs PUT?

Regola d'oro: Usa nomi al plurale per collezioni, singolare per istanze. Nomi descrivono RISORSA, non AZIONE.

2. HTTP Status Code: Risposte Corrette

Molte API restituiscono sempre 200 anche per errori. Questo causa problemi ai client intelligenti che si basano sui status code.

200 OK              → Richiesta riuscita
201 Created         → Risorsa creata (sempre con Location header)
204 No Content      → Richiesta riuscita ma nessun body
400 Bad Request     → Errore nel client (validazione fallita)
401 Unauthorized    → Autenticazione mancante
403 Forbidden       → Autenticato ma non autorizzato
404 Not Found       → Risorsa non esiste
409 Conflict        → Conflitto (es: duplicate unique key)
429 Too Many Requests → Rate limit exceeded
500 Internal Error   → Errore server (log sempre!)

3. Error Response Standardizzata (RFC 7807)

Ogni API dovrebbe rispondere con lo stesso formato di errore:

// Errore API standardizzato
{
  "type": "https://api.example.com/problems/validation-error",
  "title": "Validation Failed",
  "status": 400,
  "detail": "Email format is invalid",
  "instance": "/api/v1/users",
  "timestamp": "2026-06-07T10:00:00Z",
  "errors": [
    {
      "field": "email",
      "message": "Must be a valid email format",
      "value": "not-an-email"
    }
  ]
}

Questo formato permette a frontend e client di gestire errori in modo uniforme, non indovinando dalla response.

4. Versioning: URI vs Header

La scelta più dibattuta. Ecco il mio take:

// Opzione 1: URI versioning (consigliato per breaking changes)
GET /api/v1/users
GET /api/v2/users   # Nuovo schema

// Opzione 2: Header versioning (consigliato per minor changes)
GET /api/users
Accept: application/vnd.myapi.v2+json

// Evita: Query string versioning
GET /api/users?api_version=2    # Cattiva pratica
Consiglio

Usa URI versioning (v1, v2) solo quando hai breaking changes. Per aggiungere campi opzionali, basta aggiungere il campo senza cambiare versione. I vecchi client continueranno a funzionare.

5. Autenticazione: JWT, API Key, OAuth2

Ogni approccio ha pro e contro:

  • API Key: Semplice, perfetto per servizi server-to-server. NON usare per frontend pubblico.
  • JWT: Stateless, scalabile, perfetto per SPA. Ricorda: non è una soluzione di autenticazione, solo di autorizzazione.
  • OAuth2: Complesso ma necessario per delegare autenticazione a servizi terzi (Google, GitHub, etc).
// JWT: Access token breve + Refresh token lungo
POST /api/v1/auth/login
Request: { "email": "...", "password": "..." }
Response: {
  "access_token": "eyJ...",      // 15 min validity
  "refresh_token": "xyz...",      // 30 days validity
  "expires_in": 900
}

// Poi: Header Authorization per ogni richiesta
GET /api/v1/users
Authorization: Bearer eyJ...

6. Documentazione OpenAPI/Swagger

La documentazione è PARTE della API, non aggiunta dopo. Usa OpenAPI 3.0:

openapi: 3.0.0
info:
  title: User API
  version: 1.0.0
paths:
  /users:
    get:
      summary: List all users
      parameters:
        - name: limit
          in: query
          schema:
            type: integer
            default: 20
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/User'

Una volta scritto OpenAPI, genera documentazione interattiva con Swagger UI e client SDK automaticamente.

Checklist Final API Design

Checklist
  • ✓ Naming: Plurale per collezioni, singolare per istanze
  • ✓ Status code: 2xx per successo, 4xx per client error, 5xx per server error
  • ✓ Error response: RFC 7807 format per ogni errore
  • ✓ Versioning: URI v1/v2 solo con breaking changes
  • ✓ Autenticazione: JWT per frontend, API key per backend
  • ✓ Documentazione: OpenAPI 3.0 sempre sincronizzata

Conclusione

Una API ben progettata non è solo codice: è contratto tra cliente e server. Se il contratto è chiaro, tutto il resto è dettaglio.

Sull'Autore

Leonardo Pedron è Backend Developer con esperienza nella progettazione di API REST a elevata concorrenza. Ha lavorato su sistemi che gestiscono milioni di richieste al giorno.