Sviluppo di API

Gli API rappresentano il limite HTTP di un servizio Lino. Espongono casi d'uso a livello di applicazione senza mescolare le preoccupazioni di trasporto con le regole di dominio. Questo capitolo spiega come Lino genera API minimi, contratti di richiesta/risposta, typed clients, metadati OpenAPI e registrazione automatica degli endpoint da parte dei source generators.


L'endpoint generato deve rimanere in buone condizioni: riceve i dati HTTP, assembla un comando o una query, lo invia al livello Applicazione tramite ISender e converte il risultato in una risposta digitata. La convalida, le regole aziendali, la persistenza, le transazioni e l'autorizzazione del dominio continuano nei comandi, nelle query, nei gestori, nei validatori, nei repository e nell'Unità di Lavoro.

API minimi su Lino

Lino adotta il nucleo ASP.NET API minimi come standard per la generazione di endpoint, perché mantengono il codice diretto, esplicito e performante senza superare i limiti di Clean Architecture.

Negli attuali progetti Lino, gli endpoint generati sono classi Minimal API che implementano IEndpoint. Ogni endpoint espone un metodo statico MapEndpoint(IEndpointRouteBuilder app) e un metodo di gestione che utilizza ISender per inviare il comando o la query generati al livello Applicazione.

Parti principali generate

  • *Endpoint.cs: metodo mappa HTTP, percorso, metadati, autorizzazione, requisiti del tenant, limitazione della velocità e versione.
  • *Request.cs: rappresenta l'input proveniente dal corpo, dalla stringa di query, dai parametri del percorso o dai dati del modulo.
  • *Extensions.cs: converte la richiesta in comando/query e converte il risultato dell'applicazione nella risposta HTTP.
  • *Response.cs: definisce il contratto fortemente tipizzato restituito dall'endpoint e dai typed clients.

Funzionalità integrate

Lino utilizza TypedResults E Results<...> in modo che le risposte di successo ed errore siano esplicite nel codice e vengano visualizzate correttamente in OpenAPI. I guasti provenienti dal livello Applicazione vengono convertiti in ProblemDetails Mettere result.MapToProblemDetails().

  • WithTags: raggruppa gli endpoint per modulo, entità o funzionalità in OpenAPI e Scalar.
  • WithName: imposta un OperationId coerente quando applicabile.
  • WithSummary: descrive chiaramente lo scopo dell'endpoint.
  • Produces(statusCode, schema): specifica i codici di stato e i contratti di risposta.
  • MapToApiVersion(1, 0): associa l'endpoint alla versione API.
  • RequirePermission, RequireAuthorization, AllowAnonymous E RequireTenant: applica la sicurezza in base alle opzioni del progetto.
  • Limitazione della velocità a livello di gruppo o endpoint, utilizzando policy autenticate o anonime a seconda della configurazione.

Richieste e risposte

Per impostazione predefinita, Lino utilizza record per richieste e risposte. Sono concisi, immutabili per impostazione predefinita e funzionano bene come contratti espliciti tra API, typed clients e consumatori esterni.

  • Le richieste ricevute tramite endpoint vengono trasformate in comandi o query.
  • I risultati dei comandi o delle query vengono convertiti in risposte.
  • Le entità di dominio non devono essere esposte direttamente come contratto HTTP.
public record CreatePersonRequest(string Name, int Age);
public record CreatePersonResponse(Guid Id, string Name, int Age);

Creazione di nuovi API

Crea API da CLI quando il modello di dominio e il caso d'uso sono già sufficientemente chiari per essere esposti da HTTP. Gli API collegano comandi e query al livello di presentazione tramite API minimi, contratti, risposte digitate e metadati della documentazione.

lino api new
lino api new --name <ApiName> --service <ServiceName> --module <ModuleName> --entity <EntityName>
lino api list --service <ServiceName> --module <ModuleName> --entity <EntityName>

