📖 Manuel
Guide Ocelot API Gateway
Workflow — mise en place pas à pas
1. Installer les packages
dotnet add package Ocelot # Core — toujours requis
dotnet add package Ocelot.Provider.Consul # Service Discovery Consul
dotnet add package Ocelot.Provider.Eureka # Service Discovery Eureka
dotnet add package Ocelot.Cache.CacheManager # Cache distribué
dotnet add package Ocelot.Tracing.OpenTracing # Tracing distribué
2. Brancher Ocelot dans Program.cs
// Program.cs (.NET 8+)
var builder = WebApplication.CreateBuilder(args);
// Charge ocelot.json en priorité sur appsettings.json
builder.Configuration
.AddJsonFile("ocelot.json", optional: false, reloadOnChange: true)
.AddJsonFile($"ocelot.{builder.Environment.EnvironmentName}.json",
optional: true, reloadOnChange: true);
builder.Services
.AddOcelot(builder.Configuration)
.AddCacheManager(x => x.WithDictionaryHandle()) // cache en mémoire
.AddConsul() // si Consul utilisé
;
builder.Services.AddAuthentication()
.AddJwtBearer("Bearer", options =>
{
options.Authority = builder.Configuration["Jwt:Authority"];
options.Audience = builder.Configuration["Jwt:Audience"];
});
var app = builder.Build();
await app.UseOcelot();
app.Run();
3. Définir les routes dans ocelot.json
Chaque route = un objet dans "Routes". Minima obligatoires :
{
"Routes": [
{
"DownstreamPathTemplate": "/api/payments/{everything}",
"DownstreamScheme": "https",
"DownstreamHostAndPorts": [
{ "Host": "payment-service", "Port": 8080 }
],
"UpstreamPathTemplate": "/payments/{everything}",
"UpstreamHttpMethod": ["GET", "POST", "PUT", "DELETE"],
"AuthenticationOptions": {
"AuthenticationProviderKey": "Bearer"
},
"RateLimitOptions": {
"EnableRateLimiting": true,
"Period": "1m",
"PeriodTimespan": 60,
"Limit": 100
},
"QoSOptions": {
"ExceptionsAllowedBeforeBreaking": 3,
"DurationOfBreak": 10000,
"TimeoutValue": 5000
},
"FileCacheOptions": {
"TtlSeconds": 30,
"Region": "payments"
}
},
{
"DownstreamPathTemplate": "/api/orders/{everything}",
"DownstreamScheme": "https",
"DownstreamHostAndPorts": [
{ "Host": "order-svc-1", "Port": 8080 },
{ "Host": "order-svc-2", "Port": 8080 }
],
"UpstreamPathTemplate": "/orders/{everything}",
"UpstreamHttpMethod": ["GET", "POST"],
"LoadBalancerOptions": { "Type": "RoundRobin" }
}
],
"GlobalConfiguration": {
"BaseUrl": "https://api.company.com",
"RateLimitOptions": {
"DisableRateLimitHeaders": false,
"QuotaExceededMessage": "Trop de requêtes, réessayez plus tard",
"HttpStatusCode": 429
}
}
}
4. Aggregation de requêtes
Agrège plusieurs appels downstream en une seule réponse upstream. Utiliser la clé "Key" sur chaque route participante :
{
"Routes": [
{
"DownstreamPathTemplate": "/api/users/{userId}",
"UpstreamPathTemplate": "/users/{userId}",
"DownstreamHostAndPorts": [{ "Host": "user-svc", "Port": 8080 }],
"Key": "user"
},
{
"DownstreamPathTemplate": "/api/orders?userId={userId}",
"UpstreamPathTemplate": "/users/{userId}/orders",
"DownstreamHostAndPorts": [{ "Host": "order-svc", "Port": 8080 }],
"Key": "orders"
}
],
"Aggregates": [
{
"RouteKeys": ["user", "orders"],
"UpstreamPathTemplate": "/users/{userId}/profile"
}
]
}
Limite : l'agrégation ne supporte que GET. Pour des cas complexes (POST, transformation de payload), implémenter un custom IDefinedAggregator.
5. Service Discovery avec Consul
builder.Services.AddOcelot().AddConsul();
{
"Routes": [
{
"DownstreamPathTemplate": "/api/{everything}",
"UpstreamPathTemplate": "/payments/{everything}",
"ServiceName": "payment-service",
"LoadBalancerOptions": { "Type": "LeastConnection" }
}
],
"GlobalConfiguration": {
"ServiceDiscoveryProvider": {
"Scheme": "http",
"Host": "consul",
"Port": 8500,
"Type": "Consul",
"PollingInterval": 5000
}
}
}
6. Headers et claims transformation
{
"AddHeadersToRequest": {
"X-Tenant-Id": "Claims[tenant_id] > value"
},
"AddClaimsToRequest": {
"sub": "Claims[sub] > value"
},
"AddQueriesToRequest": {
"clientId": "Claims[client_id] > value"
},
"UpstreamHeaderTransform": {
"X-Forwarded-For": "{RemoteIpAddress}"
},
"DownstreamHeaderTransform": {
"Location": "{DownstreamBaseUrl}/{UpstreamBaseUrl}"
}
}
7. Middleware personnalisé
// Middleware de corrélation avant Ocelot
app.Use(async (ctx, next) =>
{
ctx.Request.Headers["X-Correlation-Id"] =
ctx.Request.Headers.TryGetValue("X-Correlation-Id", out var existing)
? existing.ToString()
: Guid.NewGuid().ToString("N");
await next();
});
await app.UseOcelot();
Critères de décision — Ocelot vs YARP
| Critère | Ocelot | YARP |
|---|---|---|
| Configuration | JSON déclaratif | Code + config |
| Aggregation intégrée | Oui | Non (custom) |
| Service Discovery | Consul, Eureka | Custom |
| Performance | Bonne | Excellente (Microsoft) |
| Maintenance | Communauté | Microsoft officiel |
| Courbe d'apprentissage | Faible | Moyenne |
| Cas d'usage | Équipes petites/moyennes, config déclarative | Proxy haute performance, finops |
Choisir Ocelot si : config JSON suffisante, aggregation native requise, équipe habituée au routing déclaratif. Choisir YARP si : throughput critique (>50k req/s), besoin de transformations complexes en code.
Garde-fous et anti-patterns
Ne pas faire :
- Laisser une route sans
QoSOptions— un service lent bloque toute la gateway. - Partager un seul
ocelot.jsonpour tous les environnements — utiliserocelot.{env}.json. - Utiliser le cache (
FileCacheOptions) sur des routes POST/PUT/DELETE — effets de bord silencieux. - Masquer les erreurs d'aggregation : si un sous-appel échoue, retourner un corps partiel avec un statut
207 Multi-Statuset logger chaque sous-requête individuellement. - Exposer le port Consul admin (
8500) sur le réseau public. - Stocker les secrets (
Jwt:Authority, clés API) en clair dansocelot.json— utiliser les variables d'environnement ou un vault.
Pièges courants :
UpstreamPathTemplatetrop générique (/{everything}) capte tout et masque d'autres routes. Toujours ordonner du plus spécifique au plus général.- L'aggregation retourne HTTP 200 même si les sous-requêtes ont échoué — vérifier chaque body de la réponse agrégée.
reloadOnChange: truesurocelot.jsonpeut causer un reload à chaud en production ; tester en staging d'abord.- Le circuit breaker (
QoSOptions) nécessite le packagePolly— sans lui, les options sont ignorées silencieusement.
Bonnes pratiques 2026
- Versionner
ocelot.jsonavec le code source, jamais dans un ConfigMap Kubernetes non tracé. - Activer les health checks Ocelot avec
/healthet lier à la readiness probe. - Utiliser
LeastConnectionplutôt queRoundRobindès que les services ont des latences inégales. - En Kubernetes, préférer le Service Discovery natif (
Kube) plutôt que Consul sauf si multi-cluster. - Exposer les métriques via OpenTelemetry (
Ocelot.Tracing.OpenTracing) et les consommer dans Grafana. - Limiter le nombre de routes par fichier à ~50 ; au-delà, splitter en fichiers partiels chargés via
AddOcelot(builder.Configuration).