Qual è il numero che decide quanto investire nella documentazione delle API?
Fino a 1 giornata basta una descrizione generata dal codice; fra 2 e 3 giornate serve una documentazione completa con esempi e controlli; sopra le 3 giornate il problema è l'API e va sistemata prima. In un'azienda di 40 persone, a 3 giornate, la strada giusta costava circa 32.940 euro in tre anni, contro 88.560 euro di non fare niente.

Un'azienda che produce macchine per il confezionamento ha un gestionale in .NET e da quattro anni espone le sue API a rivenditori, trasportatori e a un grande cliente. Ogni volta che un nuovo partner vuole collegarsi, parte lo stesso copione: una telefonata, tre email, un file Excel con i nomi dei campi, due settimane di domande e un programmatore interno che lascia quello che stava facendo.
Il responsabile IT pensa che il problema sia il partner, "che non capisce". La verità è che nessuno ha mai scritto come si usano quelle API, e ogni integrazione ripaga il costo di quel silenzio da capo.
Questo articolo ti dice quanto costa non avere una documentazione delle API, quali strade esistono per averla (e quanto costano in tre anni), come si costruisce con OpenAPI in ASP.NET Core senza scriverla due volte, e che cosa deve contenere perché un integratore la usi davvero.
Troverai il conto di quanto costa il silenzio, il numero che decide quanto investire, il confronto fra cinque strade con i costi in euro, il codice C# che compila per descrivere gli endpoint, il test che impedisce di rompere il contratto senza accorgersene, il piano di trenta giorni e gli errori che vedo più spesso.
Una premessa. Dal 1999 progetto software per aziende, quasi sempre in .NET, e ho visto API ottime nascoste da documenti inutili e API mediocri salvate da una pagina scritta bene. Non ti devo vendere un portale: ti consiglio la strada più economica che regge, e spesso è molto più piccola di quella che ti hanno proposto.
Il caso che uso è un'azienda tipo, costruita con ordini di grandezza e medie di settore. Non è un cliente, è un metodo: lo rifai con i tuoi numeri in un pomeriggio.
Che cos'è la documentazione di un'API e perché quasi nessuno la scrive?
La documentazione di un'API è tutto ciò che permette a una persona che non ha scritto il programma di usarlo senza chiederti nulla: quali indirizzi esistono, che cosa mandare, che cosa torna, che cosa significa ogni errore, come ci si autentica e che cosa cambierà nei prossimi mesi.
La definizione è semplice. Il motivo per cui non si scrive è altrettanto semplice, e non è pigrizia.
- Chi scrive l'API sa già come funziona. La conoscenza è così ovvia da sembrare inutile da scrivere. Per l'integratore è l'unica cosa che manca.
- Non ha una scadenza. Il rilascio dell'API ha una data, la documentazione no. Quando il tempo stringe, è la prima cosa che esce dal piano.
- Invecchia da sola. Un documento scritto a mano è giusto il giorno in cui lo scrivi. Dopo tre rilasci racconta un'API che non esiste più, e un documento sbagliato è peggio di nessun documento.
- Il costo di non averla è invisibile. Si disperde in telefonate, email e mezze giornate. Nessuno lo mette in fattura e nessuno lo somma.
L'ultimo punto è quello che rende tutto il resto un problema di soldi e non di buone maniere. Se il costo del silenzio fosse una riga di bilancio, la documentazione sarebbe già scritta.
C'è poi un fatto nuovo. Chi si collega alle tue API oggi, sempre più spesso, chiede a un assistente di intelligenza artificiale di scrivere il codice dell'integrazione. L'assistente funziona bene se gli dai una descrizione OpenAPI pulita, e funziona male se gli dai un PDF con le schermate. Una documentazione leggibile da una macchina non è più un lusso da grandi aziende: è ciò che decide se il tuo partner arriva alla prima chiamata riuscita in un'ora o in due settimane.
Com'è fatta l'azienda tipo e da quali numeri parte?
L'azienda tipo produce macchine per il confezionamento e ha 40 persone. Il gestionale è in ASP.NET Core e da quattro anni espone API REST. Le usano cinque soggetti: un portale di vendita per i rivenditori, il corriere, un'app per i tecnici in assistenza, un grande cliente con il suo sistema ordini e il commercialista per le fatture.
Ecco i numeri, quelli che rilevi in mezza giornata guardando le email, il registro delle richieste di supporto e le ore dichiarate dai programmatori.
| Misura | Valore | Come si rileva |
|---|---|---|
| Soggetti che usano le API | 5 attivi, 8 nuove integrazioni all'anno | Elenco delle chiavi di accesso emesse e dei progetti avviati nell'ultimo anno |
| Richieste di supporto sulle API | 14 al mese, 1,5 ore ciascuna | Casella di posta condivisa e ticket, parole come "campo", "errore", "come si chiama" |
| Affiancamento per ogni nuova integrazione | 3 giornate di un programmatore interno | Ore dichiarate sui progetti di integrazione dell'ultimo anno |
| Modifiche che hanno rotto un partner | 3 l'anno, 2 giornate per ripararle | Memoria del team e registro degli incidenti |
| Endpoint pubblici | 76, in 11 gruppi | Elenco delle rotte dell'applicazione |
| Documentazione esistente | Un PDF di 18 pagine del 2022 e un foglio Excel | Chiedere "dove mandate un nuovo partner?" |
| Costo di un'ora di programmatore interno | 60 euro | Costo del lavoro diviso per le ore lavorate |
| Costo di una giornata di sviluppo | 480 euro | Tariffa di riferimento, 8 ore a 60 euro |
Due note sui numeri. La prima: le 14 richieste al mese sembrano poche. Sono 21 ore, cioè quasi tre giornate piene di lavoro qualificato che non produce una riga di codice nuovo. E non contano la chiamata in cui il programmatore perde il filo di quello che stava facendo.
La seconda: il PDF del 2022 non è documentazione, è un reperto. Descrive 52 endpoint su 76, cita due campi che non esistono più e non dice mai che cosa significhi un errore 422. Il partner lo legge, non si fida, e chiama.
Quanto costa non avere la documentazione?

