API Design — Cheat Sheet

Tag: api, rest, rest-api, http, json, web-services, backend, api-design

Livello: intermedio

TL;DR: Best practice per la progettazione di API REST: denominazione risorse, metodi HTTP, codici di stato, paginazione, versionamento e idempotenza.

Concetti chiave

Usa sostantivi plurali per identificare le risorse e mai verbi negli endpoint (/api/v1/orders).

Sfrutta i metodi HTTP standard: GET per lettura, POST per creazione, PUT per sostituzione completa.

Usa PATCH per aggiornamenti parziali e DELETE per rimozione delle risorse.

Mantieni GET, HEAD, OPTIONS e PUT idempotenti; POST non e' idempotente per definizione.

Ritorna codici di stato HTTP semanticamente corretti per ogni scenario di successo o errore.

Versiona l'API tramite URI path (/api/v1/...) o header custom (Accept: application/vnd.myapi.v1+json).

Implementa paginazione standard tramite query parameter (limit, offset o cursor-based con token).

Fornisci payload di errore strutturati e consistenti su tutti gli endpoint (es. standard RFC 7807).

Supporta il filtraggio e l'ordinamento tramite query parameters espliciti (?status=active&sort=-created_at).

Assicura statelessness: ogni richiesta contiene tutte le informazioni necessarie per essere elaborata.

Domande tipiche e risposte pronte

Q: Qual e' la differenza tra PUT e PATCH in un'API REST?R: PUT sostituisce integralmente la risorsa target con il payload inviato, mentre PATCH applica una modifica parziale solo ai campi specificati nella richiesta.

Q: Come gestisci l'idempotenza nelle chiamate di pagamento o checkout (POST)?R: Implemento un header di idempotenza, come Idempotency-Key, salvando la chiave univoca e la risposta iniziale per restituire lo stesso output in caso di retry duplicati.

Q: Quale codice di stato restituisci quando una risorsa richiesta non esiste?R: Restituisco 404 Not Found corredato da un payload JSON con codice di errore applicativo e messaggio descrittivo.

Q: Quando e' preferibile usare una paginazione a cursore rispetto a limit/offset?R: Scelgo il cursore su dataset grandi o in rapido aggiornamento, poiche' evita problemi di skip/duplicazione di record ed e' piu' efficiente a livello di query database.

Insidie e errori comuni

Inserire verbi nelle URI (es. /api/getUser, /api/createInvoice) invece di sfruttare i verbi HTTP.

Restituire HTTP 200 OK con un payload contenente { success: false, error: "..." }.

Confondere 401 Unauthorized (mancata autenticazione) con 403 Forbidden (mancanza di permessi).

Dimenticare di validare a fondo il Content-Type e l'Accept header nelle richieste in entrata.

Esporre dettagli interni del database o stack trace nei payload di errore HTTP 500.

Introdurre breaking change sui campi di risposta senza aggiornare la versione dell'API.

Snippet e comandi

// Risposta di errore standard (ispirata a RFC 7807 Problem Details)
{
  "type": "https://api.example.com/errors/resource-not-found",
  "title": "Resource Not Found",
  "status": 404,
  "detail": "Customer with ID 42 was not found.",
  "instance": "/api/v1/customers/42"
}

HTTP

# Esempio di richiesta di aggiornamento parziale
PATCH /api/v1/customers/42 HTTP/1.1
Host: api.example.com
Content-Type: application/json

{
  "email": "user@example.com"
}

Da ripassare

[ ] Meccanismi di HATEOAS e livelli del Richardson Maturity Model

[ ] Pattern di rate limiting tramite header HTTP (X-RateLimit-Limit, Retry-After)

[ ] Differenze architetturali tra REST, GraphQL e gRPC

[x] Mappatura codici di stato HTTP 2xx, 4xx, 5xx

[x] Regole di naming e convenzioni RESTful

Jarvis Interviews
Jarvis