Ocelot API Gateway: Simplifying Microservices Architecture in .NET

Architecture
Ocelot API Gateway: Simplifying Microservices Architecture in .NET

Ocelot API Gateway: Simplifying Microservices Architecture in .NET

In modern microservices architectures, an API Gateway acts as a single entry point for all client requests, routing them to appropriate backend services. Ocelot is an open-source, lightweight API Gateway built specifically for .NET, making it an excellent choice for .NET-based microservices ecosystems.

What is Ocelot?

Ocelot is a .NET API Gateway that provides a simple way to route requests, aggregate responses, and apply cross-cutting concerns like authentication, rate limiting, and caching. It's built on top of ASP.NET Core and leverages its middleware pipeline.

Key Features

  • Request Routing: Route incoming requests to downstream services based on configuration
  • Request Aggregation: Combine multiple service calls into a single response
  • Service Discovery: Integration with Consul, Eureka, and other service discovery tools
  • Load Balancing: Distribute requests across multiple service instances
  • Authentication & Authorization: Centralized security with JWT, OAuth2, and more
  • Rate Limiting: Control request rates to protect backend services
  • Caching: Cache responses to improve performance
  • Quality of Service (QoS): Circuit breaker pattern and retry policies

Getting Started with Ocelot

Installation

First, install the Ocelot NuGet package:

dotnet add package Ocelot

Basic Configuration

Create an ocelot.json configuration file:

{
  "Routes": [
    {
      "DownstreamPathTemplate": "/api/products",
      "DownstreamScheme": "https",
      "DownstreamHostAndPorts": [
        {
          "Host": "localhost",
          "Port": 5001
        }
      ],
      "UpstreamPathTemplate": "/products",
      "UpstreamHttpMethod": [ "GET" ]
    },
    {
      "DownstreamPathTemplate": "/api/orders/{id}",
      "DownstreamScheme": "https",
      "DownstreamHostAndPorts": [
        {
          "Host": "localhost",
          "Port": 5002
        }
      ],
      "UpstreamPathTemplate": "/orders/{id}",
      "UpstreamHttpMethod": [ "GET", "POST", "PUT", "DELETE" ]
    }
  ],
  "GlobalConfiguration": {
    "BaseUrl": "https://localhost:5000"
  }
}

Program.cs Setup

Configure Ocelot in your ASP.NET Core application:

using Ocelot.DependencyInjection;
using Ocelot.Middleware;

var builder = WebApplication.CreateBuilder(args);

// Add Ocelot configuration
builder.Configuration.AddJsonFile("ocelot.json", optional: false, reloadOnChange: true);

// Add Ocelot services
builder.Services.AddOcelot();

var app = builder.Build();

// Use Ocelot middleware
await app.UseOcelot();

app.Run();

Advanced Features

1. Request Aggregation

Combine multiple service calls into a single response:

{
  "Routes": [
    {
      "DownstreamPathTemplate": "/api/products/{id}",
      "DownstreamScheme": "https",
      "DownstreamHostAndPorts": [
        { "Host": "localhost", "Port": 5001 }
      ],
      "UpstreamPathTemplate": "/products/{id}",
      "UpstreamHttpMethod": [ "GET" ],
      "Key": "Products"
    },
    {
      "DownstreamPathTemplate": "/api/reviews/{id}",
      "DownstreamScheme": "https",
      "DownstreamHostAndPorts": [
        { "Host": "localhost", "Port": 5003 }
      ],
      "UpstreamPathTemplate": "/reviews/{id}",
      "UpstreamHttpMethod": [ "GET" ],
      "Key": "Reviews"
    }
  ],
  "Aggregates": [
    {
      "RouteKeys": [ "Products", "Reviews" ],
      "UpstreamPathTemplate": "/productdetails/{id}"
    }
  ]
}

2. Rate Limiting

Protect your services from excessive requests:

{
  "DownstreamPathTemplate": "/api/products",
  "UpstreamPathTemplate": "/products",
  "RateLimitOptions": {
    "ClientWhitelist": [],
    "EnableRateLimiting": true,
    "Period": "1s",
    "PeriodTimespan": 1,
    "Limit": 10
  }
}

3. Authentication with JWT

Secure your gateway with JWT authentication:

using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using System.Text;

var builder = WebApplication.CreateBuilder(args);

// Configure JWT Authentication
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer("Bearer", options =>
    {
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuer = true,
            ValidateAudience = true,
            ValidateLifetime = true,
            ValidateIssuerSigningKey = true,
            ValidIssuer = builder.Configuration["Jwt:Issuer"],
            ValidAudience = builder.Configuration["Jwt:Audience"],
            IssuerSigningKey = new SymmetricSecurityKey(
                Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"]))
        };
    });

builder.Configuration.AddJsonFile("ocelot.json");
builder.Services.AddOcelot();

var app = builder.Build();

app.UseAuthentication();
await app.UseOcelot();

app.Run();

In your ocelot.json:

{
  "DownstreamPathTemplate": "/api/orders",
  "UpstreamPathTemplate": "/orders",
  "AuthenticationOptions": {
    "AuthenticationProviderKey": "Bearer",
    "AllowedScopes": []
  }
}

4. Load Balancing

Distribute requests across multiple instances:

{
  "DownstreamPathTemplate": "/api/products",
  "DownstreamScheme": "https",
  "DownstreamHostAndPorts": [
    { "Host": "localhost", "Port": 5001 },
    { "Host": "localhost", "Port": 5002 },
    { "Host": "localhost", "Port": 5003 }
  ],
  "UpstreamPathTemplate": "/products",
  "LoadBalancerOptions": {
    "Type": "RoundRobin"
  }
}