Il costo c'è, ma sta in tre voci che nessuno ha mai sommato.
- Le richieste di supporto. Quattordici al mese per 1,5 ore sono 21 ore, per dodici mesi 252 ore. A 60 euro fanno 15.120 euro l'anno.
- L'affiancamento. Otto nuove integrazioni, tre giornate di affiancamento ciascuna, 480 euro a giornata: 11.520 euro. Il programmatore spiega a voce quello che avrebbe dovuto leggere il partner.
- Le rotture. Tre volte l'anno una modifica toglie o rinomina un campo e un partner si ferma. Due giornate per capire, correggere e chiedere scusa: 2.880 euro.
Il totale è 29.520 euro l'anno, circa 88.560 euro in tre anni. Per 40 persone e 76 endpoint è una cifra che non compare in nessun bilancio, ed è la stessa cifra con cui devi confrontare qualsiasi preventivo di portale per sviluppatori.
Restano fuori, di proposito, le voci più pesanti e più difficili da stimare.
- Il partner che rinuncia: il grande cliente che, dopo due settimane senza una risposta, sceglie un fornitore che ha l'API documentata. Non lo sai, perché non telefona per dirtelo.
- Il programmatore nuovo che impiega un mese a capire il sistema perché l'unica fonte è chi lo ha scritto.
- La reputazione tecnica: chi integra e perde tempo racconta ad altri che le tue API sono un'impresa.
Se vuoi un solo esercizio da fare oggi, apri la casella di posta condivisa e conta, dell'ultimo mese, le email che iniziano con "una domanda sulle API". Moltiplica per mezz'ora e per 60 euro. Ti ci vogliono dieci minuti, e di solito la cifra è più alta di quanto ti aspetti.
Qual è il numero che decide quanto investire?

Le persone si dividono in due partiti. Quelli che dicono "la documentazione è fondamentale, facciamo un portale". E quelli che dicono "il codice si spiega da solo". Hanno ragione e torto entrambi, perché mescolano due problemi diversi.
Il primo problema è la mancanza di informazione: il partner non sa che campo mandare, che cosa significa un errore, come si autentica. Si risolve scrivendo, e scrivendo bene.
Il secondo problema è la qualità dell'API: i nomi cambiano da un endpoint all'altro, gli errori sono muti, lo stesso concetto ha tre forme. Questo non si risolve con la documentazione. Si risolve sistemando l'API, e poi scrivendo.
Il numero che distingue i due casi è semplice: quante giornate di affiancamento richiede, in media, ogni nuova integrazione. L'azienda tipo ne spende tre, 11.520 euro in otto integrazioni.
La regola che uso:
- Fino a una giornata: l'API è già abbastanza chiara. Basta una descrizione generata dal codice e pubblicata, con un paio di esempi. Spendere di più è sprecare.
- Fra due e tre giornate: serve una documentazione vera, con descrizioni, esempi, catalogo degli errori e controllo delle modifiche. È la zona in cui il ritorno è più rapido.
- Sopra le tre giornate: la documentazione non basta. Ogni integratore inciampa sulle stesse incoerenze, e nessun portale le nasconde. Si sistemano gli errori e i nomi prima, e poi si documenta.
L'azienda tipo è a tre giornate, sul bordo. La conclusione non è quella che si aspettavano né i fautori del portale né quelli del "codice che si spiega da solo": prima si fa un giro di pulizia di due o tre giorni sulle incoerenze peggiori, poi si documenta con strumenti che si aggiornano da soli.
Un controllo in più, che prende venti minuti. Chiedi al programmatore che affianca di annotare, per un mese, ogni domanda che riceve. Segna per ciascuna una lettera: I se la risposta era in un posto che il partner non ha trovato (informazione), Q se la domanda nasce da un'incoerenza dell'API (qualità), A se riguarda accessi, chiavi e ambienti. Se hai più Q che I, documentare non basta.
Quali strade esistono, e quanto costano in tre anni?

