Ocelot API Gateway

repository·develop·Indexed 27 days ago

https://github.com/threemammals/ocelot

A .NET-based API gateway for microservices architectures that acts as a single entry point for HTTP(S) requests. Implemented as ASP.NET Core middleware, it provides features for routing, transformation, caching, rate limiting, and service discovery via providers like Consul, Kubernetes, Eureka, and Service Fabric. It supports .NET 8, 9, and 10, and offers extension packages for Quality of Service (Polly) and various discovery mechanisms.

Tokens
57.1K
Snippets
161
Records
258
Agent score
91%

What's inside Ocelot

  1. Overview of Ocelot API Gateway

    develop

    Ocelot is a .NET API gateway designed for microservices (service-oriented) architectures. It provides a unified entry point for systems that communicate via HTTP(S).

    Ocelot is implemented as a series of ASP.NET Core middlewares. The pipeline works by:

    1. Manipulating the HttpRequest object based on configuration.
    2. Using a request builder middleware to create a HttpRequestMessage.
    3. Making the request to a downstream service via a dedicated middleware.
    4. Mapping the downstream HttpResponseMessage back onto the HttpResponse object to return it to the client.
  2. Overview of Ocelot features

    develop

    Ocelot's capabilities are organized into three functional groups:

    • Primary Features: Core functionalities used in even minimal setups, specifically Configuration and Routing.
    • Solid Features: Unique, independent features that do not contain subfeatures or relate to other features. Examples include Caching, Delegating Handlers, Quality of Service, and Rate Limiting.
    • Hybrid Features: Features that have multiple relationships with other features and can be part of other features. Examples include Administration, Aggregation, Authentication, Configuration, Dependency Injection, and Load Balancer.
    • Feature Families: Large groups consisting of multiple subfeatures, such as Configuration, Routing, Logging, Transformations, and Service Discovery.
  3. Understand the Ocelot architecture and request pipeline

    develop

    Ocelot is an API Gateway designed for .NET microservices (SOA) architectures. It functions as a unified entry point for systems communicating via HTTP(S) on any platform supported by ASP.NET Core.

    Ocelot operates as a series of ASP.NET Core middlewares. The request lifecycle follows this pattern:

    1. Request Manipulation: Ocelot middlewares manipulate the HttpRequest object based on your configuration.
    2. Request Building: A request builder middleware converts the HttpRequest into a HttpRequestMessage.
    3. Downstream Execution: The final middleware in the Ocelot pipeline makes the actual request to the downstream service. This middleware does not call the next middleware in the chain.
    4. Response Mapping: As the request travels back up the pipeline, a middleware maps the downstream HttpResponseMessage back onto the HttpResponse object to be returned to the client.
  4. WebSocket Feature Roadmap and Status

    develop

    The current implementation of the WebSockets feature in Ocelot is based on the WebSocketsProxyMiddleware class and is considered obsolete. The Ocelot team intends to migrate or redesign this feature to align with the native ASP.NET Core WebSocketMiddleware.

    Users are encouraged to stay updated with official .NET documentation for WebSockets and SignalR as these technologies evolve.

  5. Ocelot Configuration Overview

    develop

    Ocelot configuration is composed of four main sections that define how the gateway handles requests. A standard configuration file (typically ocelot.json) contains these sections:

    • Routes: Defines static routes that tell Ocelot how to treat upstream requests. These are generally loaded at startup and are immutable during the app's lifetime.
    • DynamicRoutes: Enables dynamic routing when using a service discovery provider.
    • Aggregates: Allows specifying aggregated routes that compose multiple normal routes into a single JSON response, enabling a Back-end For a Front-end (BFF) architecture.
    • GlobalConfiguration: Provides global settings and allows overriding static route-specific settings to avoid repetitive configuration.
    {
      "Routes": [],
      "DynamicRoutes": [],
      "Aggregates": [],
      "GlobalConfiguration": {}
    }
  6. Understand the Ocelot repository structure

    develop

    The Ocelot repository uses a flat, minimalist organization. Key directories include:

    • src/: Main library source code (the Ocelot NuGet package). Contains sub-folders for Configuration, DependencyInjection, Authentication, RateLimiting, Routing, etc.
    • unit/: Fast, isolated unit tests.
    • acceptance/: Integration and end-to-end scenario tests.
    • benchmark/: Performance benchmarking using BenchmarkDotNet.
    • manual/: Manual testing and demo applications.
    • testing/: Shared test infrastructure (Ocelot.Testing NuGet package).
    • docs/: Documentation source files (reStructuredText).
    • samples/: Example projects and demonstrations.
    • .config/: Build and versioning configuration.
    • .github/: CI/CD workflows and GitHub settings.
  7. Explore Ocelot ecosystem and extension packages

    develop

    Ocelot provides several extension packages for specific functionalities like service discovery and quality of service. You can find the latest releases and NuGet packages for the following components:

    • Ocelot: The core library.
    • Ocelot.Discovery.Consul: Consul service discovery.
    • Ocelot.Discovery.Eureka: Eureka service discovery.
    • Ocelot.Discovery.KubeClient: Kubernetes service discovery.
    • Ocelot.QualityOfService.Polly: Quality of service using Polly.
    • Ocelot.Testing: Shared testing infrastructure and utilities.
  8. Understand Ocelot error handling and middleware

    develop

    Ocelot uses a custom error handling mechanism that overrides the standard ASP.NET Core exception handling. The ExceptionHandlerMiddleware is responsible for producing status codes after setting the request-id.

    Status codes are returned in this fallback order:

    1. Native response status: Returned if no exception is present or if a mapped error status is available (excluding 499 and 500).
    2. 499 Client Closed Request: Returned when an OperationCanceledException occurs due to an aborted request. A warning is logged.
    3. 500 Internal Server Error: The fallback status returned when a generic Exception occurs that Ocelot cannot process or map. An error record is logged.
  9. Handling large file uploads and downloads in Kestrel

    develop

    Ocelot is optimized for Kestrel and Docker hosting. However, proxying large files (e.g., 100MB to 1GB+) through the gateway is not recommended due to high CPU/memory consumption and potential network errors. It is better to have client applications integrate directly with persistent storage (CDNs, Blob storage, etc.).

    If you must proxy large files through Ocelot, ensure you are using version 23.0 or higher, as large content proxying was stabilized in this release.

  10. Add custom metadata to routes

    develop

    You can add arbitrary data to your route configurations using the Metadata property. This allows you to store custom information that can be accessed within custom middlewares or delegating handlers to extend Ocelot's behavior.

    Route-level metadata is defined as a JSON dictionary within a specific route object.

    {
      "Routes": [
        {
          "UpstreamPathTemplate": "/posts/{postId}",
          "DownstreamPathTemplate": "/api/posts/{postId}",
          "DownstreamHostAndPorts": [
            { "Host": "localhost", "Port": 80 }
          ],
          "Metadata": {
            "id": "FindPost",
            "plugin1.enabled": "true"
          }
        }
      ]
    }
  11. Implement a custom Service Discovery provider

    develop

    To create a custom service discovery implementation, implement the IServiceDiscoveryProvider interface. Your implementation must provide a GetAsync() method that returns a list of Service objects matching the DownstreamRoute.

    Step 1: Implement the interface

    Create a class that implements IServiceDiscoveryProvider. The constructor should accept IServiceProvider, ServiceProviderConfiguration, and DownstreamRoute.

    Step 2: Configure Ocelot

    In your ocelot.json, set the Type property within GlobalConfiguration.ServiceDiscoveryProvider to the name of your custom class.

    Step 3: Register the provider

    In your Program.cs, register a ServiceDiscoveryFinderDelegate in the DI container to handle the instantiation of your provider.

    // 1. Implementation
    public class MyServiceDiscoveryProvider : IServiceDiscoveryProvider
    {
        private readonly IServiceProvider _serviceProvider;
        private readonly ServiceProviderConfiguration _config;
        private readonly DownstreamRoute _downstreamRoute;
    
        public MyServiceDiscoveryProvider(IServiceProvider serviceProvider, ServiceProviderConfiguration config, DownstreamRoute downstreamRoute)
        {
            _serviceProvider = serviceProvider;
            _config = config;
            _downstreamRoute = downstreamRoute;
        }
    
        public Task<List<Service>> GetAsync()
        {
            var services = new List<Service>();
            // ... logic to add services matching _downstreamRoute
            return services;
        }
    }
    
    // 2. ocelot.json configuration
    // "GlobalConfiguration": {
    //   "ServiceDiscoveryProvider": {
    //     "Type": "MyServiceDiscoveryProvider"
    //   }
    // }
    
    // 3. Registration in Program.cs
    ServiceDiscoveryFinderDelegate serviceDiscoveryFinder = (provider, config, route)
        => new MyServiceDiscoveryProvider(provider, config, route);
    
    builder.Services
        .AddSingleton(serviceDiscoveryFinder)
        .AddOcelot(builder.Configuration);
  12. Configure Rate Limiting by Client Header

    develop

    Ocelot supports partitioned rate limiting using the "By Client's Header" rule (equivalent to the API Key partition in ASP.NET Core).

    When a request enters the pipeline:

    1. Ocelot matches the route.
    2. The middleware identifies the client based on the configured ClientIdHeader.
    3. A dedicated rate limiter counter is assigned to that client for that specific route.
    4. The configured algorithm (Fixed window or Hybrid) is executed.
    5. If the quota is exceeded, Ocelot returns a 429 Too Many Requests status code, along with a body message and the Retry-After header.

    Error Handling:

    • If a client cannot be identified (e.g., missing header or invalid ClientIdHeader value), the request is blocked with a 503 Service Unavailable status.
    • Whitelisted clients (defined via the ClientWhitelist option) are processed without rate limiting.