Available load balancing strategies:

  • LeastConnection: Routes to the service with fewest active connections
  • RoundRobin: Distributes requests evenly across all instances
  • NoLoadBalancer: Uses the first available service

5. Quality of Service (Circuit Breaker)

Implement resilience patterns:

{
  "DownstreamPathTemplate": "/api/products",
  "UpstreamPathTemplate": "/products",
  "QoSOptions": {
    "ExceptionsAllowedBeforeBreaking": 3,
    "DurationOfBreak": 1000,
    "TimeoutValue": 5000
  }
}

6. Caching

Cache responses to improve performance:

builder.Services.AddOcelot()
    .AddCacheManager(x =>
    {
        x.WithDictionaryHandle();
    });
{
  "DownstreamPathTemplate": "/api/products",
  "UpstreamPathTemplate": "/products",
  "FileCacheOptions": {
    "TtlSeconds": 30,
    "Region": "products"
  }
}

Service Discovery Integration

Consul Integration

Integrate with Consul for dynamic service discovery:

dotnet add package Ocelot.Provider.Consul
builder.Services.AddOcelot()
    .AddConsul();
{
  "Routes": [
    {
      "DownstreamPathTemplate": "/api/products",
      "UpstreamPathTemplate": "/products",
      "ServiceName": "product-service",
      "LoadBalancerOptions": {
        "Type": "RoundRobin"
      }
    }
  ],
  "GlobalConfiguration": {
    "ServiceDiscoveryProvider": {
      "Host": "localhost",
      "Port": 8500,
      "Type": "Consul"
    }
  }
}

Best Practices

  1. Use Environment-Specific Configurations: Maintain separate ocelot.json files for different environments
  2. Implement Proper Logging: Use Serilog or similar for comprehensive logging
  3. Enable CORS Carefully: Configure CORS policies appropriately for your frontend applications
  4. Monitor Performance: Use Application Insights or similar tools to monitor gateway performance
  5. Secure Your Gateway: Always use HTTPS and implement proper authentication/authorization
  6. Version Your APIs: Include API versioning in your routing strategy
  7. Use Health Checks: Implement health check endpoints for monitoring

Complete Example: E-Commerce Gateway

{
  "Routes": [
    {
      "DownstreamPathTemplate": "/api/products/{everything}",
      "DownstreamScheme": "https",
      "ServiceName": "product-service",
      "UpstreamPathTemplate": "/products/{everything}",
      "UpstreamHttpMethod": [ "GET", "POST", "PUT", "DELETE" ],
      "AuthenticationOptions": {
        "AuthenticationProviderKey": "Bearer"
      },
      "RateLimitOptions": {
        "EnableRateLimiting": true,
        "Period": "1m",
        "Limit": 100
      },
      "LoadBalancerOptions": {
        "Type": "RoundRobin"
      },
      "QoSOptions": {
        "ExceptionsAllowedBeforeBreaking": 3,
        "DurationOfBreak": 5000,
        "TimeoutValue": 10000
      }
    },
    {
      "DownstreamPathTemplate": "/api/orders/{everything}",
      "DownstreamScheme": "https",
      "ServiceName": "order-service",
      "UpstreamPathTemplate": "/orders/{everything}",
      "UpstreamHttpMethod": [ "GET", "POST", "PUT", "DELETE" ],
      "AuthenticationOptions": {
        "AuthenticationProviderKey": "Bearer"
      }
    },
    {
      "DownstreamPathTemplate": "/api/users/{everything}",
      "DownstreamScheme": "https",
      "ServiceName": "user-service",
      "UpstreamPathTemplate": "/users/{everything}",
      "UpstreamHttpMethod": [ "GET", "POST", "PUT", "DELETE" ],
      "AuthenticationOptions": {
        "AuthenticationProviderKey": "Bearer"
      }
    }
  ],
  "GlobalConfiguration": {
    "BaseUrl": "https://api.myecommerce.com",
    "ServiceDiscoveryProvider": {
      "Host": "consul",
      "Port": 8500,
      "Type": "Consul"
    },
    "RateLimitOptions": {
      "DisableRateLimitHeaders": false,
      "QuotaExceededMessage": "Rate limit exceeded. Please try again later.",
      "HttpStatusCode": 429
    }
  }
}

Advantages of Ocelot

  • Native .NET Integration: Built specifically for .NET ecosystem
  • Lightweight: Minimal overhead and fast performance
  • Easy Configuration: JSON-based configuration is simple and readable
  • Extensible: Custom middleware and delegating handlers support
  • Active Community: Well-maintained with regular updates
  • Production-Ready: Used by many organizations in production

When to Use Ocelot

Ocelot is ideal when:

  • Building microservices with .NET/ASP.NET Core
  • Need a lightweight, simple API Gateway solution
  • Want tight integration with .NET ecosystem
  • Require basic to intermediate gateway features
  • Working with Consul or Eureka for service discovery

Alternatives to Consider

While Ocelot is excellent for .NET, consider these alternatives based on your needs:

  • Kong: More feature-rich, language-agnostic
  • YARP (Yet Another Reverse Proxy): Microsoft's official reverse proxy library
  • Traefik: Cloud-native, automatic service discovery
  • Envoy: High-performance, used in service mesh architectures

Conclusion

Ocelot provides a powerful yet simple solution for implementing API Gateway patterns in .NET microservices architectures. Its configuration-driven approach, combined with robust features like load balancing, rate limiting, and service discovery integration, makes it an excellent choice for .NET developers building distributed systems.

Whether you're starting a new microservices project or modernizing an existing monolith, Ocelot can help you manage complexity, improve security, and enhance the overall architecture of your .NET applications.

Further Reading