Le API minimali sono una funzionalità entusiasmante introdotta in .NET 6, progettata per rivoluzionare il modo in cui crei le API.
Immagina di costruire API robuste con un codice minimo e zero boilerplate—nessuna lotta con i controller, il routing o il middleware. Questo è ciò che le API minimali ti permettono di fare. L’idea con queste API è di semplificare il processo di sviluppo, rendendolo incredibilmente facile ed efficiente.
In questo articolo, esploreremo il mondo delle API minimali in .NET 8 e ti guideremo nella creazione di un’API completamente funzionante per una libreria. Imparerai come ottenere tutti i libri, recuperare un libro tramite il suo ID, aggiungere nuovi libri e persino eliminare libri. Iniziamo.
Indice dei Contenuti
Prerequisiti
Prima di iniziare, assicurati di avere i seguenti prerequisiti installati sulla tua macchina:
-
Visual Studio Code o qualsiasi altro editor di codice a tua scelta
-
C# Dev Kit per Visual Studio Code
In alternativa, puoi usare Visual Studio 2022, che include il supporto integrato per .NET 8. Ma in questo articolo, utilizzeremo Visual Studio Code. È leggero, facile da usare e multipiattaforma.
Utilizzeremo Swagger UI per testare la nostra API. Swagger UI è uno strumento potente che ti permette di interagire con la tua API direttamente dal browser. Fornisce un’interfaccia utente intuitiva per testare i tuoi endpoint API, facilitando il test e il debug della tua API.
Quando crei un nuovo progetto, installerà automaticamente i pacchetti necessari e configurerà il progetto per utilizzare Swagger UI. .NET 8 include Swagger UI di default, quindi che tu crei la tua applicazione in Visual Studio o con .NET, Swagger UI sarà configurato per te.
Esegui la tua applicazione e Swagger UI si aprirà automaticamente nel tuo browser – ma poiché stiamo usando VS Code, dobbiamo cliccare sul numero di porta nel nostro terminale.
Puoi trovare il codice sorgente per questo progetto su GitHub.
Introduzione alle API Minime
Immagina di lavorare in un codebase con numerosi endpoint, rendendolo piuttosto grande e complesso. Tradizionalmente, costruire un’API in ASP.NET Core comporta l’uso di controller, routing, middleware e una quantità significativa di codice boilerplate. Ma ci sono due approcci per costruire un’API in ASP.NET Core: il modo tradizionale e il modo minimale.
Il modo tradizionale è familiare alla maggior parte degli sviluppatori, coinvolgendo controller e un’ampia infrastruttura di codice. Il modo minimale, introdotto in .NET 6
, ti permette di creare API con un codice minimo e zero boilerplate. Questo approccio semplifica il processo di sviluppo, permettendoti di concentrarti sulla scrittura della logica aziendale piuttosto che affrontare il codice infrastrutturale.
Le API minime sono leggere, veloci e perfette per costruire API di piccole e medie dimensioni. Sono ideali per la prototipazione, la costruzione di microservizi o la creazione di API semplici che non richiedono molta complessità. In questo manuale, esploreremo il mondo delle API minime in .NET 6 e impareremo a creare un’API di libreria completamente funzionante da zero.
Come Creare un’API Minima
Creare un’API minima è semplice quando si utilizza il dotnet CLI
, poiché il template predefinito è già un’API minima. Ma se usi Visual Studio, dovrai rimuovere il codice boilerplate che viene con il template del progetto.
Iniziamo utilizzando il dotnet CLI
per creare un progetto di API minimale.
dotnet new webapi -n BookStoreApi
Il comando dotnet new webapi
crea un nuovo progetto di API minimale chiamato BookStoreApi
. Questo progetto contiene i file e le cartelle necessari per iniziare.
Esploriamo la struttura del progetto:
-
Program.cs
: Il punto di ingresso dell’applicazione, dove viene configurato l’host. -
bookapi-minimal.sln
: Il file della soluzione che contiene il progetto. -
bookapi-minimal.http
: Un file che contiene richieste HTTP di esempio per testare l’API. -
bookapi-minimal.csproj
: Il file del progetto che contiene la configurazione del progetto. -
appsettings.json
: Il file di configurazione che archivia le impostazioni dell’applicazione. -
appsettings.Development.json
: Il file di configurazione per l’ambiente di sviluppo.
Quando apri il file program.cs, noterai che il codice è minimale. Il file Program.cs
contiene il seguente codice:
var builder = WebApplication.CreateBuilder(args);
// Aggiungi servizi al container.
// Ulteriori informazioni sulla configurazione di Swagger/OpenAPI su https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
// Configura il pipeline delle richieste HTTP.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
var summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
app.MapGet("/weatherforecast", () =>
{
var forecast = Enumerable.Range(1, 5).Select(index =>
new WeatherForecast
(
DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
Random.Shared.Next(-20, 55),
summaries[Random.Shared.Next(summaries.Length)]
))
.ToArray();
return forecast;
})
.WithName("GetWeatherForecast")
.WithOpenApi();
app.Run();
record WeatherForecast(DateOnly Date, int TemperatureC, string? Summary)
{
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
}
Se non capisci ancora completamente il codice, non preoccuparti—lo esamineremo in dettaglio nelle sezioni successive. Il punto chiave è che le API minimali richiedono pochissimo codice, il che è uno dei loro principali vantaggi.
Il codice predefinito configura un’API semplice per le previsioni meteorologiche che puoi utilizzare per testare la tua configurazione. Genera un elenco di previsioni meteorologiche e le restituisce quando effettui una richiesta GET
all’endpoint /weatherforecast
. Inoltre, il codice include Swagger UI per aiutarti a testare l’API.
Presta particolare attenzione al metodo app.MapGet
, che mappa una rotta a una funzione di gestione. In questo caso, mappa la rotta /weatherforecast
a una funzione che restituisce un elenco di previsioni meteorologiche. Utilizzeremo metodi simili per creare i nostri endpoint nelle sezioni successive.
Prima di iniziare a creare la struttura delle cartelle del nostro progetto, comprendiamo i metodi HTTP sia nelle API basate su Controller che nelle API Minimali.
Metodi HTTP nelle API basate su Controller e nelle API Minimali
In un approccio basato su Controller, che è il modo tradizionale di creare web API, devi creare una classe di controller e definire metodi per ciascun metodo HTTP. Ad esempio:
-
Per creare un metodo
GET
, si utilizza l’attributo[HttpGet]
. -
Per creare un metodo
POST
, si utilizza l’attributo[HttpPost]
. -
Per creare un metodo
PUT
, si utilizza l’attributo[HttpPut]
. -
Per creare un metodo
DELETE
, si utilizza l’attributo[HttpDelete]
.
Questo è come vengono creati gli endpoint in un approccio basato su Controller.
Invece, le API Minimal utilizzano metodi come app.MapGet
, app.MapPost
, app.MapPut
e app.MapDelete
per creare endpoint. Questa è la principale differenza tra i due approcci: le API basate su Controller utilizzano attributi per definire gli endpoint, mentre le API Minimal utilizzano metodi.
Ora che sai come gestire le richieste HTTP sia nelle API basate su Controller che nelle API Minimal, creiamo la struttura della cartella del nostro progetto.
Prima di creare la nostra struttura di cartelle del progetto, eseguiamo prima ciò che abbiamo. Come abbiamo appreso in precedenza, quando si crea un progetto con Visual Studio o .NET CLI, viene fornito con un progetto WeatherForecast predefinito che possiamo eseguire e vedere sull’UI. Eseguiamolo per assicurarci che tutto funzioni prima di procedere con la creazione della nostra cartella del progetto.
Esegui questo comando:
dotnet run
Dovresti vedere il seguente output:
info: Microsoft.Hosting.Lifetime[14]
Now listening on: http://localhost:5228
info: Microsoft.Hosting.Lifetime[0]
Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
Hosting environment: Development
info: Microsoft.Hosting.Lifetime[0]
Content root path: D:\Devolopemnt\Dotnet\bookapi-minimal
Questo significa che l’applicazione è in esecuzione e in ascolto su http://localhost:5228
. Come ho menzionato sopra, poiché stiamo utilizzando il dotnet CLI
e Visual Studio Code, l’applicazione non aprirà automaticamente il browser per noi. Dobbiamo farlo manualmente.
Apri il tuo browser e naviga su http://localhost:5228/swagger/index.html
per vedere la risposta predefinita dall’API.
Dovresti vedere qualcosa del genere:
Ora la prossima cosa che dobbiamo fare è trovare un modo per strutturare il nostro progetto e creare i file e le cartelle necessari per iniziare.
File del Progetto API Minimale
Per organizzare il nostro progetto, creeremo una gerarchia di cartelle strutturata. Questo ci aiuterà a mantenere il nostro codice pulito e manutenibile. Ecco la struttura delle cartelle che utilizzeremo:
-
AppContext: Contiene il contesto del database e le configurazioni correlate.
-
Configurazioni: Contiene le configurazioni di Entity Framework Core e i dati iniziali per il database.
-
Contratti: Contiene gli Oggetti di Trasferimento Dati (DTO) utilizzati nella nostra applicazione.
-
Endpoint: Dove definiamo e configuriamo i nostri endpoint API minimale.
-
Eccezioni: Contiene le classi di eccezione personalizzate utilizzate nel progetto.
-
Estensioni: Contiene i metodi di estensione che utilizzeremo in tutto il progetto.
-
Modelli: Contiene i modelli di logica aziendale.
-
Servizi: Contiene le classi di servizio che implementano la logica aziendale.
-
Interfacce: Contiene le definizioni delle interfacce utilizzate per mappare i nostri servizi.
In Visual Studio Code, puoi creare questa struttura delle cartelle nel seguente modo:
- AppContext
- Configurations
- Contracts
- Endpoints
- Exceptions
- Extensions
- Models
- Services
- Interfaces
Dopo averla impostata, la struttura della cartella del tuo progetto dovrebbe assomigliare a questa:
Ora che la struttura del nostro progetto è impostata, possiamo procedere e iniziare a scrivere il nostro codice. Cominciamo creando i nostri modelli.
Come Creare i Modelli
In questa sezione, creeremo i modelli per la nostra applicazione. I modelli sono i mattoni fondamentali della nostra applicazione, rappresentano i dati con cui la nostra applicazione lavorerà. Per il nostro esempio, creeremo un modello per un libro.
Per iniziare, crea una cartella chiamata Models
nella directory del tuo progetto. All’interno di questa cartella, crea un file chiamato BookModel.cs
e aggiungi il seguente codice:
// Models/BookModel.cs
namespace bookapi_minimal.Models
{
public class BookModel
{
public Guid Id { get; set; }
public string Title { get; set; }
public string Author { get; set; }
public string Description { get; set; }
public string Category { get; set; }
public string Language { get; set; }
public int TotalPages { get; set; }
}
}
Questa classe BookModel
definisce le proprietà che rappresentano i dettagli di un libro, come il titolo
, autore
, descrizione
, categoria
, lingua
e pagine totali
. Ogni proprietà è progettata per contenere informazioni specifiche sul libro, semplificando la gestione e la manipolazione dei dati del libro all’interno della nostra applicazione.
Ora che abbiamo creato il nostro modello, creiamo il nostro contesto del database.
Come Creare il Contesto del Database
Il contesto del database è una classe che rappresenta una sessione con il database. È responsabile dell’interazione con il database ed esecuzione delle operazioni del database. Nella nostra applicazione, useremo Entity Framework Core per interagire con il database.
Installa i Pacchetti Richiesti
Prima di creare il nostro contesto del database, dobbiamo installare i seguenti pacchetti:
-
Microsoft.EntityFrameworkCore
-
Microsoft.EntityFrameworkCore.SqlServer
-
FluentValidation.DependencyInjectionExtensions
Potete installare questi pacchetti utilizzando i seguenti comandi:
dotnet add package Microsoft.EntityFrameworkCore.Design
dotnet add package Microsoft.EntityFrameworkCore
dotnet add package Microsoft.EntityFrameworkCore.SqlServer
dotnet add package Microsoft.EntityFrameworkCore.Tools
dotnet add package FluentValidation.DependencyInjectionExtensions
Verifica Installazione Pacchetti
Per verificare che i pacchetti siano installati, aprire il file bookapi-minimal.csproj
nella directory principale del vostro progetto. Dovreste vedere i pacchetti installati elencati come segue:
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<RootNamespace>bookapi_minimal</RootNamespace>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="FluentValidation.DependencyInjectionExtensions" Version="11.9.2" />
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.6" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.8" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.8">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.8" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.8">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
</ItemGroup>
</Project>
Questo conferma che i pacchetti sono stati installati con successo.
Ora creiamo il nostro contesto del database.
Nella cartella AppContext, crea un nuovo file chiamato ApplicationContext.cs
e aggiungi il seguente codice:
// AppContext/ApplicationContext.cs
using bookapi_minimal.Models;
using Microsoft.EntityFrameworkCore;
namespace bookapi_minimal.AppContext
{
public class ApplicationContext(DbContextOptions<ApplicationContext> options) : DbContext(options)
{
// Schema predefinito per il contesto del database
private const string DefaultSchema = "bookapi";
// DbSet per rappresentare la raccolta di libri nel nostro database
public DbSet<BookModel> Books { get; set; }
// Costruttore per configurare il contesto del database
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.HasDefaultSchema(DefaultSchema);
modelBuilder.ApplyConfigurationsFromAssembly(typeof(ApplicationContext).Assembly);
modelBuilder.ApplyConfigurationsFromAssembly(typeof(ApplicationContext).Assembly);
}
}
}
Analizziamo il codice sopra:
-
Definiamo una classe chiamata
ApplicationContext
che eredita daDbContext
. La classeDbContext
fa parte di Entity Framework Core e rappresenta una sessione con il database. -
Il costruttore accetta un’istanza di
DbContextOptions<ApplicationContext>
. Questo costruttore viene utilizzato per configurare le opzioni del contesto del database. -
Definiamo una proprietà chiamata
Books
di tipoDbSet<BookModel>
. Questa proprietà rappresenta la raccolta di libri nel nostro database. -
Sovrascriviamo il metodo
OnModelCreating
per configurare lo schema del database e applicare eventuali configurazioni definite nella nostra applicazione.
Ora che abbiamo creato il nostro contesto del database, creiamo il nostro metodo di estensione e registriamo il nostro contesto del database nel contenitore di iniezione delle dipendenze.
Creare un Metodo di Estensione
Prima di creare il metodo di estensione, comprendiamo cos’è un metodo di estensione nel contesto di ASP.NET Core.
Un metodo di estensione è un metodo statico che aggiunge nuove funzionalità a un tipo esistente senza modificare il tipo originale. In ASP.NET Core, i metodi di estensione sono comunemente utilizzati per estendere la funzionalità dell’interfaccia IServiceCollection
, che viene utilizzata per registrare i servizi nel contenitore di iniezione delle dipendenze.
I servizi sono componenti che forniscono funzionalità a un’applicazione, come l’accesso al database, la registrazione e la configurazione. Creando un metodo di estensione per l’interfaccia IServiceCollection
, è possibile semplificare il processo di registrazione dei propri servizi nel contenitore di iniezione delle dipendenze.
Invece di mettere tutto nel file Program.cs
, creeremo un metodo di estensione per registrare i nostri servizi nel contenitore di iniezione delle dipendenze. Questo ci aiuterà a mantenere il nostro codice pulito e organizzato.
Nella cartella Extensions
, crea un nuovo file chiamato ServiceExtensions.cs
e aggiungi il seguente codice:
using System.Reflection;
using bookapi_minimal.AppContext;
using FluentValidation;
using Microsoft.EntityFrameworkCore;
namespace bookapi_minimal.Extensions
{
public static class ServiceExtensions
{
public static void AddApplicationServices(this IHostApplicationBuilder builder)
{
if (builder == null) throw new ArgumentNullException(nameof(builder));
if (builder.Configuration == null) throw new ArgumentNullException(nameof(builder.Configuration));
// Aggiunta del contesto del database
builder.Services.AddDbContext<ApplicationContext>(configure =>
{
configure.UseSqlServer(builder.Configuration.GetConnectionString("sqlConnection"));
});
// Aggiunta dei validatori dall'assembly corrente
builder.Services.AddValidatorsFromAssembly(Assembly.GetExecutingAssembly());
}
}
}
Rompiamo il codice sopra:
-
Definiamo una classe statica chiamata
ServiceExtensions
che contiene un metodo di estensione chiamatoAddApplicationServices
. Questo metodo estende l’interfacciaIHostApplicationBuilder
, che viene utilizzata per configurare la pipeline di elaborazione delle richieste dell’applicazione. -
Il metodo
AddApplicationServices
accetta un’istanza diIHostApplicationBuilder
come parametro. Questo parametro viene utilizzato per accedere alla configurazione e ai servizi dell’applicazione. -
Aggiungiamo il
ApplicationContext
al contenitore di iniezione delle dipendenze e lo configuriamo per utilizzare SQL Server come fornitore di database. Recuperiamo la stringa di connessione dal fileappsettings.json
utilizzando il metodoGetConnectionString
. -
Aggiungiamo
validators
dall’attualeassembly
utilizzando il metodoAddValidatorsFromAssembly
. Questo metodo scansiona l’assembly attuale per classi che implementano l’interfaccia IValidator e le registra nel contenitore di iniezione delle dipendenze.
Successivamente, dobbiamo aggiungere la stringa di connessione al file appsettings.json
. Aggiungi il seguente codice al tuo file appsettings.json
:
{
"ConnectionStrings": {
"sqlConnection": "Server=localhost\\SQLEXPRESS02;Database=BookAPIMinimalAPI;Integrated Security=true;TrustServerCertificate=true;"
}
}
Assicurati di sostituire your_password
con la tua attuale password di SQL Server.
Il tuo file appsettings.json
dovrebbe apparire così:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"ConnectionStrings": {
"sqlConnection": "Server=localhost\\SQLEXPRESS02;Database=BookAPIMinimalAPI;Integrated Security=true;TrustServerCertificate=true;"
},
"AllowedHosts": "*"
}
Congratulazioni! Hai creato con successo il contesto del database, il metodo di estensione e la stringa di connessione per la tua applicazione. Nella prossima sezione, creeremo un Contratto.
Come Creare un Contratto
I contratti sono Oggetti di Trasferimento Dati (DTO) che definiscono la struttura dei dati scambiati tra il client e il server. Nella nostra applicazione, creeremo contratti per rappresentare i dati inviati e ricevuti dai nostri endpoint API.
Ecco i contratti che creeremo:
-
CreateBookRequest: Questo rappresenta i dati inviati quando si crea un nuovo libro.
-
UpdateBookRequest: tHI Rappresenta i dati inviati quando si aggiorna un libro esistente.
-
BookResponse: Rappresenta i dati restituiti quando si recupera un libro.
-
ErrorResponse: Rappresenta la risposta di errore restituita quando si verifica un’eccezione.
-
ApiResponse: Rappresenta la risposta restituita dall’API.
Nella cartella Contracts
, crea un nuovo file chiamato CreateBookRequest
e aggiungi il seguente codice:
// Contracts/CreateBookRequest.cs
namespace bookapi_minimal.Contracts
{
public record CreateBookRequest
{
public string Title { get; init; }
public string Author { get; init; }
public string Description { get; init; }
public string Category { get; init; }
public string Language { get; init; }
public int TotalPages { get; init; }
}
}
Nella cartella Contracts
, crea un nuovo file chiamato UpdateBookRequest
e aggiungi il seguente codice:
// Contratti/UpdateBookRequest.cs
namespace bookapi_minimal.Contracts
{
public record UpdateBookRequest
{
public string Title { get; set; }
public string Author { get; set; }
public string Description { get; set; }
public string Category { get; set; }
public string Language { get; set; }
public int TotalPages { get; set; }
}
}
Nella cartella Contratti
, crea un nuovo file chiamato BookResponse
e aggiungi il seguente codice:
// Contratti/BookResponse.cs
namespace bookapi_minimal.Contracts
{
public record BookResponse
{
public Guid Id { get; set; }
public string Title { get; set; }
public string Author { get; set; }
public string Description { get; set; }
public string Category { get; set; }
public string Language { get; set; }
public int TotalPages { get; set; }
}
}
Nella cartella Contratti
, crea un nuovo file chiamato ErrorResponse
e aggiungi il seguente codice:
// Contratti/ErrorResponse.cs
namespace bookapi_minimal.Contracts
{
public record ErrorResponse
{
public string Title { get; set; }
public int StatusCode { get; set; }
public string Message { get; set; }
}
}
Nella cartella Contratti
, crea un nuovo file chiamato ApiResponse
e aggiungi il seguente codice:
// Contratti/ApiResponse.cs
namespace bookapi_minimal.Contracts
{
public class ApiResponse<T>
{
public T Data { get; set; }
public string Message { get; set; }
public ApiResponse(T data, string message)
{
Data = data;
Message = message;
}
}
}
Questi contratti ci aiutano a definire la struttura dei dati scambiati tra il client e il server, facilitando il lavoro con i dati nella nostra applicazione.
Nella prossima sezione, creeremo servizi per implementare la logica di business della nostra applicazione.
Come Aggiungere Servizi
I servizi sono componenti che forniscono funzionalità a un’applicazione. Nella nostra applicazione, creeremo servizi per implementare la logica di business. Creeremo servizi per gestire le operazioni CRUD per i libri, convalidare i dati dei libri e gestire le eccezioni.
In ASP.NET Core, i servizi vengono registrati nel contenitore di injection delle dipendenze e possono essere iniettati in altri componenti, come controller e endpoint, ma questa è una API minimale quindi inietteremo direttamente i servizi negli endpoint.
Creiamo un’interfaccia per i nostri servizi. Nella cartella Interfaces
, crea un nuovo file chiamato IBookService.cs
e aggiungi il seguente codice:
// Interfaces/IBookService.cs
using bookapi_minimal.Contracts;
namespace bookapi_minimal.Interfaces
{
public interface IBookService
{
Task<BookResponse> AddBookAsync(CreateBookRequest createBookRequest);
Task<BookResponse> GetBookByIdAsync(Guid id);
Task<IEnumerable<BookResponse>> GetBooksAsync();
Task<BookResponse> UpdateBookAsync(Guid id, UpdateBookRequest updateBookRequest);
Task<bool> DeleteBookAsync(Guid id);
}
}
Analizziamo il codice sopra: Abbiamo definito un’interfaccia chiamata IBookService
che contiene metodi per gestire le operazioni CRUD per i libri. L’interfaccia definisce i seguenti metodi:
-
AddBookAsync
: Aggiunge un nuovo libro al database. -
GetBookByIdAsync
: Recupera un libro tramite il suo ID. -
GetBooksAsync
: Recupera tutti i libri dal database. -
UpdateBookAsync
: Aggiorna un libro esistente.
Stiamo utilizzando il Contratto che abbiamo creato in precedenza nella cartella Contracts
. L’interfaccia IBookService
definisce la struttura dei metodi che verranno implementati dalle classi di servizio. Questo ci aiuta a separare l’interfaccia dall’implementazione, rendendo più facile mantenere e testare il nostro codice.
Ora che abbiamo creato l’interfaccia, creiamo la classe di servizio che implementa l’interfaccia.
Come Implementare il Servizio Libri
Questo servizio implementerà l’interfaccia IBookService
e fornirà la logica di business per la nostra applicazione. Nella cartella Services
, crea un nuovo file chiamato BookService.cs
. Il tuo file iniziale dovrebbe apparire così:
// Services/BookService.cs
namespace bookapi_minimal.Services
{
public class BookService
{
}
}
La prima cosa che dobbiamo fare è aggiungere l’interfaccia alla classe BookService
. Aggiorna la classe BookService
per implementare l’interfaccia IBookService
come segue:
// Services/BookService.cs
using bookapi_minimal.Interfaces;
namespace bookapi_minimal.Services
{
public class BookService:IBookService
{
}
}
Quando fai questo, il tuo VS Code potrebbe mostrare un errore perché non abbiamo implementato i metodi dell’interfaccia. Procediamo e implementiamo i metodi nella classe BookService
.
In VS Code puoi usare la scorciatoia Ctrl + .
per implementare i metodi dell’interfaccia. Poi vedrai il seguente codice generato per te:
using bookapi_minimal.Contracts;
using bookapi_minimal.Interfaces;
namespace bookapi_minimal.Services
{
// Classe di servizio per la gestione dei libri
public class BookService : IBookService
{
// Metodo per aggiungere un nuovo libro al database
public Task<BookResponse> AddBookAsync(CreateBookRequest createBookRequest)
{
throw new NotImplementedException();
}
// Metodo per eliminare un libro dal database
public Task<bool> DeleteBookAsync(Guid id)
{
throw new NotImplementedException();
}
// Metodo per ottenere un libro dal database tramite il suo ID
public Task<BookResponse> GetBookByIdAsync(Guid id)
{
throw new NotImplementedException();
}
// Metodo per ottenere tutti i libri dal database
public Task<IEnumerable<BookResponse>> GetBooksAsync()
{
throw new NotImplementedException();
}
// Metodo per aggiornare un libro nel database
public Task<BookResponse> UpdateBookAsync(Guid id, UpdateBookRequest updateBookRequest)
{
throw new NotImplementedException();
}
}
}
Ora puoi vedere che i metodi nell’interfaccia sono stati implementati nella classe BookService
. Implementeremo la logica di business per ogni metodo nella sezione successiva.
Prima di farlo, aggiungiamo le dipendenze necessarie alla classe BookService
. Dobbiamo iniettare le dipendenze ApplicationContext
e ILogger
nella classe BookService
. ApplicationContext
viene utilizzato per interagire con il database, mentre ILogger
viene utilizzato per il logging.
Per iniettare le dipendenze, aggiorna la classe BookService
come segue:
// Services/BookService.cs
// ...
private readonly ApplicationContext _context; // Contesto del database
private readonly ILogger<BookService> _logger; // Logger per registrare informazioni ed errori
//..
Dato che abbiamo aggiunto le dipendenze, dobbiamo aggiornare il costruttore di BookService
per accettare le dipendenze. Aggiorna il costruttore di BookService
come segue:
// Services/BookService.cs
// ...
// Costruttore per inizializzare il contesto del database e il logger
public BookService(ApplicationContext context, ILogger<BookService> logger)
{
_context = context;
_logger = logger;
}
// ...
Ora che abbiamo aggiunto le dipendenze e aggiornato il costruttore, possiamo implementare la logica di business per ogni metodo nella classe BookService
.
Creiamo la logica per le operazioni di CREATE, READ, UPDATE e DELETE nella classe BookService
.
Come Implementare il Metodo AddBookAsync
Come ho già detto, utilizzeremo il metodo AddBookAsync
per aggiungere un nuovo libro al database. In questo metodo, creeremo una nuova entità libro, mapperemo i dati dall’oggetto CreateBookRequest
all’entità libro e salveremo l’entità libro nel database. Restituiremo inoltre l’entità libro come oggetto BookResponse
.
Aggiorna il metodo AddBookAsync
nella classe BookService
come segue:
// Services/BookService.cs
// ...
/// <summary>
/// Aggiungi un nuovo libro
/// </summary>
/// <param name="createBookRequest">Richiesta di libro da aggiungere</param>
/// <returns>Dettagli del libro creato</returns>
public async Task<BookResponse> AddBookAsync(CreateBookRequest createBookRequest)
{
try
{
var book = new BookModel
{
Title = createBookRequest.Title,
Author = createBookRequest.Author,
Description = createBookRequest.Description,
Category = createBookRequest.Category,
Language = createBookRequest.Language,
TotalPages = createBookRequest.TotalPages
};
// Aggiungi il libro al database
_context.Books.Add(book);
await _context.SaveChangesAsync();
_logger.LogInformation("Book added successfully.");
// Restituisci i dettagli del libro creato
return new BookResponse
{
Id = book.Id,
Title = book.Title,
Author = book.Author,
Description = book.Description,
Category = book.Category,
Language = book.Language,
TotalPages = book.TotalPages
};
}
catch (Exception ex)
{
_logger.LogError($"Error adding book: {ex.Message}");
throw;
}
}
// ...
In questo codice, stiamo creando una nuova entità libro dall’oggetto CreateBookRequest
, mappando i dati dall’oggetto CreateBookRequest
all’entità libro, salvando l’entità libro nel database e restituendo l’entità libro come oggetto BookResponse
.
Stiamo anche registrando informazioni ed errori utilizzando la dipendenza ILogger
. Se si verifica un’eccezione durante il processo, registriamo il messaggio di errore e rilanciamo l’eccezione.
Ora che abbiamo implementato il metodo AddBookAsync
, implementiamo il metodo GetBookByIdAsync
.
Come Implementare il Metodo GetBookByIdAsync
Il metodo GetBookByIdAsync
viene utilizzato per recuperare un libro dal database tramite il suo ID. In questo metodo, interrogheremo il database per il libro con l’ID specificato, mapperemo l’entità libro a un oggetto BookResponse
e restituiremo l’oggetto BookResponse
.
Aggiorna il metodo GetBookByIdAsync
nella classe BookService
come segue:
// Servizi/BookService.cs
//...
/// <summary>
/// Ottieni un libro tramite il suo ID
/// </summary>
/// <param name="id">ID del libro</param>
/// <returns>Dettagli del libro</returns>
public async Task<BookResponse> GetBookByIdAsync(Guid id)
{
try
{
// Trova il libro tramite il suo ID
var book = await _context.Books.FindAsync(id);
if (book == null)
{
_logger.LogWarning($"Book with ID {id} not found.");
return null;
}
// Restituisci i dettagli del libro
return new BookResponse
{
Id = book.Id,
Title = book.Title,
Author = book.Author,
Description = book.Description,
Category = book.Category,
Language = book.Language,
TotalPages = book.TotalPages
};
}
catch (Exception ex)
{
_logger.LogError($"Error retrieving book: {ex.Message}");
throw;
}
}
//...
In questo codice, stiamo interrogando il database per il libro con l’ID specificato, mappando l’entità del libro a un oggetto BookResponse
e restituendo l’oggetto BookResponse
. Stiamo anche registrando informazioni ed errori utilizzando la dipendenza ILogger
.
Se il libro con l’ID specificato non viene trovato, registriamo un messaggio di avviso e restituiamo null. Se si verifica un’eccezione durante il processo, registriamo il messaggio di errore e rilanciamo l’eccezione.
Ora che abbiamo implementato il metodo GetBookByIdAsync
, implementiamo il metodo GetBooksAsync
.
Come Implementare il Metodo GetBooksAsync
Il metodo GetBooksAsync
viene utilizzato per recuperare tutti i libri dal database. In questo metodo, interrogheremo il database per tutti i libri, mapperemo ogni entità libro a un oggetto BookResponse
e restituiremo un elenco di oggetti BookResponse
.
Aggiorna il metodo GetBooksAsync
nella classe BookService
come segue:
// Services/BookService.cs
//...
/// <summary>
/// Ottieni tutti i libri
/// </summary>
/// <returns>Elenco di tutti i libri</returns>
public async Task<IEnumerable<BookResponse>> GetBooksAsync()
{
try
{
// Ottieni tutti i libri dal database
var books = await _context.Books.ToListAsync();
// Restituisci i dettagli di tutti i libri
return books.Select(book => new BookResponse
{
Id = book.Id,
Title = book.Title,
Author = book.Author,
Description = book.Description,
Category = book.Category,
Language = book.Language,
TotalPages = book.TotalPages
});
}
catch (Exception ex)
{
_logger.LogError($"Error retrieving books: {ex.Message}");
throw;
}
}
//...
Qui, stiamo interrogando il database per tutti i libri, mappando ogni entità libro a un oggetto BookResponse
e restituendo un elenco di oggetti BookResponse
. Stiamo anche registrando informazioni ed errori utilizzando la dipendenza ILogger
. Se si verifica un’eccezione durante il processo, registriamo il messaggio di errore e rilanciamo l’eccezione.
Ora che abbiamo implementato il metodo GetBooksAsync
, implementiamo il metodo UpdateBookAsync
.
Come Implementare il Metodo UpdateBookAsync
Il metodo UpdateBookAsync
viene utilizzato per aggiornare un libro esistente nel database. In questo metodo, interrogheremo il database per trovare il libro con l’ID specificato, aggiorneremo l’entità del libro con i dati provenienti dall’oggetto UpdateBookRequest
, salveremo l’entità del libro aggiornata nel database e restituiremo l’entità del libro aggiornata come oggetto BookResponse
.
Aggiorna il metodo UpdateBookAsync
nella classe BookService
come segue:
// Services/BookService.cs
//...
/// <summary>
/// Aggiorna un libro esistente
/// </summary>
/// <param name="id">ID del libro da aggiornare</param>
/// <param name="book">Modello del libro aggiornato</param>
/// <returns>Dettagli del libro aggiornato</returns>
public async Task<BookResponse> UpdateBookAsync(Guid id, UpdateBookRequest book)
{
try
{
// Trova il libro esistente tramite il suo ID
var existingBook = await _context.Books.FindAsync(id);
if (existingBook == null)
{
_logger.LogWarning($"Book with ID {id} not found.");
return null;
}
// Aggiorna i dettagli del libro
existingBook.Title = book.Title;
existingBook.Author = book.Author;
existingBook.Description = book.Description;
existingBook.Category = book.Category;
existingBook.Language = book.Language;
existingBook.TotalPages = book.TotalPages;
// Salva le modifiche nel database
await _context.SaveChangesAsync();
_logger.LogInformation("Book updated successfully.");
// Restituisci i dettagli del libro aggiornato
return new BookResponse
{
Id = existingBook.Id,
Title = existingBook.Title,
Author = existingBook.Author,
Description = existingBook.Description,
Category = existingBook.Category,
Language = existingBook.Language,
TotalPages = existingBook.TotalPages
};
}
catch (Exception ex)
{
_logger.LogError($"Error updating book: {ex.Message}");
throw;
}
}
//...
Qui, stiamo interrogando il database per il libro con l’ID specificato, aggiornando l’entità del libro con i dati provenienti dall’oggetto UpdateBookRequest
, salvando l’entità del libro aggiornata nel database e restituendo l’entità del libro aggiornata come oggetto BookResponse
. Stiamo anche registrando informazioni ed errori utilizzando la dipendenza ILogger
.
Se il libro con l’ID specificato non viene trovato, registriamo un messaggio di avviso e restituiamo null. Se si verifica un’eccezione durante il processo, registriamo il messaggio di errore e rilanciamo l’eccezione.
Ora che abbiamo implementato il metodo UpdateBookAsync
, implementiamo il metodo DeleteBookAsync
.
Come Implementare il Metodo DeleteBookAsync
Il metodo DeleteBookAsync
viene utilizzato per eliminare un libro esistente dal database. In questo metodo, interrogheremo il database per il libro con l’ID specificato, rimuoveremo l’entità del libro dal database e restituiremo un valore booleano che indica se il libro è stato eliminato con successo.
Aggiorna il metodo DeleteBookAsync
nella classe BookService
come segue:
// Servizi/BookService.cs
//...
/// <summary>
/// Elimina un libro tramite il suo ID
/// </summary>
/// <param name="id">ID del libro da eliminare</param>
/// <returns>True se il libro è stato eliminato, false altrimenti</returns>
public async Task<bool> DeleteBookAsync(Guid id)
{
try
{
// Trova il libro tramite il suo ID
var book = await _context.Books.FindAsync(id);
if (book == null)
{
_logger.LogWarning($"Book with ID {id} not found.");
return false;
}
// Rimuove il libro dal database
_context.Books.Remove(book);
await _context.SaveChangesAsync();
_logger.LogInformation($"Book with ID {id} deleted successfully.");
return true;
}
catch (Exception ex)
{
_logger.LogError($"Error deleting book: {ex.Message}");
throw;
}
}
//...
In questo codice, stiamo interrogando il database per il libro con l’ID specificato, rimuovendo l’entità del libro dal database e restituendo un valore booleano che indica se il libro è stato eliminato con successo. Stiamo inoltre registrando informazioni ed errori utilizzando la dipendenza ILogger
.
Se il libro con l’ID specificato non viene trovato, registriamo un messaggio di avviso e restituiamo false. Se si verifica un’eccezione durante il processo, registriamo il messaggio di errore e rilanciamo l’eccezione.
Ora hai implementato con successo la logica aziendale per i metodi AddBookAsync
, GetBookByIdAsync
, GetBooksAsync
, UpdateBookAsync
e DeleteBookAsync
nella classe BookService
. Questi metodi gestiscono le operazioni CRUD per i libri, convalidano i dati dei libri e gestiscono le eccezioni. A questo punto, la tua classe BookService
dovrebbe apparire così:
using bookapi_minimal.AppContext;
using bookapi_minimal.Contracts;
using bookapi_minimal.Interfaces;
using bookapi_minimal.Models;
using Microsoft.EntityFrameworkCore;
namespace bookapi_minimal.Services
{
public class BookService : IBookService
{
private readonly ApplicationContext _context; // Contesto del database
private readonly ILogger<BookService> _logger; // Logger per il logging delle informazioni e degli errori
// Costruttore per inizializzare il contesto del database e il logger
public BookService(ApplicationContext context, ILogger<BookService> logger)
{
_context = context;
_logger = logger;
}
/// Aggiungi un nuovo libro
/// </summary>
/// <param name="createBookRequest">Richiesta di libro da aggiungere</param>
/// <returns>Dettagli del libro creato</returns>
public async Task<BookResponse> AddBookAsync(CreateBookRequest createBookRequest)
{
try
{
var book = new BookModel
{
Title = createBookRequest.Title,
Author = createBookRequest.Author,
Description = createBookRequest.Description,
Category = createBookRequest.Category,
Language = createBookRequest.Language,
TotalPages = createBookRequest.TotalPages
};
// Aggiungi il libro al database
_context.Books.Add(book);
await _context.SaveChangesAsync();
_logger.LogInformation("Book added successfully.");
// Restituisci i dettagli del libro creato
return new BookResponse
{
Id = book.Id,
Title = book.Title,
Author = book.Author,
Description = book.Description,
Category = book.Category,
Language = book.Language,
TotalPages = book.TotalPages
};
}
catch (Exception ex)
{
_logger.LogError($"Error adding book: {ex.Message}");
throw;
}
}
/// <summary>
/// Ottieni un libro tramite il suo ID
/// </summary>
/// <param name="id">ID del libro</param>
/// <returns>Dettagli del libro</returns>
public async Task<BookResponse> GetBookByIdAsync(Guid id)
{
try
{
// Trova il libro tramite il suo ID
var book = await _context.Books.FindAsync(id);
if (book == null)
{
_logger.LogWarning($"Book with ID {id} not found.");
return null;
}
// Restituisci i dettagli del libro
return new BookResponse
{
Id = book.Id,
Title = book.Title,
Author = book.Author,
Description = book.Description,
Category = book.Category,
Language = book.Language,
TotalPages = book.TotalPages
};
}
catch (Exception ex)
{
_logger.LogError($"Error retrieving book: {ex.Message}");
throw;
}
}
/// <summary>
/// Ottieni tutti i libri
/// </summary>
/// <returns>Elenco di tutti i libri</returns>
public async Task<IEnumerable<BookResponse>> GetBooksAsync()
{
try
{
// Ottieni tutti i libri dal database
var books = await _context.Books.ToListAsync();
// Restituisci i dettagli di tutti i libri
return books.Select(book => new BookResponse
{
Id = book.Id,
Title = book.Title,
Author = book.Author,
Description = book.Description,
Category = book.Category,
Language = book.Language,
TotalPages = book.TotalPages
});
}
catch (Exception ex)
{
_logger.LogError($"Error retrieving books: {ex.Message}");
throw;
}
}
/// <summary>
/// Aggiorna un libro esistente
/// </summary>
/// <param name="id">ID del libro da aggiornare</param>
/// <param name="book">Modello del libro aggiornato</param>
/// <returns>Dettagli del libro aggiornato</returns>
public async Task<BookResponse> UpdateBookAsync(Guid id, UpdateBookRequest book)
{
try
{
// Trova il libro esistente tramite il suo ID
var existingBook = await _context.Books.FindAsync(id);
if (existingBook == null)
{
_logger.LogWarning($"Book with ID {id} not found.");
return null;
}
// Aggiorna i dettagli del libro
existingBook.Title = book.Title;
existingBook.Author = book.Author;
existingBook.Description = book.Description;
existingBook.Category = book.Category;
existingBook.Language = book.Language;
existingBook.TotalPages = book.TotalPages;
// Salva le modifiche nel database
await _context.SaveChangesAsync();
_logger.LogInformation("Book updated successfully.");
// Restituisci i dettagli del libro aggiornato
return new BookResponse
{
Id = existingBook.Id,
Title = existingBook.Title,
Author = existingBook.Author,
Description = existingBook.Description,
Category = existingBook.Category,
Language = existingBook.Language,
TotalPages = existingBook.TotalPages
};
}
catch (Exception ex)
{
_logger.LogError($"Error updating book: {ex.Message}");
throw;
}
}
/// <summary>
/// Elimina un libro tramite il suo ID
/// </summary>
/// <param name="id">ID del libro da eliminare</param>
/// <returns>True se il libro è stato eliminato, false altrimenti</returns>
public async Task<bool> DeleteBookAsync(Guid id)
{
try
{
// Trova il libro tramite il suo ID
var book = await _context.Books.FindAsync(id);
if (book == null)
{
_logger.LogWarning($"Book with ID {id} not found.");
return false;
}
// Rimuovi il libro dal database
_context.Books.Remove(book);
await _context.SaveChangesAsync();
_logger.LogInformation($"Book with ID {id} deleted successfully.");
return true;
}
catch (Exception ex)
{
_logger.LogError($"Error deleting book: {ex.Message}");
throw;
}
}
}
}
Complimenti! Hai implementato con successo la logica aziendale per i metodi AddBookAsync
, GetBookByIdAsync
, GetBooksAsync
, UpdateBookAsync
e DeleteBookAsync
nella classe BookService
.
C’è una cosa che dobbiamo fare: dobbiamo registrare il servizio nel nostro metodo di estensione. Procediamo a farlo.
Nel tuo file ServiceExtensions.cs
, aggiungi il seguente codice:
// Extensions/ServiceExtensions.cs
//..
builder.Services.AddScoped<IBookService, BookService>();
//...
Questo registrerà la classe BookService
come un servizio scoped. Questo significa che il servizio verrà creato una volta per richiesta e smaltito dopo che la richiesta è completata.
Ora che abbiamo il servizio funzionante, procediamo a creare le classi di eccezione.
Come Creare Eccezioni
Gestire correttamente le eccezioni è fondamentale per garantire la stabilità e la affidabilità di un’applicazione. Nel contesto di ASP.NET Core, ci sono due principali tipi di eccezioni:
-
Eccezioni di Sistema: Queste sono eccezioni lanciate dal runtime .NET o dal sistema sottostante.
-
Eccezioni dell’Applicazione: Queste sono eccezioni lanciate dal codice dell’applicazione per gestire errori o condizioni specifiche.
In ASP.NET Core con .NET 8, è stata introdotta una nuova funzionalità chiamata gestione delle eccezioni globali. Questa funzionalità consente di gestire le eccezioni globalmente nella tua applicazione, facilitando la gestione degli errori e fornendo un’esperienza utente coerente.
Nella nostra applicazione, creeremo classi di eccezione personalizzate per gestire errori e condizioni specifiche. Utilizzeremo anche la funzionalità di gestione delle eccezioni globali per gestire le eccezioni globalmente, garantendo un approccio uniforme alla gestione degli errori in tutta l’applicazione.
Creeremo le seguenti classi di eccezione:
-
NoBookFoundException
: Lanciata quando un libro con l’ID specificato non viene trovato. -
BookDoesNotExistException
: Lanciata quando un libro con l’ID specificato non esiste. -
GlobalExceptionHandler
: Gestisce le eccezioni globalmente nell’applicazione.
Nella cartella Exceptions
, crea un nuovo file chiamato NoBookFoundException.cs
e aggiungi il seguente codice:
// Exceptions/NoBookFoundException.cs
namespace bookapi_minimal.Exceptions
{
public class NoBookFoundException : Exception
{
public NoBookFoundException() : base("No books found")
{}
}
}
In questo codice, stiamo creando una classe di eccezione personalizzata denominata NoBookFoundException
che eredita dalla classe Exception
. La classe NoBookFoundException
viene utilizzata per gestire lo scenario in cui non vengono trovati libri nel database. Stiamo inoltre fornendo un messaggio di errore personalizzato per l’eccezione.
Nella cartella Exceptions
, creare un nuovo file denominato BookDoesNotExistException.cs
e aggiungere il seguente codice:
namespace bookapi_minimal.Exceptions
{
public class BookDoesNotExistException : Exception
{
private int id { get; set; }
public BookDoesNotExistException(int id) : base($"Book with id {id} does not exist")
{
this.id = id;
}
}
}
In questo codice, stiamo creando una classe di eccezione personalizzata denominata BookDoesNotExistException
che eredita dalla classe Exception
. La classe BookDoesNotExistException
viene utilizzata per gestire lo scenario in cui un libro con l’ID specificato non esiste nel database. Stiamo inoltre fornendo un messaggio di errore personalizzato per l’eccezione.
Nella cartella Exceptions
, creare un nuovo file denominato GlobalExceptionHandler.cs
e aggiungere il seguente codice:
// Eccezioni/GlobalExceptionHandler.cs
using System.Net;
using bookapi_minimal.Contracts;
using Microsoft.AspNetCore.Diagnostics;
namespace bookapi_minimal.Exceptions
{
// Classe gestore di eccezioni globali che implementa IExceptionHandler
public class GlobalExceptionHandler : IExceptionHandler
{
private readonly ILogger<GlobalExceptionHandler> _logger;
// Costruttore per inizializzare il logger
public GlobalExceptionHandler(ILogger<GlobalExceptionHandler> logger)
{
_logger = logger;
}
// Metodo per gestire le eccezioni in modo asincrono
public async ValueTask<bool> TryHandleAsync(
HttpContext httpContext,
Exception exception,
CancellationToken cancellationToken)
{
// Registrare i dettagli dell'eccezione
_logger.LogError(exception, "An error occurred while processing your request");
var errorResponse = new ErrorResponse
{
Message = exception.Message,
Title = exception.GetType().Name
};
// Determinare il codice di stato in base al tipo di eccezione
switch (exception)
{
case BadHttpRequestException:
errorResponse.StatusCode = (int)HttpStatusCode.BadRequest;
break;
case NoBookFoundException:
case BookDoesNotExistException:
errorResponse.StatusCode = (int)HttpStatusCode.NotFound;
break;
default:
errorResponse.StatusCode = (int)HttpStatusCode.InternalServerError;
break;
}
// Impostare il codice di stato della risposta
httpContext.Response.StatusCode = errorResponse.StatusCode;
// Scrivere la risposta di errore come JSON
await httpContext.Response.WriteAsJsonAsync(errorResponse, cancellationToken);
// Restituire true per indicare che l'eccezione è stata gestita
return true;
}
}
}
Analizziamo il codice sopra:
-
Definiamo una classe chiamata
GlobalExceptionHandler
che implementa l’interfacciaIExceptionHandler
. L’interfacciaIExceptionHandler
viene utilizzata per gestire le eccezioni globalmente nell’applicazione. -
La classe
GlobalExceptionHandler
contiene un costruttore che inizializza la dipendenzaILogger<GlobalExceptionHandler>
. L’ILogger
viene utilizzato per registrare informazioni ed errori. -
Il metodo
TryHandleAsync
viene utilizzato per gestire le eccezioni in modo asincrono. Questo metodo accettaHttpContext
,Exception
eCancellationToken
come parametri. -
Registriamo i dettagli dell’eccezione utilizzando la dipendenza
ILogger
. -
Creiamo un oggetto
ErrorResponse
per rappresentare la risposta di errore restituita dall’API. L’oggettoErrorResponse
contiene il messaggio di errore, il titolo e il codice di stato. -
Determiniamo il codice di stato in base al tipo di eccezione. Se l’eccezione è una
BadHttpRequestException
, impostiamo il codice di stato suBadRequest
. Se l’eccezione è unaNoBookFoundException
oBookDoesNotExistException
, impostiamo il codice di stato suNotFound
. Altrimenti, impostiamo il codice di stato suInternalServerError
. -
Impostiamo il codice di stato della risposta utilizzando la proprietà
httpContext.Response.StatusCode
. -
Scriviamo la risposta di errore come JSON utilizzando il metodo
httpContext.Response.WriteAsJsonAsync
. -
Restituiamo
true
per indicare che l’eccezione è stata gestita con successo.
Ora che abbiamo creato le classi di eccezione, registriamo il GlobalExceptionHandler
nel contenitore di iniezione di dipendenze. Poiché abbiamo creato un metodo di estensione per registrare i servizi nel contenitore di iniezione di dipendenze, aggiungeremo il GlobalExceptionHandler
alla classe ServiceExtensions
.
Aggiorniamo la classe ServiceExtensions
nella cartella Extensions
come segue:
// Extensions/ServiceExtensions.cs
//...
builder.Services.AddExceptionHandler<GlobalExceptionHandler>();
builder.Services.AddProblemDetails();
//...
Il metodo AddExceptionHandler
registra il GlobalExceptionHandler
nel contenitore di iniezione delle dipendenze. Il metodo AddProblemDetails
registra la classe ProblemDetails
nel contenitore di iniezione delle dipendenze.
Ora che abbiamo registrato il GlobalExceptionHandler
nel contenitore di iniezione delle dipendenze, possiamo utilizzarlo per gestire le eccezioni globalmente nella nostra applicazione. Nella prossima sezione, creeremo gli endpoint API per interagire con i dati dei libri.
Come Creare gli Endpoint API
Nel contesto delle API minimali in ASP.NET Core, ci sono molti modi per configurare i tuoi endpoint.
Puoi definirli direttamente nel tuo file Program.cs
. Ma man mano che il tuo progetto cresce e hai bisogno di aggiungere più endpoint o funzionalità, è utile organizzare meglio il tuo codice. Un modo per raggiungere questo obiettivo è creare una classe separata per gestire tutti gli endpoint.
Come abbiamo discusso sopra, le API minimali non utilizzano controllori o viste come le applicazioni ASP.NET Core tradizionali. Invece, utilizzano metodi come MapGet
, MapPost
, MapPut
e MapDelete
per definire metodi HTTP e percorsi per gli endpoint API.
Per iniziare, vai nella cartella Endpoints
e crea un nuovo file chiamato BookEndpoints.cs
. Aggiungi il seguente codice al file:
// Endpoints/BookEndpoints.cs
namespace bookapi_minimal.Endpoints
{
public static class BookEndPoint
{
public static IEndpointRouteBuilder MapBookEndPoint(this IEndpointRouteBuilder app)
{
return app;
}
}
}
La classe BookEndpoints
contiene un metodo MapBookEndPoint
che restituisce un oggetto IEndpointRouteBuilder
. L’oggetto IEndpointRouteBuilder
viene utilizzato per definire i metodi HTTP e le rotte per gli endpoint dell’API. Nelle sezioni seguenti, definiranno gli endpoint dell’API per creare
, leggere
, aggiornare
e eliminare
libri.
Come Creare l’Endpoint AddBookAsync
per i Libri
In questa sezione, creeremo l’endpoint AddBookAsync
. Questo endpoint accetterà un oggetto Book
come payload JSON e lo aggiungerà al database. Utilizzeremo il metodo MapPost
per definire il metodo HTTP e la rotta per questo endpoint.
Aggiungi il seguente codice alla classe BookEndpoints
:
// Endpoints/BookEndpoints.cs
//...
// Endpoint per aggiungere un nuovo libro
app.MapPost("/books", async (CreateBookRequest createBookRequest, IBookService bookService) =>
{
var result = await bookService.AddBookAsync(createBookRequest);
return Results.Created($"/books/{result.Id}", result);
});
//...
-
Definizione della Rotta: Il metodo MapPost definisce la rotta per l’endpoint come
/books
. -
Modello di Richiesta: L’endpoint accetta un oggetto
CreateBookRequest
come payload JSON. L’oggettoCreateBookRequest
contiene i dati necessari per creare un nuovo libro. -
Modello di Risposta: L’endpoint restituisce un oggetto
Book
come payload JSON. L’oggettoBook
contiene i dati del libro appena creato. -
Valore di Ritorno: L’endpoint restituisce un risultato
Created
. Il risultatoCreated
contiene la posizione del libro appena creato e l’oggettoBook
.
Come Creare l’Endpoint del Libro GetBookAsync
In questa sezione, creeremo l’endpoint GetBookAsync
. Questo endpoint accetterà un ID libro come parametro di query e restituirà il libro con l’ID specificato. Utilizzeremo il metodo MapGet
per definire il metodo HTTP e la rotta per questo endpoint.
Aggiungi il seguente codice alla classe BookEndpoints
:
// Endpoints/BookEndpoints.cs
// ...
// Endpoint per ottenere tutti i libri
app.MapGet("/books", async (IBookService bookService) =>
{
var result = await bookService.GetBooksAsync();
return Results.Ok(result);
});
//...
-
Definizione della Rotta: Il metodo MapGet definisce la rotta per l’endpoint come
/books
. -
Modello di Richiesta: L’endpoint accetta un oggetto
Book
come payload JSON. L’oggettoBook
contiene i dati necessari per creare un nuovo libro. -
Modello di Risposta: L’endpoint restituisce un oggetto
Book
come payload JSON. L’oggettoBook
contiene i dati del nuovo libro creato. -
Valore di Ritorno: L’endpoint restituisce un risultato
Ok
. Il risultatoOk
contiene l’oggettoBook
.
How to Create the GetBookByIdAsync
Book Endpoint
In questa sezione, creeremo l’endpoint GetBookByIdAsync
. Questo endpoint accetterà un ID libro come parametro di route e restituirà il libro con l’ID specificato. Utilizzeremo il metodo MapGet
per definire il metodo HTTP e la route per questo endpoint.
Aggiungi il seguente codice alla classe BookEndpoints
:
// Endpoints/BookEndpoints.cs
//...
// Endpoint per ottenere un libro per ID
app.MapGet("/books/{id:guid}", async (Guid id, IBookService bookService) =>
{
var result = await bookService.GetBookByIdAsync(id);
return result != null ? Results.Ok(result) : Results.NotFound();
});
//...
-
Definizione della Route: Il metodo MapGet definisce la route per l’endpoint come
/books/{id:guid}
. Il parametro{id:guid}
specifica che il parametroid
dovrebbe essere un GUID. -
Modello di Richiesta: L’endpoint accetta un oggetto
Book
come payload JSON. L’oggettoBook
contiene i dati necessari per creare un nuovo libro. -
Modello di Risposta: L’endpoint restituisce un oggetto
Book
come payload JSON. L’oggettoBook
contiene i dati per il nuovo libro creato. -
Valore di Ritorno: L’endpoint restituisce un risultato
Ok
se il libro viene trovato. Il risultatoNotFound
viene restituito se il libro non viene trovato.
Come Creare l’Endpoint UpdateBookAsync
per il Libro
In questa sezione, creeremo l’endpoint UpdateBookAsync
. Questo endpoint accetterà un ID libro come parametro di percorso e un oggetto Book
come payload JSON e aggiornerà il libro con l’ID specificato. Utilizzeremo il metodo MapPut
per definire il metodo HTTP e il percorso per questo endpoint.
Aggiungi il seguente codice alla classe BookEndpoints
:
// Endpoints/BookEndpoints.cs
//...
// Endpoint per aggiornare un libro per ID
app.MapPut("/books/{id:guid}", async (Guid id, UpdateBookRequest updateBookRequest, IBookService bookService) =>
{
var result = await bookService.UpdateBookAsync(id, updateBookRequest);
return result != null ? Results.Ok(result) : Results.NotFound();
});
//...
-
Definizione del Percorso: Il metodo MapPut definisce il percorso per l’endpoint come
/books/{id:guid}
. Il parametro{id:guid}
specifica che il parametroid
dovrebbe essere un GUID. -
Modello di Richiesta: L’endpoint accetta un oggetto
Book
come payload JSON. L’oggettoBook
contiene i dati necessari per creare un nuovo libro. -
Modello di Risposta: L’endpoint restituisce un oggetto
Book
come payload JSON. L’oggettoBook
contiene i dati del libro appena creato. -
Valore di Ritorno: L’endpoint restituisce un risultato
Ok
se il libro viene trovato. Il risultatoNotFound
viene restituito se il libro non viene trovato.
Come Creare l’Endpoint DeleteBookAsync
per il Libro
In questa sezione, creeremo l’endpoint DeleteBookAsync
. Questo endpoint accetterà un ID libro come parametro di route e eliminerà il libro con l’ID specificato. Utilizzeremo il metodo MapDelete
per definire il metodo HTTP e la route per questo endpoint.
Aggiungi il seguente codice alla classe BookEndpoints
:
// Endpoints/BookEndpoints.cs
//...
// Endpoint per eliminare un libro per ID
app.MapDelete("/books/{id:guid}", async (Guid id, IBookService bookService) =>
{
var result = await bookService.DeleteBookAsync(id);
return result ? Results.NoContent() : Results.NotFound();
});
//...
-
Definizione della Route: Il metodo MapDelete definisce la route per l’endpoint come
/books/{id:guid}
. Il parametro{id:guid}
specifica che il parametroid
dovrebbe essere un GUID. -
Modello di Richiesta: L’endpoint accetta un oggetto
Book
come payload JSON. L’oggettoBook
contiene i dati necessari per creare un nuovo libro. -
Modello di Risposta: L’endpoint restituisce un oggetto
Book
come payload JSON. L’oggettoBook
contiene i dati per il nuovo libro creato. -
Valore di Ritorno: L’endpoint restituisce un risultato
NoContent
se il libro viene eliminato con successo. Il risultatoNotFound
viene restituito se il libro non viene trovato.
Ora abbiamo definito tutti i metodi per gli endpoint del libro. Quindi la tua classe di endpoint dovrebbe apparire così:
// Endpoints/BookEndpoints.cs
using bookapi_minimal.Contracts;
using bookapi_minimal.Interfaces;
namespace bookapi_minimal.Endpoints
{
public static class BookEndPoint
{
public static IEndpointRouteBuilder MapBookEndPoint(this IEndpointRouteBuilder app)
{
// Definisci gli endpoint
// Endpoint per aggiungere un nuovo libro
app.MapPost("/books", async (CreateBookRequest createBookRequest, IBookService bookService) =>
{
var result = await bookService.AddBookAsync(createBookRequest);
return Results.Created($"/books/{result.Id}", result);
});
// Endpoint per ottenere tutti i libri
app.MapGet("/books", async (IBookService bookService) =>
{
var result = await bookService.GetBooksAsync();
return Results.Ok(result);
});
// Endpoint per ottenere un libro per ID
app.MapGet("/books/{id:guid}", async (Guid id, IBookService bookService) =>
{
var result = await bookService.GetBookByIdAsync(id);
return result != null ? Results.Ok(result) : Results.NotFound();
});
// Endpoint per aggiornare un libro per ID
app.MapPut("/books/{id:guid}", async (Guid id, UpdateBookRequest updateBookRequest, IBookService bookService) =>
{
var result = await bookService.UpdateBookAsync(id, updateBookRequest);
return result != null ? Results.Ok(result) : Results.NotFound();
});
// Endpoint per eliminare un libro per ID
app.MapDelete("/books/{id:guid}", async (Guid id, IBookService bookService) =>
{
var result = await bookService.DeleteBookAsync(id);
return result ? Results.NoContent() : Results.NotFound();
});
return app;
}
}
}
Complimenti! Hai creato tutti gli endpoint per l’API del libro. Gli endpoint gestiscono le operazioni CRUD per i libri e restituiscono le risposte appropriate in base alla richiesta e ai dati.
Come Registrare gli Endpoint
Dopo aver definito i punti finali dell’API per l’API del libro, il passo successivo è registrare questi punti finali nel file Program.cs
. Utilizzeremo il metodo MapBookEndpoints
per registrare i punti finali del libro.
Dovremmo anche pulire la nostra classe Program.cs
per assicurarci che rimanga organizzata e mantenibile.
// Program.cs
using System.Reflection;
using bookapi_minimal.Endpoints;
using bookapi_minimal.Services;
using Microsoft.OpenApi.Models;
var builder = WebApplication.CreateBuilder(args);
builder.AddApplicationServices();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(c=>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "Mimal API", Version = "v1", Description = "Showing how you can build minimal " +
"api with .net" });
// Imposta il percorso dei commenti per il JSON di Swagger e l'interfaccia utente.
var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
c.IncludeXmlComments(xmlPath);
});
var app = builder.Build();
// Configura la pipeline delle richieste HTTP.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseExceptionHandler();
app.MapGroup("/api/v1/")
.WithTags(" Book endpoints")
.MapBookEndPoint();
app.Run();
Rompiamo i componenti chiave del file Program.cs
:
-
AddApplicationServices: Questo metodo registra i servizi necessari per l’API. È un metodo di estensione che abbiamo creato in precedenza per aggiungere servizi al contenitore di iniezione delle dipendenze.
-
AddSwaggerGen: Questo metodo registra il generatore di Swagger, che viene utilizzato per creare la documentazione di Swagger per l’API. Specificiamo il titolo, la versione e la descrizione dell’API nel documento di Swagger.
-
MapGroup: Questo metodo raggruppa gli endpoint. Prende un percorso come parametro e restituisce un oggetto
IEndpointRouteBuilder
. Utilizziamo il metodoWithTags
per aggiungere tag agli endpoint e il metodoMapBookEndpoints
per registrare gli endpoint del libro. -
Run: Questo metodo avvia l’applicazione.
Per abilitare la documentazione Swagger, è necessario aggiungere la proprietà GenerateDocumentationFile
al file .csproj
. In questo esempio, il file si chiama bookapi-minimal.csproj
, ma il nome può variare in base al progetto.
Aggiungi la seguente riga al file .csproj
:
<PropertyGroup>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
</PropertyGroup>
Alla fine, bookapi-minimal.csproj dovrebbe apparire così:
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<RootNamespace>bookapi_minimal</RootNamespace>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="FluentValidation.DependencyInjectionExtensions" Version="11.9.2" />
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.6" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.8" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.8">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.8" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.8">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
</ItemGroup>
</Project>
Ora che abbiamo registrato gli endpoint del libro nel file Program.cs
, possiamo eseguire l’applicazione e testare gli endpoint dell’API utilizzando Swagger.
Quando esegui l’applicazione, dovresti vedere la documentazione di Swagger all’URL seguente: https://localhost:5001/swagger/index.html
. La documentazione di Swagger fornisce informazioni sugli endpoint dell’API, i modelli di richiesta e risposta e ti permette di testare gli endpoint direttamente dal browser. Dovresti vedere qualcosa del genere:
Congratulazioni! Hai implementato la logica di business per il servizio di libri, creato eccezioni personalizzate, definito gli endpoint dell’API e registrato gli endpoint nel file Program.cs
. Hai anche abilitato la documentazione di Swagger per testare gli endpoint dell’API.
Come Aggiungere Dati di Seed al Database
Un altro passo importante è popolare il database con dati iniziali all’avvio dell’applicazione. Questi dati di seed popoleranno il database, permettendoti di testare gli endpoint della tua API senza aggiungere manualmente i dati.
Aggiungiamo alcuni dati di seed prima di eseguire le migrazioni e testare i nostri endpoint dell’API.
Per fare questo, creeremo una nuova classe nella nostra cartella Configuration chiamata BookTypeConfigurations
e aggiungeremo il seguente codice:
using bookapi_minimal.Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
namespace bookapi_minimal.Configurations
{
public class BookTypeConfigurations : IEntityTypeConfiguration<BookModel>
{
public void Configure(EntityTypeBuilder<BookModel> builder)
{
// Configura il nome della tabella
builder.ToTable("Books");
// Configura la chiave primaria
builder.HasKey(x => x.Id);
// Configura le proprietà
builder.Property(x => x.Id).ValueGeneratedOnAdd();
builder.Property(x => x.Title).IsRequired().HasMaxLength(100);
builder.Property(x => x.Author).IsRequired().HasMaxLength(100);
builder.Property(x => x.Description).IsRequired().HasMaxLength(500);
builder.Property(x => x.Category).IsRequired().HasMaxLength(100);
builder.Property(x => x.Language).IsRequired().HasMaxLength(50);
builder.Property(x => x.TotalPages).IsRequired();
// Dati di seed
builder.HasData(
new BookModel
{
Id = Guid.NewGuid(),
Title = "The Alchemist",
Author = "Paulo Coelho",
Description = "The Alchemist follows the journey of an Andalusian shepherd",
Category = "Fiction",
Language = "English",
TotalPages = 208
},
new BookModel
{
Id = Guid.NewGuid(),
Title = "To Kill a Mockingbird",
Author = "Harper Lee",
Description = "A novel about the serious issues of rape and racial inequality.",
Category = "Fiction",
Language = "English",
TotalPages = 281
},
new BookModel
{
Id = Guid.NewGuid(),
Title = "1984",
Author = "George Orwell",
Description = "A dystopian social science fiction novel and cautionary tale about the dangers of totalitarianism. ",
Category = "Fiction",
Language = "English",
TotalPages = 328
}
);
}
}
}
Analizziamo il codice sopra:
In Entity Framework Core, puoi utilizzare l’interfaccia IEntityTypeConfiguration
per configurare il tipo di entità e i dati di inizializzazione per il database. La classe BookTypeConfigurations
implementa l’interfaccia IEntityTypeConfiguration<BookModel>
e fornisce la configurazione per l’entità BookModel
.
-
Metodo Configure: Questo metodo viene utilizzato per configurare il tipo di entità
BookModel
. Definisce il nome della tabella, la chiave primaria e le proprietà per l’entitàBookModel
.-
Nome della Tabella: Il metodo
ToTable
specifica il nome della tabella da creare nel database. In questo caso, il nome della tabella è impostato su “Books”. -
Chiave Primaria: Il metodo
HasKey
specifica la chiave primaria per l’entitàBookModel
. La chiave primaria è impostata sulla proprietàId
. -
Proprietà: Il metodo
Property
configura le proprietà dell’entitàBookModel
. Specifica il tipo di dati, la lunghezza e i vincoli per ogni proprietà.
-
-
Dati di Inizializzazione: Il metodo
HasData
inizializza il database con dati iniziali. Crea tre oggettiBookModel
con dati di esempio per testare gli endpoint dell’API.
Ora che abbiamo creato la classe BookTypeConfigurations
, dobbiamo registrare questa configurazione nella classe ApplicationContext
. Questo garantisce che la configurazione venga applicata quando il database viene creato o migrato.
Finalmente siamo quasi pronti per testare la nostra API. Ma prima di farlo, dobbiamo eseguire le migrazioni per creare il database e applicare i dati iniziali.
Ricordate che abbiamo aggiunto la stringa di connessione del nostro database nel file appsettings.json
? Ora eseguiamo una migrazione e in seguito aggiorniamo il nostro database affinché la migrazione abbia effetto.
Come Eseguire una Migrazione
Le migrazioni vi permettono di aggiornare lo schema del database in base alle modifiche apportate alle vostre classi modello. In Entity Framework Core, potete utilizzare il comando dotnet ef migrations add
per creare una nuova migrazione che rifletta queste modifiche.
Per eseguire una migrazione, eseguite il seguente comando nella terminale:
dotnet ef migrations add InitialCreate
Se il comando ha successo, dovreste vedere un output simile a questo:
Build started...
Build succeeded.
Done. To undo this action, use 'ef migrations remove'
Ora vedrete una nuova cartella chiamata Migrations
nel vostro progetto. Questa cartella contiene i file di migrazione creati in base alle modifiche apportate alle vostre classi modello. Questi file di migrazione includono i comandi SQL necessari per aggiornare lo schema del database.
Come Aggiornare il Database
Dopo aver creato la migrazione, dovete applicare la migrazione per aggiornare lo schema del database. Potete utilizzare il comando dotnet ef database update
per applicare la migrazione e aggiornare il database. Assicuratevi che il SQL Server sia in esecuzione.
Eseguite il seguente comando nella terminale:
dotnet ef database update
Questo aggiornerà lo schema del database in base alle modifiche apportate alle vostre classi modello. Assicuratevi che non ci siano errori nella vostra stringa di connessione del database.
Come Testare gli Endpoint dell’API
Ora possiamo testare i nostri endpoint utilizzando Swagger. Per farlo, esegui l’applicazione digitando il seguente comando nel terminale:
dotnet run
Questo avvierà la nostra applicazione. Puoi aprire il tuo browser e navigare su https://localhost:5001/swagger/index.html
per accedere alla documentazione di Swagger. Dovresti vedere un elenco di endpoint API, modelli di richiesta e risposta e la possibilità di testare gli endpoint direttamente dal browser.
Se il tuo numero di porta è diverso da 5001
, non preoccuparti – funzionerà comunque. La porta potrebbe cambiare a seconda del tipo di macchina che stai utilizzando, ma otterrai comunque lo stesso risultato.
Come Testare l’Endpoint Get All Books
Per testare l’endpoint Get All Books
, segui questi passaggi:
-
Nella documentazione di Swagger, clicca sull’endpoint
GET /api/v1/books
. -
Clicca sul pulsante
Provalo
. -
Clicca sul pulsante
Esegui
.
Questo invierà una richiesta all’API per recuperare tutti i libri nel database.
Dovresti vedere la risposta dell’API, che includerà l’elenco dei libri che sono stati inseriti nel database.
L’immagine seguente mostra la risposta dell’API:
Come Testare l’Endpoint Get Book by ID
Per testare l’endpoint Get Book by ID
, segui questi passaggi:
-
Nella documentazione Swagger, clicca sull’endpoint
GET /api/v1/books/{id}
. -
Inserisci l’ID di un libro nel campo
id
. Puoi utilizzare uno degli ID dei libri che è stato inserito nel database. -
Clicca sul pulsante
Prova
.
Questo invierà una richiesta all’API per recuperare il libro con l’ID specificato. Dovresti vedere la risposta dell’API, che includerà il libro con l’ID specificato.
L’immagine seguente mostra la risposta dell’API:
Come Testare l’Endpoint Add Book
Per testare l’endpoint Add Book
, segui questi passaggi:
-
Nella documentazione Swagger, clicca sull’endpoint
POST /api/v1/books
. -
Clicca sul pulsante
Prova
. -
Inserisci i dettagli del libro nel corpo della richiesta.
-
Fai clic sul pulsante
Esegui
.
Questo invierà una richiesta all’API per aggiungere un nuovo libro al database.
Dovresti vedere la risposta dall’API, che includerà il libro appena creato.
L’immagine seguente mostra la risposta dall’API:
Come Testare l’Endpoint Aggiorna Libro
Per testare l’endpoint Aggiorna Libro
, segui questi passaggi:
-
Nella documentazione di Swagger, fai clic sull’endpoint
PUT /api/v1/books/{id}
. -
Inserisci l’ID di un libro nel campo
id
. Puoi usare l’id di uno dei libri che abbiamo appena aggiunto. -
Fai clic sul pulsante
Provalo
.
Questo invierà una richiesta all’API per aggiornare il libro con l’ID specificato.
Dovresti vedere la risposta dall’API, che includerà il libro aggiornato.
L’immagine seguente mostra la risposta dall’API:
Come Testare l’Endpoint Elimina Libro
Per testare l’endpoint Elimina Libro
, segui questi passaggi:
-
Nella documentazione di Swagger, fai clic sull’endpoint
DELETE /api/v1/books/{id}
. -
Inserisci l’ID di un libro nel campo
id
. Puoi utilizzare uno qualsiasi degli ID dei libri che abbiamo appena aggiunto o dei dati preimpostati. -
Fai clic sul pulsante
Provalo
.
Questo invierà una richiesta all’API per eliminare il libro con l’ID specificato.
L’immagine qui sotto mostra la risposta dall’API:
Congratulazioni! Hai implementato tutte le operazioni CRUD per i libri e testato i punti terminali dell’API utilizzando Swagger, verificando che funzionino come previsto. Ora puoi ampliare questa base per aggiungere ulteriori funzionalità e caratteristiche alla tua API.
Conclusione
Questo manuale ha esplorato come creare un’API minima in ASP.NET Core con .NET 8. Abbiamo costruito un’API di libri completa che supporta le operazioni CRUD, implementato eccezioni personalizzate, definito e registrato i punti terminali dell’API e abilitato la documentazione Swagger per facilitare i test.
Seguendo questo tutorial, hai acquisito una solida base per la creazione di API minime con ASP.NET Core. Ora puoi applicare queste conoscenze e creare API robuste per vari settori e industrie.
Spero che tu abbia trovato questo tutorial utile e informativo. Grazie per aver letto!
Non esitare a connetterti con me sui social media:
Source:
https://www.freecodecamp.org/news/create-a-minimal-api-in-net-core-handbook/