Le strade sono quattro, più quella di non fare niente. I prezzi sono ordini di grandezza che ho sotto mano, da verificare con un preventivo. Il conto è sempre lo stesso: costo di passaggio, manutenzione per tre anni, e il costo di quello che resta come prima.
| Strada | Che cosa si fa | Costo di passaggio | Manutenzione e canoni in 3 anni | Costo che resta in 3 anni | Totale in 3 anni |
|---|---|---|---|---|---|
| A. Non documentare | Niente, si risponde al telefono | 0 | 0 | supporto 45.360 + affiancamento 34.560 + rotture 8.640 | 88.560 |
| B. Documento a mano | Word o wiki, scritto da un programmatore | 3.840 (8 giornate) | 8.640 (6 giornate l'anno) | supporto 29.484 + affiancamento 23.040 + rotture 8.640 | 73.644 |
| C. Descrizione dal codice, così com'è | OpenAPI generata e pubblicata, senza altro | 1.920 (4 giornate) | 2.880 (2 giornate l'anno) | supporto 20.412 + affiancamento 23.040 + rotture 8.640 | 56.892 |
| D. Portale acquistato | Servizio a canone con pagine, prova in linea e contenuti scritti | 4.800 (10 giornate) | 7.200 di canone + 5.760 di contenuti | supporto 15.876 + affiancamento 17.280 + rotture 8.640 | 59.556 |
| E. Dal codice, con esempi e controllo | OpenAPI curata, esempi, errori elencati, controllo delle modifiche nella pipeline | 4.320 (9 giornate) | 2.880 (2 giornate l'anno) | supporto 11.340 + affiancamento 11.520 + rotture 2.880 | 32.940 |
Come leggere la tabella. La strada più economica in tre anni è la E, la più cara dopo il silenzio è il documento a mano, e il portale acquistato costa quasi come la semplice descrizione generata, perché il canone non elimina il lavoro di scrivere i contenuti.
Perché la E batte la C, che pure sembra "già tutto automatico"? Per due ragioni. La prima: la descrizione generata dice la forma (campi, tipi, indirizzi) ma non dice il perché, né che cosa fare quando torna un errore. È la parte che genera le richieste di supporto. La seconda: senza un controllo delle modifiche, le tre rotture l'anno restano tre. Nella E scendono a una.
Perché la E batte il portale? Perché il portale è un contenitore, e il tuo problema è il contenuto. Un portale con descrizioni vuote costa 7.200 euro di canone e lascia l'integratore dov'era. Ha senso quando hai centinaia di partner esterni, un programma di sviluppatori con registrazione e chiavi emesse da solo. Per otto integrazioni l'anno no.
E il documento a mano? Sembra la strada prudente e costa più della descrizione generata, perché invecchia. Il risparmio sul supporto è del 35 per cento il primo anno e di meno il secondo, perché le persone smettono di fidarsi. Il costo che ho messo è una stima prudente.
Tre avvertenze sui conti.
- Le percentuali di riduzione (il 55 per cento del supporto con la descrizione generata, il 75 per cento con quella curata, il 67 per cento dell'affiancamento con la E) sono ordini di grandezza che ho visto nei progetti. Le tue vanno misurate dopo il primo trimestre.
- Il canone del portale che ho usato, 2.400 euro l'anno, è un ordine di grandezza. I listini cambiano spesso e molti servizi chiedono di più al crescere degli utenti.
- Nella E non c'è il costo di sistemare le incoerenze dell'API. Sono reali, e sono il motivo per cui la zona "sopra le tre giornate" esiste. Contale a parte: due o tre giornate di pulizia sono un buon punto di partenza.
Come si costruisce la descrizione OpenAPI in ASP.NET Core senza scriverla due volte?
La regola che tiene in piedi tutto è una: la documentazione non si scrive accanto al codice, si ricava dal codice. Se la descrizione degli endpoint vive in un file separato, nel giro di tre rilasci racconta un'altra API.
OpenAPI è lo standard che descrive un'API REST in un file leggibile da persone e da programmi: indirizzi, parametri, forme di richiesta e risposta, errori, autenticazione. Da quel file si generano le pagine di riferimento, i client in vari linguaggi, i test del contratto e i file per Postman.
In ASP.NET Core la generazione è inclusa dal .NET 9, nel pacchetto Microsoft.AspNetCore.OpenApi. Non devi più installare strumenti di terze parti per ottenere il file. Per una pagina navigabile con la prova in linea puoi aggiungere un visualizzatore come Scalar, che è un pacchetto a parte.
Ecco un'applicazione minima che descrive un endpoint come si deve. Il codice compila con .NET 10, dopo aver installato i pacchetti Microsoft.AspNetCore.OpenApi e Scalar.AspNetCore.
using Microsoft.AspNetCore.Mvc;
using Scalar.AspNetCore;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddSingleton<IRegistroOrdini, RegistroOrdini>();
builder.Services.AddOpenApi(opzioni =>
{
opzioni.AddDocumentTransformer((documento, contesto, token) =>
{
documento.Info.Title = "API Ordini";
documento.Info.Version = "v1";
documento.Info.Description =
"Crea e consulta gli ordini. Autenticazione con chiave nell'intestazione X-Api-Key. " +
"Gli errori seguono il formato Problem Details (RFC 9457).";
return Task.CompletedTask;
});
});
var app = builder.Build();
app.MapOpenApi(); // pubblica /openapi/v1.json
if (app.Environment.IsDevelopment())
{
app.MapScalarApiReference(); // pagina di consultazione con prova in linea
}
var ordini = app.MapGroup("/ordini").WithTags("Ordini");
ordini.MapGet("/{id:guid}", (Guid id, IRegistroOrdini registro) =>
{
var ordine = registro.Trova(id);
return ordine is null
? Results.Problem(
title: "Ordine non trovato",
detail: $"Nessun ordine con identificativo {id}.",
statusCode: StatusCodes.Status404NotFound)
: Results.Ok(ordine);
})
.WithName("LeggiOrdine")
.WithSummary("Legge un ordine")
.WithDescription("Restituisce l'ordine con righe e stato. Lo stato cambia solo in avanti.")
.Produces<OrdineDto>(StatusCodes.Status200OK)
.ProducesProblem(StatusCodes.Status404NotFound);
ordini.MapPost("/", (
[FromHeader(Name = "Idempotency-Key")] string? chiave,
NuovoOrdineDto richiesta,
IRegistroOrdini registro) =>
{
if (string.IsNullOrWhiteSpace(chiave))
{
return Results.Problem(
title: "Manca l'intestazione Idempotency-Key",
detail: "Senza chiave una ripetizione della chiamata creerebbe un ordine doppio.",
statusCode: StatusCodes.Status400BadRequest);
}
var creato = registro.Crea(chiave, richiesta);
return Results.Created($"/ordini/{creato.Id}", creato);
})
.WithName("CreaOrdine")
.WithSummary("Crea un ordine")
.WithDescription("Se ripeti la chiamata con la stessa Idempotency-Key ottieni lo stesso ordine, non un secondo.")
.Produces<OrdineDto>(StatusCodes.Status201Created)
.ProducesProblem(StatusCodes.Status400BadRequest);
app.Run();
public record RigaDto(string Codice, int Quantita);
public record NuovoOrdineDto(string CodiceCliente, List<RigaDto> Righe);
public record OrdineDto(Guid Id, string CodiceCliente, string Stato, List<RigaDto> Righe);
public interface IRegistroOrdini
{
OrdineDto? Trova(Guid id);
OrdineDto Crea(string chiave, NuovoOrdineDto richiesta);
}
public class RegistroOrdini : IRegistroOrdini
{
private readonly Dictionary<Guid, OrdineDto> _ordini = new();
private readonly Dictionary<string, Guid> _chiavi = new();
public OrdineDto? Trova(Guid id) => _ordini.GetValueOrDefault(id);
public OrdineDto Crea(string chiave, NuovoOrdineDto richiesta)
{
lock (_ordini)
{
if (_chiavi.TryGetValue(chiave, out var esistente))
{
return _ordini[esistente];
}
var ordine = new OrdineDto(Guid.NewGuid(), richiesta.CodiceCliente, "Ricevuto", richiesta.Righe);
_ordini[ordine.Id] = ordine;
_chiavi[chiave] = ordine.Id;
return ordine;
}
}
}
public partial class Program { }Che cosa fa il file generato, senza che tu scriva una riga di documentazione a parte? Elenca i due endpoint con nome, riassunto e descrizione, le forme di OrdineDto e NuovoOrdineDto, l'intestazione obbligatoria dell'idempotenza, e i codici di risposta possibili, compreso il formato degli errori.
Tre scelte in questo codice valgono più del codice stesso.
- Ogni endpoint ha un nome di operazione.
WithNamediventa l'identificativo che usano i generatori di client. Se lo lasci vuoto, il nome è inventato dagli strumenti e cambia a ogni rinomina del metodo. - Gli errori sono dichiarati.
ProducesProblemmette nel file i casi in cui l'endpoint fallisce. Un partner che vede solo il 200 scrive un'integrazione che si rompe al primo errore. - La descrizione dice una regola, non ripete il nome. "Lo stato cambia solo in avanti" è un'informazione. "Legge un ordine" è solo un titolo.
Una nota sulle descrizioni lunghe. Non scriverle dentro stringhe del codice se sono più di due frasi. Dal .NET 10 il generatore può leggere anche i commenti XML (///) dai tuoi metodi, a patto di attivare la generazione del file di documentazione nel progetto. Per le API costruite con i controller, i commenti XML sono la strada naturale; per le API minime, le chiamate WithSummary e WithDescription sono più dirette e si vedono in revisione.
Che cosa deve contenere la documentazione perché l'integratore la usi davvero?

Il file OpenAPI è il riferimento: dice che cosa esiste. Non basta. Un integratore ha cinque bisogni, e il file ne copre uno e mezzo.
- Il riferimento. Ogni endpoint, ogni campo, ogni tipo. Lo genera il codice. È l'unica parte che non deve mai essere scritta a mano.
- La prima chiamata in dieci minuti. Una pagina che porta dalla chiave di accesso a una risposta riuscita, con una richiesta pronta da incollare in
curl. È la pagina più letta e la più trascurata. Se non c'è, il partner la chiede per telefono. - Le guide per scenario. "Come creo un ordine e ne seguo lo stato", "come gestisco una ripetizione dopo un timeout". Una pagina per ogni cosa che l'integratore vuole fare davvero, nell'ordine in cui la fa.
- Il catalogo degli errori. Per ogni errore: che cosa significa, di chi è la colpa, che cosa fare. È qui che si spegne la maggior parte delle richieste di supporto.
- Il registro delle modifiche. Che cosa è cambiato, quando, e che cosa sarà tolto. Senza questo, l'integratore deve scoprirlo da solo, di solito a mezzanotte.
I punti 2, 3, 4 e 5 non si ricavano dal codice. Si scrivono una volta, in pochi file di testo nello stesso repository, e si rivedono con il codice nella stessa richiesta di modifica. Sono circa quattro giornate di lavoro per la prima stesura, e poi poco.
Per ognuna delle cinque parti, ecco che cosa funziona nella pratica.
La prima chiamata
Una richiesta completa, copiabile, con un valore di prova che funziona nell'ambiente di prova. Non "sostituisci con la tua chiave" in un testo di tre righe: la richiesta intera, e sotto la risposta attesa.
curl -X POST https://api.esempio.it/ordini \
-H "X-Api-Key: CHIAVE_DI_PROVA" \
-H "Idempotency-Key: 6f2c1d9e-prova-0001" \
-H "Content-Type: application/json" \
-d '{"codiceCliente":"C-1042","righe":[{"codice":"NASTRO-45","quantita":12}]}'Sotto, la risposta con codice 201 e il corpo completo. Se il partner vede la stessa cosa sul suo schermo in dieci minuti, ti ha già risparmiato la telefonata.
Gli errori
Il formato degli errori deve essere uno solo, per tutta l'API. Lo standard è Problem Details, descritto dall'RFC 9457, che ASP.NET Core sa già produrre. Un errore ha un tipo, un titolo, un codice di stato, un dettaglio e, quando serve, l'elenco dei campi sbagliati.
Il catalogo degli errori è una tabella di questo tipo:
| Codice | Quando succede | Di chi è la colpa | Che cosa fare |
|---|---|---|---|
| 400 | Manca Idempotency-Key o il corpo non è leggibile | Chi chiama | Aggiungere l'intestazione; controllare il formato del corpo |
| 401 | Chiave assente, scaduta o revocata | Chi chiama | Chiedere una nuova chiave; non riprovare in automatico |
| 404 | L'ordine non esiste o appartiene a un altro cliente | Chi chiama | Controllare l'identificativo; non è un errore da ripetere |
| 409 | Stessa Idempotency-Key con un corpo diverso | Chi chiama | Usare una chiave nuova per un ordine nuovo |
| 422 | Il corpo è leggibile ma una riga non è valida (codice sconosciuto, quantità zero) | Chi chiama | Correggere il campo indicato nell'elenco degli errori |
| 429 | Troppe richieste in poco tempo | Chi chiama | Aspettare i secondi indicati in Retry-After e riprovare |
| 503 | Il servizio è in manutenzione o sotto carico | Noi | Riprovare con attesa crescente; controllare la pagina di stato |
La colonna "di chi è la colpa" è quella che fa risparmiare più telefonate. Se è dell'integratore, sa che deve correggere. Se è nostra, sa che deve aspettare, e non apre un ticket.
Le ripetizioni
La domanda più costosa del mondo è "la chiamata è andata a buon fine?". Succede quando la rete cade a metà: il partner non sa se l'ordine è stato creato. Se riprova senza una protezione, rischia un doppione; se non riprova, rischia di perderlo.
La soluzione è l'idempotenza: l'integratore manda una chiave unica per ogni operazione, e il servizio, se la vede due volte, restituisce lo stesso risultato. Nel codice qui sopra l'intestazione è Idempotency-Key, ormai una convenzione diffusa. Documentala nella guida "cosa fare dopo un timeout": è la pagina che ti evita gli ordini doppi.
Le modifiche e le scadenze
Un'API cambia. La promessa che puoi fare è che le modifiche che rompono un partner non arrivano senza preavviso. Per rispettarla servono due cose. Un numero di versione nell'indirizzo o nell'intestazione, e un modo standard per annunciare che qualcosa sta per sparire.
Lo standard c'è. L'intestazione Deprecation (RFC 9745) dice che un endpoint è deprecato; l'intestazione Sunset (RFC 8594) dice il giorno in cui verrà spento. Messe nelle risposte, permettono a chi integra di accorgersene dal proprio registro, senza leggere la tua newsletter.
app.Use(async (contesto, successivo) =>
{
if (contesto.Request.Path.StartsWithSegments("/v1/spedizioni-vecchie"))
{
contesto.Response.Headers["Deprecation"] = "true";
contesto.Response.Headers["Sunset"] = "Fri, 30 Apr 2027 23:59:59 GMT";
contesto.Response.Headers["Link"] = "<https://api.esempio.it/docs/migrazione-spedizioni>; rel=\"deprecation\"";
}
await successivo();
});In questo esempio la data è scritta in chiaro per semplicità. In un progetto vero la leggi da una tabella delle deprecazioni, la stessa che alimenta il registro delle modifiche, così le due cose non possono diventare incoerenti.
Come si impedisce di rompere un partner senza accorgersene?
Le tre rotture l'anno dell'azienda tipo hanno la stessa origine: un programmatore sistema un nome, toglie un campo che "non serve" o rende obbligatorio un parametro, e nessuno controlla chi lo usa. Il rimedio non è la prudenza, è un controllo automatico che fallisce quando il contratto cambia.
Il controllo funziona in due livelli.
Il primo è un test del contratto. Il file OpenAPI approvato sta nel repository. A ogni compilazione, il test avvia l'applicazione, legge il file che genera adesso e lo confronta con quello approvato. Se sono diversi, il test fallisce, e chi ha fatto la modifica deve aggiornare il file approvato nella stessa richiesta di modifica: il cambiamento diventa visibile a chi la revisiona.
using System.Text.Json.Nodes;
using Microsoft.AspNetCore.Mvc.Testing;
using Xunit;
public class ContrattoApiTests : IClassFixture<WebApplicationFactory<Program>>
{
private readonly WebApplicationFactory<Program> _fabbrica;
public ContrattoApiTests(WebApplicationFactory<Program> fabbrica)
{
_fabbrica = fabbrica;
}
[Fact]
public async Task Il_contratto_non_cambia_senza_che_qualcuno_lo_approvi()
{
var client = _fabbrica.CreateClient();
var attuale = await client.GetStringAsync("/openapi/v1.json");
var approvato = await File.ReadAllTextAsync("Contratto/openapi.v1.json");
Assert.Equal(Normalizza(approvato), Normalizza(attuale));
}
private static string Normalizza(string json) => JsonNode.Parse(json)!.ToJsonString();
}Il test serve il pacchetto Microsoft.AspNetCore.Mvc.Testing, e la riga public partial class Program { } in fondo all'applicazione, che l'esempio precedente già contiene. Il file approvato si crea la prima volta salvando quello che l'applicazione genera e rivedendolo a mano.
Il secondo livello distingue le modifiche innocue da quelle che rompono. Aggiungere un campo facoltativo in una risposta non fa male a nessuno. Togliere un campo, cambiarne il tipo o rendere obbligatorio un parametro che prima era facoltativo sì. Lo strumento libero oasdiff confronta due file OpenAPI e classifica le differenze. Nella pipeline basta un passo:
oasdiff breaking Contratto/openapi.v1.json openapi-attuale.json --fail-on ERRSe il confronto trova una modifica che rompe, il comando esce con errore e la pipeline si ferma. La modifica si può fare lo stesso, ma solo in una nuova versione dell'API, con preavviso e con una data di spegnimento della vecchia.
Quanto costa tutto questo? Il test e il passo nella pipeline sono circa una giornata di lavoro. Il vantaggio non sta nel test, sta nella conversazione che costringe: ogni modifica al contratto passa da una revisione in cui qualcuno chiede "e i partner?". Nell'azienda tipo le rotture scendono da tre a una l'anno, e quella che resta è quella che si è scelto di fare.
Come si pubblica, e a chi serve la prova in linea?
Con il file OpenAPI in mano, le strade per pubblicarlo sono tre, dalla più semplice alla più ricca.
- Il file e basta. Lo metti a un indirizzo pubblico o lo mandi al partner. Gli sviluppatori esperti lo caricano nel loro strumento. È il minimo, e costa zero.
- Una pagina di riferimento. Un visualizzatore (Scalar, Redoc, Swagger UI) legge il file e disegna le pagine con la ricerca e la prova in linea. Costa una mezza giornata.
- Un sito di documentazione. Le pagine scritte a mano (prima chiamata, guide, errori, modifiche) e la pagina di riferimento stanno insieme, con la stessa grafica. Costa dalle due alle quattro giornate, e si pubblica da pipeline a ogni rilascio.
La prova in linea, cioè il pulsante che fa partire una richiesta vera dal browser, piace molto e va usata con giudizio. Su un ambiente di prova con dati finti è un regalo. Su produzione è un rischio: chi la prova può creare un ordine vero. Regola semplice: la prova in linea esiste solo nell'ambiente di prova, con chiavi di prova.
L'ambiente di prova è, dopo la prima chiamata, la cosa che l'integratore apprezza di più. Un indirizzo separato, dati finti ma realistici, chiavi che si ottengono da soli, nessun rischio di sporcare la produzione. Per un partner serio la differenza fra "ho un ambiente dove sbagliare" e "provo in produzione" è la differenza fra una settimana e un mese.
Dal file OpenAPI si ricava anche altro, quasi gratis.
- I client pronti. Strumenti come Kiota (di Microsoft) generano un client per C#, TypeScript, Python e altri linguaggi. Un partner che usa .NET scrive
cliente.Ordini.PostAsync(...)invece di costruire richieste a mano. - La collezione per Postman o per altri strumenti. Si importa il file e la collezione è pronta, con tutti gli endpoint.
- I dati per gli assistenti di programmazione. Un file OpenAPI coerente è l'input migliore per chi chiede a un assistente di scrivere l'integrazione. Più il file è curato, meno l'assistente inventa.
Che cosa succede se l'API è incoerente?
Torno alla zona "sopra le tre giornate", perché è il punto in cui più progetti falliscono. Se il tuo conteggio dice che ogni integrazione richiede quattro o cinque giornate di affiancamento, la documentazione non risolverà niente: renderà solo visibili, in modo ordinato, le incoerenze.
Le incoerenze che vedo più spesso, nell'ordine in cui costano:
- Nomi diversi per la stessa cosa.
codiceClientein un endpoint,customerIdin un altro,idClientein un terzo. L'integratore scrive tre mappature e sospetta che siano cose diverse. - Errori muti. Un 500 generico, o un 400 con il testo "Errore". L'integratore non sa se deve correggere o riprovare, e chiama.
- Date e numeri in formati misti. Una data in formato italiano, una in ISO 8601, una come numero di millisecondi. Gli importi come testo con la virgola. Sono i bug più silenziosi.
- Paginazione diversa in ogni elenco. Pagina e dimensione, oppure un cursore, oppure niente e restituisce tutto.
- Lo stesso stato con parole diverse. "Annullato", "cancellato", "stornato" per tre endpoint sullo stesso concetto.
- Campi che cambiano significato. Un campo
statoche prima valeva 0 o 1 e ora vale un testo, senza un annuncio.
Nessuna di queste si risolve con un portale. Si risolvono con una giornata di pulizia per ogni gruppo di endpoint, scegliendo una convenzione e applicandola. Il costo è dalle due alle tre giornate per l'azienda tipo, e si recupera in meno di un anno solo nell'affiancamento.
Il modo giusto di farlo è non toccare le vecchie rotte. Si crea la versione corretta come nuova versione, si annuncia con Deprecation e Sunset e si lascia la vecchia accesa per sei-dodici mesi. In quel periodo la vecchia è documentata come "in spegnimento" e la nuova è quella del quickstart. È la pulizia più lenta e meno pericolosa che esista.
Come si passa dal silenzio alla documentazione in trenta giorni?
Il passaggio non richiede un progetto di sei mesi. Per l'azienda tipo il piano è di trenta giorni lavorativi al massimo, con un programmatore a metà tempo e un'ora a settimana di chi riceve le richieste di supporto.
- Giorni 1-3: il conteggio. Si apre la posta condivisa, si contano le domande dell'ultimo mese e si assegna a ciascuna la lettera I, Q o A. Si sommano le giornate di affiancamento dell'ultimo anno. Si scrive il numero che decide.
- Giorni 4-8: il file OpenAPI. Si attiva la generazione, si dà un nome di operazione a ogni endpoint, si dichiarano i codici di errore. Si pubblica il file così com'è, su un indirizzo interno.
- Giorni 9-12: la descrizione degli endpoint. Per i dieci endpoint più usati, un riassunto, una descrizione che dice la regola e un esempio. Gli altri 66 restano come sono. Di solito la gran parte delle domande riguarda una piccola parte degli endpoint.
- Giorni 13-16: la prima chiamata. Una pagina, una richiesta copiabile, una risposta attesa, un ambiente di prova. La si fa provare a una persona che non conosce le API.
- Giorni 17-20: il catalogo degli errori. La tabella con codice, causa, colpa e rimedio. Si sostituiscono gli errori muti con Problem Details nei dieci endpoint più usati.
- Giorni 21-24: il controllo delle modifiche. Il file approvato nel repository, il test del contratto, il passo con oasdiff nella pipeline.
- Giorni 25-28: le guide. Le due o tre guide che corrispondono alle domande più frequenti: creare un ordine, seguirne lo stato, gestire un timeout.
- Giorni 29-30: la pubblicazione. Il sito della documentazione, l'indirizzo, il registro delle modifiche. Si manda il link ai cinque soggetti che già usano le API, con una riga: "da oggi la documentazione è qui, e si aggiorna a ogni rilascio".
Il piano di ritorno costa poco: tutto è in file di testo nel repository e non cambia il comportamento dell'API. Se il piano si ferma al giorno 12, hai già un file generato e dieci endpoint descritti, cioè la strada C della tabella.
Una nota sulle persone, che pesa più del codice. Prima di cominciare, chiedi ai due programmatori che rispondono più spesso ai partner di scrivere, a mano libera, le cinque domande che si sentono fare di più. È il sommario della documentazione, e di solito è migliore di quello che avresti progettato a tavolino. Poi, tre mesi dopo il rilascio, rifai il conteggio: se le richieste non sono scese di almeno la metà, qualcosa non è stato scritto dove le persone guardano.
Quali errori evitare quando si documenta un'API?
Gli errori che vedo più spesso, e che costano di più, sono otto.
- Scrivere il documento a mano, separato dal codice. Dopo tre rilasci è sbagliato, e le persone smettono di fidarsi anche delle parti giuste.
- Documentare tutto allo stesso livello. Settantasei endpoint descritti con la stessa cura significano dieci descritti male. Si cura la piccola parte che genera la maggior parte delle domande.
- Descrizioni che ripetono il nome. "CreaOrdine: crea un ordine". Non aggiunge niente. Scrivi la regola, il vincolo, il caso strano.
- Non dichiarare gli errori. Il file mostra solo il successo, e l'integratore scopre i casi di fallimento in produzione.
- Esempi che non funzionano. Un esempio copiato da un ambiente vecchio, con un campo che non esiste più, è peggio di nessun esempio. Gli esempi vanno provati in pipeline come qualsiasi altro codice.
- Rompere il contratto di nascosto. Togliere un campo "perché nessuno lo usa" senza controllare. Si controlla con un test, non con la memoria.
- Esporre la prova in linea su produzione. Un partner curioso crea un ordine vero. Solo ambiente di prova, solo chiavi di prova.
- Comprare un portale prima di avere il contenuto. Il canone parte subito, le pagine restano vuote, e l'integratore trova un'interfaccia elegante senza risposte.
Una regola le riassume tutte: la documentazione è parte del rilascio, non un'attività a fianco. Se una modifica all'API passa in produzione senza toccare la documentazione, la pipeline deve fermarla. È più facile di quanto sembri, e dopo il primo mese nessuno ci pensa più.
Quando conviene non documentare?
Succede spesso, ed è una buona notizia. Ci sono tre situazioni in cui spendere per una documentazione completa non conviene, e te le dico apertamente.
- L'API è interna a un solo team. Chi la scrive è anche chi la usa, e chi la usa siede nella stanza accanto. Qui il file generato e un README bastano, e sono gratis.
- Una sola integrazione, già in produzione, che non cambia. Il costo del silenzio è quasi zero. Una pagina con le regole di autenticazione e gli errori salva da molti guai.
- L'API sta per sparire. Se in dodici mesi la sostituirai con un prodotto, investi nel piano di spegnimento e basta.
In ognuno di questi casi c'è un minimo che conviene fare comunque, e costa poche ore: il file OpenAPI generato e pubblicato, un elenco scritto delle chiavi emesse e di chi le usa, e una pagina con l'indirizzo dell'ambiente di prova. Sono 8-10 ore di lavoro e tolgono il rischio peggiore, quello di avere un'API che solo una persona sa spiegare.
Se sei arrivato fin qui, probabilmente hai in mente un preventivo di portale, o un partner che aspetta una risposta da due settimane. Prima di decidere, prendi i tuoi numeri: richieste al mese, giornate di affiancamento, rotture all'anno. Mezza giornata, e sai in quale zona della regola ti trovi.
Se vuoi un secondo sguardo sul tuo caso, la strada è la consulenza software. E quando la soluzione giusta è un sistema costruito attorno al tuo modo di lavorare, con API pensate fin dall'inizio per chi dovrà integrarle, lo trovi spiegato nella pagina sul software su misura. Se il tuo problema è collegare il gestionale a un negozio online, ne parlo nella guida all'integrazione fra gestionale ed e-commerce. Sul tema delle scelte di architettura che si pagano per anni, c'è quando serve davvero il pattern CQRS.
Domande frequenti
Per un'azienda con 40 persone, 76 endpoint e 8 nuove integrazioni all'anno, circa 29.520 euro l'anno: 15.120 euro di richieste di supporto, 11.520 euro di affiancamento ai partner e 2.880 euro per le modifiche che rompono un'integrazione. In tre anni sono circa 88.560 euro.
È lo standard che descrive un'API REST in un file leggibile da persone e da programmi: indirizzi, parametri, forme di richiesta e risposta, errori e autenticazione. Da quel file si ricavano le pagine di consultazione, i client in vari linguaggi, i test del contratto e le collezioni per Postman.
Dal .NET 9 sì: il pacchetto Microsoft.AspNetCore.OpenApi produce il file dall'applicazione, con AddOpenApi e MapOpenApi. Non descrive il perché delle regole né la prima chiamata: quelle parti vanno scritte e tenute nello stesso repository del codice.
Per 8 integrazioni l'anno no: nel caso dell'azienda tipo costa circa 59.556 euro in tre anni contro 32.940 della strada dal codice con esempi e controllo, perché il canone non elimina il lavoro di scrivere i contenuti. Ha senso con centinaia di partner esterni e chiavi emesse in autonomia.
Con un test che confronta il file OpenAPI generato con quello approvato nel repository, e con uno strumento come oasdiff che segnala le modifiche incompatibili e ferma la pipeline. Le modifiche che rompono si fanno in una nuova versione, con le intestazioni Deprecation e Sunset.
Quando è interna a un solo team, quando c'è una sola integrazione stabile, o quando sta per essere sostituita entro dodici mesi. Il minimo da fare comunque è pubblicare il file OpenAPI generato, tenere un elenco delle chiavi emesse e indicare l'ambiente di prova.