La procedura guidata interattiva richiederà:

  • Servizio: servizio in cui verrà creato API.
  • Modulo: modulo di servizio, quando applicabile.
  • Entità o enumerazione: elemento di dominio associato all'endpoint.
  • Nome di API: normalmente allineato al verbo dell'operazione, come CreatePerson.
  • Tipo di operazione: GET, POST, PUT, PATCH, DELETE, caricamento, download o opzioni endpoint.
  • Itinerario:modello di percorso, come /people/{id:guid}.
  • Proprietà: campi di richiesta e risposta che devono effettivamente oltrepassare il confine HTTP.

Cosa può configurare la procedura guidata

  • OTTENERE: risultato singolo, elenco, elenco impaginato e opzioni/seleziona scenari.
  • INVIARE: creazione e azioni aziendali, incluso il tipo di comando e le proprietà selezionate.
  • METTERE E TOPPA: aggiornamento completo o parziale.
  • ELIMINARE: rimozione mappata per eliminare i comandi.
  • Caricamento: endpoint con IFormFile E DisableAntiforgery() quando necessario.
  • Scaricamento:restituisce endpoint FileStreamHttpResult; I progetti autenticati possono generare endpoint token per l'accesso sicuro ai file.
  • Enumerazioni: endpoint che espongono opzioni valide per query e risposta generate.

Flusso consigliato

  1. Crea o rivedi l'entità, i comandi e le query che rappresentano il caso d'uso.
  2. Correre lino api new e seleziona il servizio, il modulo e l'entità corretti.
  3. Scegli il tipo di operazione in base al caso d'uso, non solo in base al verbo HTTP desiderato.
  4. Definire un percorso stabile, utilizzando vincoli come {id:int} O {id:guid} quando appropriato.
  5. Seleziona solo le proprietà che devono oltrepassare il confine HTTP.
  6. Definire l'autorizzazione, il permesso, i requisiti dell'affittuario, i limiti di tariffa e i codici di stato previsti.
  7. Esegui build e ispeziona Scalar/OpenAPI per confermare il percorso, il riepilogo, la versione, la sicurezza e le risposte prodotte.

Esempio: CreaPersona

Quando crei un file API POST chiamata CreatePerson, associato all'entità Person, CLI genera endpoint, contratti di richiesta/risposta, estensioni di mappatura, metadati OpenAPI e integrazione con il comando corrispondente.

<ProjectName>/
└── src/
    └── Services/
        └── <ServiceName>/
            └── Api/
                └── Endpoints/
                    └── People/
                        └── CreatePerson/
                            ├── CreatePersonEndpoint.cs
                            ├── CreatePersonExtensions.cs
                            ├── CreatePersonRequest.cs
                            └── CreatePersonResponse.cs

Contratti e clienti tipizzati

Quando il progetto dispone di un'app Web Blazor, Lino genera anche artefatti per il consumo digitato di API: contratti condivisi, interfaccia client e implementazione HTTP. Ciò consente a Blazor di utilizzare gli endpoint in modo semplice, coerente e fortemente tipizzato.

<ProjectName>/
└── src/
    └── Services/
        └── <ServiceName>/
            ├── Api.Contracts/
            │   └── Features/
            │       └── People/
            │           ├── CreatePerson/
            │           │   ├── CreatePersonRequest.cs
            │           │   └── CreatePersonResponse.cs
            │           └── IPersonApiClient.cs
            └── Api.Client/
                └── Features/
                    └── PersonApiClient.cs

L'interfaccia client è registrata per l'inserimento delle dipendenze e l'implementazione utilizza HttpClientProvider con gli helper HTTP di Tolitech per chiamare il API generato in modo fortemente tipizzato.

Lista di controllo prima della pubblicazione

  • Utilizzo GET per leggere, POST per creazione/azioni, PUT/PATCH per il cambiamento e DELETE per la rimozione quando ha senso.
  • Non esporre le entità di dominio direttamente come contratto esterno.
  • Errori di convalida del documento, conflitto, non trovato e accesso negato.
  • Utilizzo api list per evitare percorsi duplicati o endpoint concorrenti per lo stesso caso d'uso.

