API Platform in Symfony 7: REST API per integrazioni B2B
Un'integrazione B2B vive o muore sulla qualità e sulla stabilità della sua API. Quando un partner collega il suo sistema al tuo, costruisce il suo codice attorno alla forma esatta delle tue risposte, e da quel momento tu hai una responsabilità che non avevi con un'interfaccia web: non controlli più il calendario di chi consuma i tuoi dati. Cambi il nome di un campo, ne rimuovi uno che credevi inutile, e il client di un partner si rompe in produzione, senza che tu te ne accorga finché non arriva la telefonata. In un progetto di piattaforma di procurement per un'azienda con una rete capillare di filiali, dove decine di sistemi esterni si agganciavano alle stesse API, questo era il rischio quotidiano: una modifica innocua per noi era un guasto per loro. API Platform, il framework per costruire API su Symfony, dà moltissimo gratis, ma la stabilità di un'integrazione B2B non è un regalo del framework, è una disciplina che ci metti tu. Vediamo come costruire REST API solide con API Platform su Symfony 7: la definizione delle risorse, il controllo fine della serializzazione, il versioning che protegge i partner, la sicurezza degli endpoint e la documentazione generata.
Cosa ti dà API Platform gratis, e perché è tanto
Il valore di API Platform è la quantità di lavoro che ti toglie. Dichiari una classe come risorsa API, tipicamente con l'attributo #[ApiResource], e ottieni automaticamente un set completo di endpoint REST (e, se vuoi, GraphQL) per le operazioni di lettura e scrittura, con paginazione, filtri, negoziazione del contenuto e gestione degli errori già pronti. In più, e questo per il B2B è oro, genera automaticamente la documentazione OpenAPI, l'interfaccia Swagger interattiva che descrive ogni endpoint, ogni parametro e ogni formato di risposta.
Per un'integrazione B2B questa produttività ha un valore doppio. Da un lato ti fa partire in fretta, con un'API che rispetta gli standard invece di una collezione di endpoint inventati. Dall'altro ti dà gratis l'artefatto su cui i partner costruiranno: la documentazione. Costruire la stessa cosa a mano, endpoint per endpoint, con la sua documentazione mantenuta a parte, è settimane di lavoro che API Platform comprime in ore. Il rischio, però, è scambiare questa facilità per completezza: generare un'API non significa aver progettato un'integrazione B2B, e la differenza sta tutta in ciò che il framework non fa al posto tuo.
Il controllo fine della serializzazione: i gruppi
La prima cosa che il framework non decide per te, ed è la più importante, è cosa esattamente esporre. Il default ingenuo è serializzare l'intera entità, con tutte le sue proprietà, comprese quelle interne che un partner non deve vedere e non deve poter modificare. È un errore di sicurezza e di stabilità insieme: esponi più di quanto serve, e ogni campo esposto diventa un contratto che dovrai mantenere. La risposta di API Platform sono i gruppi di serializzazione, che ti permettono di controllare con precisione quali campi entrano in lettura e quali in scrittura, per ciascuna operazione.
#[ApiResource(
normalizationContext: ['groups' => ['order:read']],
denormalizationContext: ['groups' => ['order:write']],
)]
class Order
{
#[Groups(['order:read'])]
public int $id;
#[Groups(['order:read', 'order:write'])]
public string $reference;
#[Groups(['order:read', 'order:write'])]
public float $amount;
// interno: non esposto a nessun partner, né in lettura né in scrittura
public string $internalNotes;
}Con questo controllo, l'API espone solo ciò che hai deciso esplicitamente, e ogni campo nella risposta è una scelta consapevole, non un effetto collaterale. È la stessa logica di allow-list che applico ovunque ci sia un confine di fiducia: si dichiara cosa è permesso e si tace tutto il resto. Questo è anche il primo presidio di stabilità, perché meno campi esponi, meno superficie di contratto dovrai mantenere stabile nel tempo. I dettagli di generazione di REST e GraphQL li ho descritti parlando di API Platform per generare API REST e GraphQL da Doctrine.
Se stai costruendo un'integrazione B2B e vuoi che la tua API sia solida e non si trasformi in un campo minato di modifiche che rompono i partner, nel mio profilo professionale trovi l'esperienza concreta su architetture API e piattaforme di integrazione per il mercato europeo.
Il versioning: il vincolo che protegge i partner
Questo è il cuore di un'integrazione B2B seria, ed è ciò che distingue un'API pubblica da un endpoint interno. Poiché non controlli quando i partner aggiornano il loro codice, non puoi cambiare la forma di una risposta esistente senza rischiare di romperli.
In un'API interna sei tu a deployare client e server insieme: se cambi un campo, aggiorni entrambi nello stesso commit. In un'API B2B il client è di qualcun altro, su un altro server, con un altro calendario di rilascio. La forma della tua risposta non è più una scelta privata, è un contratto pubblico.
La regola d'oro è che le modifiche all'API devono essere additive: aggiungere un campo nuovo è sicuro, perché un client che non lo conosce semplicemente lo ignora; rimuovere o rinominare un campo, cambiare il tipo o la semantica di uno esistente, è un breaking change che va gestito con il versioning.
La strategia di versioning, che sia nel percorso dell'URL o in un header, serve esattamente a questo: permettere all'API di evolvere senza obbligare tutti i partner a cambiare nello stesso istante. Pubblichi la versione nuova, lasci la vecchia in funzione con una policy di deprecazione chiara (questa versione sarà supportata fino a una certa data, poi ritirata), e dai ai partner il tempo di migrare. Senza questo, ogni evoluzione dell'API è una scommessa sulla pazienza dei tuoi clienti. Le strategie pratiche di versioning e compatibilità le ho dettagliate parlando di versioning delle API e backward compatibility: i principi valgono identici in Symfony con API Platform.
La sicurezza degli endpoint, operazione per operazione
Un'API B2B è una porta sui tuoi dati, e va protetta operazione per operazione, non in blocco. API Platform permette di applicare regole di sicurezza per singola operazione, tipicamente con espressioni nell'attributo della risorsa, così che la lettura possa avere requisiti diversi dalla scrittura, e un partner possa accedere solo a ciò che gli compete.
#[ApiResource(
operations: [
new Get(security: "is_granted('ROLE_PARTNER')"),
new Post(security: "is_granted('ROLE_PARTNER_WRITE')"),
]
)]
class Order { /* ... */ }I principi sono quelli di sempre, applicati al contesto B2B: nessuna operazione di scrittura senza autenticazione, autorizzazione granulare in modo che un partner veda solo i propri dati e non quelli di un altro, e rate limiting per impedire che un client mal configurato o malevolo saturi l'API. L'autenticazione B2B passa tipicamente per token API o OAuth2, e va trattata con la stessa serietà di sicurezza di qualunque altro punto di accesso, perché un'API B2B compromessa è una falla che attraversa i confini aziendali. Questo è anche il terreno delle architetture di integrazione più complesse, come un gateway B2B che fa da ponte tra Symfony e servizi esterni.
La documentazione generata è un asset B2B, non un accessorio
Un aspetto che si tende a sottovalutare: per un'integrazione B2B, la documentazione è il contratto. È il documento contro cui il partner scrive il suo codice, ed è la prima cosa che guarda quando qualcosa non funziona. API Platform genera automaticamente la specifica OpenAPI e l'interfaccia Swagger, e questo è un vantaggio competitivo reale, perché una documentazione sempre allineata al codice elimina la classe di problemi più frustrante delle integrazioni: la documentazione che mente, che descrive un'API diversa da quella reale. Mantenere accurata questa documentazione, arricchendola con descrizioni e esempi attraverso gli attributi, non è cosmesi: è ridurre l'attrito di ogni partner che si integra, e ridurre le richieste di supporto. Una buona documentazione generata trasforma un'integrazione da una serie di email di chiarimento in un processo self-service.
Filtri e paginazione: ciò che un partner ti chiederà subito
Un dettaglio pratico che emerge appena un'integrazione B2B entra in produzione è che il partner non vuole scaricare tutto, vuole interrogare sottoinsiemi: gli ordini di un certo periodo, le fatture di un certo stato, i prodotti aggiornati dopo una certa data per sincronizzarsi in modo incrementale. API Platform copre anche questo gratis, con un sistema di filtri dichiarativi (per ricerca esatta o parziale, per intervallo di date, per ordinamento) che si attivano con attributi sulla risorsa e diventano automaticamente parametri di query documentati.
#[ApiResource]
#[ApiFilter(DateFilter::class, properties: ['updatedAt'])]
#[ApiFilter(SearchFilter::class, properties: ['status' => 'exact'])]
class Order { /* ... */ }Con poche righe, il partner può chiedere "tutti gli ordini aggiornati dopo ieri con stato sent" e ricevere esattamente quelli, paginati. La paginazione, anch'essa di default, è la sua compagna necessaria: senza, un partner che chiede una risorsa con milioni di righe metterebbe in ginocchio la tua API e la sua. Su questo vale la pena ragionare per tempo: una paginazione a offset va bene per i casi comuni, ma per le sincronizzazioni incrementali su grandi volumi conviene esporre un filtro per data o per cursore, così il partner scarica solo il delta dall'ultima sincronizzazione invece di ripaginare l'intero dataset ogni volta. È la differenza tra un'integrazione che scala con i dati e una che diventa più lenta a ogni riga aggiunta, e prevederla in fase di progettazione costa pochissimo, mentre aggiungerla dopo, su un'API già in uso da partner, ricade nel problema del versioning.
Quando API Platform è la scelta giusta, e quando no
API Platform brilla quando la tua API espone un modello di dominio in modo sostanzialmente orientato alle risorse: entità che si leggono, si creano, si aggiornano e si cancellano, con relazioni e filtri. Lì la sua convenzione ti fa risparmiare moltissimo e ti regala standard e documentazione. È meno naturale, invece, quando la tua API è fortemente orientata alle azioni o RPC: una serie di operazioni che non corrispondono a un semplice CRUD su una risorsa, ma a comandi specifici con logiche proprie. Lì forzare tutto nel modello a risorse di API Platform può produrre più attrito che beneficio, e a volte un controller scritto a mano, esplicito, è più chiaro.
La regola che applico è non avere ideologie: API Platform per la parte dell'API che è genuinamente orientata alle risorse, controller espliciti per le operazioni che sono genuinamente azioni. I due approcci convivono benissimo nello stesso progetto Symfony, e scegliere caso per caso è meglio che piegare ogni endpoint a un solo paradigma. La domanda da farsi per ogni endpoint è: questo è "una risorsa che manipolo" o "un'azione che eseguo"? La risposta indica lo strumento, e mescolare i due approcci nello stesso progetto non è un'incoerenza, è il segno che stai scegliendo lo strumento giusto per ogni pezzo invece di piegare tutto a un dogma.
Un cambio all'API può davvero rompere il client di un partner?
Sì, e in silenzio, ed è la cosa più importante da interiorizzare di tutto questo discorso. Un partner ha scritto il suo codice assumendo che la tua risposta abbia un certo campo con un certo nome e un certo tipo. Il giorno in cui rinomini quel campo, il suo parser non lo trova più, e a seconda di come è scritto il suo codice o va in errore o, peggio, continua silenziosamente con un valore mancante. Tu non vedi nulla, perché il tuo sistema funziona; il guasto è dalla sua parte. Ecco perché la disciplina del B2B è non negoziabile: modifiche solo additive sulle versioni esistenti, breaking change solo dietro una nuova versione, deprecazione comunicata con anticipo. Non è burocrazia, è il rispetto del fatto che qualcun altro dipende da te e non puoi cambiargli il pavimento sotto i piedi senza avvisarlo.
Tirando le somme, API Platform su Symfony 7 è uno strumento potente per costruire le API di un'integrazione B2B, ma il suo regalo, la generazione automatica, è metà del lavoro, non tutto. La parte che fa la differenza è la disciplina che ci aggiungi: esporre con i gruppi di serializzazione solo ciò che hai deciso, proteggere ogni operazione con la sua regola di sicurezza, trattare il versioning come un patto con i partner e non come un dettaglio tecnico, e curare la documentazione generata come il contratto che effettivamente è. API Platform ti porta al traguardo della "API che funziona" in una frazione del tempo; portarla al traguardo della "API B2B su cui un partner può costruire per anni" è il lavoro ingegneristico che resta, e che nessun framework fa al posto tuo. Se stai costruendo o mantenendo un'integrazione B2B e vuoi che la tua API sia abbastanza stabile da non rompere i partner a ogni evoluzione, contattami per una consulenza diretta: nella mia esperienza, la differenza tra un'integrazione che dura per anni e una che genera continue emergenze sta quasi tutta nelle scelte di progettazione che il framework ti lascia, giustamente, fare da solo.