YARP (Yet Another Reverse Proxy) è una potente libreria .NET che permette di creare server reverse proxy ad alte prestazioni, pronti per la produzione e altamente personalizzabili.
Per gli sviluppatori impazienti di buttarsi nel codice, il progetto completo è disponibile su GitHub: APIGateway.NET
Perché usare YARP ?
YARP (Yet Another Reverse Proxy) emerge come un’alternativa chiara e potente a Ocelot per l’implementazione di API Gateway in .NET. Offre una soluzione robusta e flessibile, particolarmente adatta per progetti moderni basati su architetture a microservizi.
- Semplicità e chiarezza: A differenza di Ocelot, YARP offre un’API più intuitiva e una documentazione più completa. La sua struttura e il suo utilizzo sono progettati per essere più facilmente comprensibili, riducendo la curva di apprendimento per gli sviluppatori.
- Prestazioni superiori: YARP è ottimizzato per offrire prestazioni elevate, superando Ocelot in scenari di carico intensivo. Supporta nativamente HTTP/2 e gRPC, rendendolo ideale per applicazioni moderne che richiedono alte prestazioni e bassa latenza.
- Maggiore flessibilità: YARP permette una personalizzazione più granulare rispetto a Ocelot. Gli sviluppatori possono facilmente estendere e modificare il comportamento del proxy direttamente attraverso il codice .NET, offrendo un controllo più preciso sulla logica di routing e trasformazione delle richieste.
Implementazione
Creazione soluzione
Usando Visual Studio o il tuo IDE preferito, iniziamo con la creazione della soluzione. A tal fine, è sufficiente creare due progetti ASP.NET Core Web API, come illustrato nell’immagine.
Configurazione progetto APIGateway
Per iniziare la configurazione del progetto che fungerà da punto d’ingresso, devi installare la libreria YARP.ReverseProxy
. Puoi farlo usando il NuGet Package Manager oppure eseguendo questo comando:
dotnet add package Yarp.ReverseProxy
Registrazione servizio
Dopo aver installato la libreria, registrala nei servizi:
using System.Threading.RateLimiting;
using Microsoft.AspNetCore.RateLimiting;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddControllers();
builder.Services.AddHealthChecks();
// YARP - Register Service
builder.Services.AddReverseProxy().LoadFromConfig(builder.Configuration.GetSection("ReverseProxy"));
builder.Services.AddSwaggerGen();
// YARP - Configure RateLimiter Service to prevent DoS attacks
builder.Services.AddRateLimiter(options =>
{
options.AddFixedWindowLimiter("customPolicy", opt =>
{
opt.PermitLimit = 1;
opt.Window = TimeSpan.FromSeconds(4);
opt.QueueProcessingOrder = QueueProcessingOrder.OldestFirst;
opt.QueueLimit = 1;
});
});
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.MapControllers();
app.MapHealthChecks("healthy");
// YARP - Configure RateLimiter Application Part to prevent DoS attacks
app.UseRateLimiter();
// YARP - Add Application Part
app.MapReverseProxy();
await app.RunAsync();
La componente RateLimiter non è indispensabile, ma integrarla aumenterà la sicurezza del gateway. Con la configurazione attuale, il gateway introdurrà un ritardo di 4 secondi nel caso di chiamate simultanee.
Configurazione rotte
Affinché il gateway operi correttamente, è indispensabile configurare le rotte delle diverse applicazioni che saranno ospitate. Modifica il file appsettings.json
aggiungendo la seguente configurazione:
"ReverseProxy": {
"Routes": {
"get-customers": {
"ClusterId": "customers",
"RateLimiterPolicy": "customPolicy",
"Match": {
"Path": "/customers/all",
"Methods": [
"GET"
]
}
},
"create-customer": {
"ClusterId": "customers",
"Match": {
"Path": "/customers/create",
"Methods": [
"POST"
]
},
"Transforms": [
{
"RequestHeader": "X-Added-Website",
"Set": "https://CosminIrimescu.COM"
}
]
}
},
"Clusters": {
"customers": {
"Destinations": {
"customers/destination1": {
"Address": "http://localhost:5010/"
}
}
}
}
}
Configurazione progetto APIGateway.Customers
È il momento di configurare il progetto che esporrà le API attraverso l’APIGateway.
using Microsoft.AspNetCore.Mvc;
namespace APIGateway.Customers.Controllers;
[ApiController]
[Route("[controller]/[action]")]
public class CustomersController : ControllerBase
{
private static readonly List<string> _customers = ["Cst1", "Cst2", "Cst3"];
[HttpGet]
public Task<IActionResult> All()
{
return Task.FromResult<IActionResult>(Ok(_customers));
}
[HttpPost]
public Task<IActionResult> Create([FromQuery] string customer)
{
const string HeaderKeyName = "X-Added-Website";
Request.Headers.TryGetValue(HeaderKeyName, out var headerValue);
_customers.Add(customer);
return Task.FromResult<IActionResult>(Ok(new
{
Customers = _customers,
CustomHeader = headerValue
}));
}
}
Nella funzione Create viene recuperato un header personalizzato, definito nella configurazione delle rotte all’interno del file appsettings.json del progetto APIGateway, e restituito come payload. Sebbene questo header non sia necessario, serve a comprendere le potenzialità di YARP.
Registrazione Controllers
Con l’introduzione di .NET 8, il template ASP.NET Core Web API non registra più automaticamente i controller. Pertanto, è necessario modificare il file Program.cs
per aggiungere manualmente la registrazione e la mappatura dei controller, come mostrato nel codice seguente.
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddControllers();
builder.Services.AddSwaggerGen();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.MapControllers();
await app.RunAsync();
Test Gateway
Ora che l’implementazione è completata, i due progetti possono essere avviati per testare il gateway. Il progetto APIGateway è configurato per l’esecuzione sulla porta 5000, mentre APIGateway.Customers è impostato sulla porta 5010. Con entrambe le applicazioni in esecuzione, è possibile aprire un terminale e testare il gateway utilizzando i seguenti comandi curl:
Creazione nuovo customer
curl --location --request POST 'http://localhost:5000/customers/create?customer=nuovo%20cst'
Elenco dei customers
curl --location 'http://localhost:5000/customers/all'
Conclusione
I gateway API rappresentano un elemento fondamentale nelle architetture moderne, soprattutto quando si tratta di microservizi. Offrono un punto centrale per gestire le richieste, semplificare la comunicazione tra client e servizi, e applicare logiche trasversali come autenticazione, autorizzazione e caching. YARP, in particolare, si distingue per la sua flessibilità e integrazione nativa con ASP.NET Core, rendendolo una scelta eccellente per chi lavora già in questo ecosistema. È una soluzione che consente di affrontare con semplicità le sfide della gestione delle API, adattandosi facilmente a diversi scenari e necessità.