Registrazione degli endpoint con source generators

Lino evita la mappatura manuale di file di grandi dimensioni utilizzando source generators. Invece di elencare gli endpoint uno per uno in Program.cs, il log viene prodotto durante la compilazione.

Implementazione delle classi endpoint generate IEndpoint Di Tolitech.MinimalApis.Generators.Abstractions. Il gruppo endpoint chiama MapEndpointsGenerated(), prodotto da Tolitech.MinimalApis.Generatorse i nuovi endpoint vengono registrati dal codice generato.

Perché è importante?

  • Meno cablaggio manuale: gli sviluppatori non devono ricordarsi di mappare manualmente ciascun endpoint.
  • Coerenza in fase di compilazione: gli endpoint seguono la stessa struttura e vengono scoperti dal codice generato.
  • Avvio più pulito: Program.cs impostazione dei delegati per la configurazione di servizi, middleware e metodi di estensione.
  • Compatibilità AOT: riduce la dipendenza dalla riflessione in fase di esecuzione.
  • OpenAPI coerente: tag, riepiloghi, codici di stato e versione vengono generati sull'endpoint.
  • Allineamento architettonico: HTTP si trova in API, l'orchestrazione passa attraverso MediatR e i contratti possono essere condivisi con i clienti.

Flusso in fase di esecuzione

  1. Program.cs crea l'applicazione e chiama l'estensione dagli endpoint del servizio o del modulo.
  2. L'interno crea il set di versioni API e il gruppo di endpoint, applica autorizzazioni/limitazioni di velocità e chiama MapEndpointsGenerated().
  3. Il mapper generato chiama il metodo MapEndpoint di ciascun endpoint.
  4. Ogni endpoint mappa il percorso, i metadati OpenAPI, l'autorizzazione, i requisiti del tenant e il gestore.
  5. Il gestore riceve l'input HTTP, lo converte in comando/query, lo invia a MediatR e restituisce un risultato digitato.

Definizioni degli errori

Le definizioni degli errori standardizzano gli errori noti del dominio e dell'applicazione. Aiutano API, gestori, log e frontend a gestire problemi prevedibili senza fare affidamento su messaggi vaganti, stringhe duplicate o decisioni ad hoc su ciascun endpoint.

lino error-definition new --name <ErrorDefinitionName> --service <ServiceName> --module <ModuleName> --entity <EntityName>
lino error-definition list --service <ServiceName> --module <ModuleName> --entity <EntityName>

Negli API generati, è necessario convertire gli errori previsti restituiti dai comandi e dalle query ProblemDetails con codice di stato, codice di errore e messaggio sicuro. Il server può registrare registri tecnici dettagliati, ma la risposta HTTP deve rimanere coerente, sicura e localizzabile.

StatoUtilizzo tipicoEsempio
400 Richiesta errataInput non valido o errore di convalida.Campo obbligatorio mancante, formato non valido, regola di richiesta non funzionante.
401 Non autorizzatoUtente non autenticato.Token mancante, scaduto o non valido.
403 ProibitoUtente autenticato senza autorizzazione.Autorizzazione richiesta da RequirePermission non concesso.
404 Non trovatoRisorsa inesistente o fuori dall'ambito consentito.ProductNotFound, entità di un altro tenant o identificatore sconosciuto.
409 ConflittoConflitto di stato o regola di unicità.Record duplicato, transizione non valida, conflitto di versione.

Buone pratiche

  • Creare definizioni di errore per errori previsti e riutilizzabili.
  • Evitare di restituire eccezioni tecniche o dettagli dell'infrastruttura al cliente.
  • Mantieni codici di errore stabili in modo che frontend, typed clients e test possano reagire in sicurezza.
  • Documentare in OpenAPI i codici di stato che l'endpoint può produrre.
  • Utilizza i log lato server per i dettagli diagnostici e i messaggi protetti nella risposta pubblica.
Si è verificato un errore non gestito. Ricarica 🗙