Partire dal contratto che consumerà il client
Prima di implementare un endpoint definiamo risorse, operazioni, stati e casi di errore. Il frontend deve sapere quali campi sono obbligatori, quali possono mancare e come cambiano le risposte in base ai permessi. Le integrazioni esterne devono poter distinguere un input non valido da un conflitto o un'indisponibilità temporanea.
Utilizziamo DTO TypeScript per descrivere richieste e risposte, ma non confondiamo il controllo a compilazione con la validazione a runtime. I dati ricevuti dalla rete vengono trasformati e verificati esplicitamente. Campi inattesi, formati e limiti sono gestiti in modo coerente.
La documentazione OpenAPI, resa consultabile anche tramite Swagger UI quando utile, nasce dallo stesso contratto. Include esempi, autenticazione, codici di stato e paginazione. Viene controllata insieme al codice affinché non diventi un documento separato e superato.
Moduli costruiti sui confini del dominio
NestJS facilita moduli e dependency injection, ma organizzare il codice solo per dettaglio tecnico può comunque creare dipendenze difficili da gestire. Per questo dividiamo le responsabilità in base alle funzioni reali del prodotto: identità, ordini, assistenza, fatturazione o altri ambiti significativi.
Controller, servizi e accesso ai dati restano distinti: il controller riceve la richiesta, il servizio applica le regole, l'accesso ai dati gestisce la persistenza. Rendiamo esplicite le dipendenze per facilitare i test, evitando però livelli aggiuntivi che non semplificano né modificare né verificare il codice.
Autenticazione e autorizzazione non sono lo stesso controllo
L'autenticazione stabilisce chi sta chiamando l'API. L'autorizzazione decide se quella identità può compiere l'operazione sulla risorsa specifica. Implementiamo strategie coerenti con il prodotto, per esempio sessioni, token o integrazione con un gestore di identità.
Guard e policy applicano ruoli, proprietà del dato e contesto organizzativo prima del caso d'uso. In una piattaforma per più aziende, non basta verificare che l'utente abbia il ruolo corretto: ogni query e ogni comando devono rimanere all'interno dell'organizzazione autorizzata.
Le credenziali tecniche per servizi esterni vengono separate dalle identità utente e limitate per scopo. Le operazioni sensibili producono registri utili a ricostruire chi ha richiesto e chi ha eseguito l'azione.
Versionare senza moltiplicare il debito
Le modifiche compatibili vengono preferite quando possibile: aggiunta di campi facoltativi, endpoint nuovi e deprecazioni comunicate. Quando il contratto deve cambiare in modo incompatibile, definiamo una versione e un periodo di convivenza collegato ai client effettivi.
La versione non elimina il problema della manutenzione. Occorre sapere quali consumer usano ancora il contratto precedente e quando potrà essere rimosso. Log e metriche aiutano a evitare endpoint obsoleti mantenuti per supposizione.
Errori coerenti
e osservabili
Collaborazione, consegne
e assistenza
COLLABORAZIONE
Possiamo integrarci nel repository e nel flusso del team, lavorando su attività concordate con branch, pull request e revisioni. Prima di iniziare verifichiamo ambiente, standard, pipeline e criteri di completamento.
CONSEGNA
Comprende codice, migration, test, aggiornamento OpenAPI e note per configurazione o rilascio. Dipendenze e cambi di perimetro vengono comunicati durante lo sviluppo. Per attività con forte incertezza proponiamo un'analisi limitata prima della stima completa.
ASSISTENZA
L'assistenza può proseguire con aggiornamenti, analisi degli errori e nuove versioni dei contratti. Manteniamo visibili le attività preventive, evitando che ogni intervento sia guidato soltanto dall'urgenza.