Files
git.stella-ops.org/docs/modules/gateway/openapi.md
master cc69d332e3
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
Add unit tests for RabbitMq and Udp transport servers and clients
- Implemented comprehensive unit tests for RabbitMqTransportServer, covering constructor, disposal, connection management, event handlers, and exception handling.
- Added configuration tests for RabbitMqTransportServer to validate SSL, durable queues, auto-recovery, and custom virtual host options.
- Created unit tests for UdpFrameProtocol, including frame parsing and serialization, header size validation, and round-trip data preservation.
- Developed tests for UdpTransportClient, focusing on connection handling, event subscriptions, and exception scenarios.
- Established tests for UdpTransportServer, ensuring proper start/stop behavior, connection state management, and event handling.
- Included tests for UdpTransportOptions to verify default values and modification capabilities.
- Enhanced service registration tests for Udp transport services in the dependency injection container.
2025-12-05 19:01:12 +02:00

12 KiB

Gateway OpenAPI Implementation

This document describes the implementation architecture of OpenAPI document aggregation in the StellaOps Router Gateway.

Architecture

The Gateway generates OpenAPI 3.1.0 documentation by aggregating schemas and endpoint metadata from connected microservices.

Component Overview

┌─────────────────────────────────────────────────────────────────────┐
│                         Gateway                                      │
├─────────────────────────────────────────────────────────────────────┤
│                                                                      │
│  ┌──────────────────┐    ┌────────────────────┐                     │
│  │ ConnectionManager │───►│ InMemoryRoutingState│                    │
│  │                   │    │                    │                     │
│  │ - OnHelloReceived │    │ - Connections[]    │                     │
│  │ - OnConnClosed    │    │ - Endpoints        │                     │
│  └──────────────────┘    │ - Schemas          │                     │
│           │               └─────────┬──────────┘                     │
│           │                         │                                │
│           ▼                         ▼                                │
│  ┌──────────────────┐    ┌────────────────────┐                     │
│  │ OpenApiDocument  │◄───│ GatewayOpenApi     │                     │
│  │ Cache            │    │ DocumentCache      │                     │
│  │                  │    │                    │                     │
│  │ - Invalidate()   │    │ - TTL expiration   │                     │
│  └──────────────────┘    │ - ETag generation  │                     │
│                          └─────────┬──────────┘                     │
│                                    │                                │
│                                    ▼                                │
│                          ┌────────────────────┐                     │
│                          │ OpenApiDocument    │                     │
│                          │ Generator          │                     │
│                          │                    │                     │
│                          │ - GenerateInfo()   │                     │
│                          │ - GeneratePaths()  │                     │
│                          │ - GenerateTags()   │                     │
│                          │ - GenerateSchemas()│                     │
│                          └─────────┬──────────┘                     │
│                                    │                                │
│                                    ▼                                │
│                          ┌────────────────────┐                     │
│                          │ ClaimSecurity      │                     │
│                          │ Mapper             │                     │
│                          │                    │                     │
│                          │ - SecuritySchemes  │                     │
│                          │ - SecurityRequire  │                     │
│                          └────────────────────┘                     │
│                                                                      │
└─────────────────────────────────────────────────────────────────────┘

Components

Component File Responsibility
IOpenApiDocumentGenerator OpenApi/IOpenApiDocumentGenerator.cs Interface for document generation
OpenApiDocumentGenerator OpenApi/OpenApiDocumentGenerator.cs Builds OpenAPI 3.1.0 JSON
IGatewayOpenApiDocumentCache OpenApi/IGatewayOpenApiDocumentCache.cs Interface for document caching
GatewayOpenApiDocumentCache OpenApi/GatewayOpenApiDocumentCache.cs TTL + invalidation caching
ClaimSecurityMapper OpenApi/ClaimSecurityMapper.cs Maps claims to OAuth2 scopes
OpenApiEndpoints OpenApi/OpenApiEndpoints.cs HTTP endpoint handlers
OpenApiAggregationOptions OpenApi/OpenApiAggregationOptions.cs Configuration options

OpenApiDocumentGenerator

Generates the complete OpenAPI 3.1.0 document from routing state.

Process Flow

  1. Collect connections from IGlobalRoutingState
  2. Generate info section from OpenApiAggregationOptions
  3. Generate paths by iterating all endpoints across connections
  4. Generate components including schemas and security schemes
  5. Generate tags from unique service names

Schema Handling

Schemas are prefixed with service name to avoid naming conflicts:

var prefixedId = $"{conn.Instance.ServiceName}_{schemaId}";
// billing_CreateInvoiceRequest

Operation ID Generation

Operation IDs follow a consistent pattern:

var operationId = $"{serviceName}_{path}_{method}";
// billing_invoices_POST

GatewayOpenApiDocumentCache

Implements caching with TTL expiration and content-based ETags.

Cache Behavior

Trigger Action
First request Generate and cache document
Subsequent requests (within TTL) Return cached document
TTL expired Regenerate document
Connection added/removed Invalidate cache

ETag Generation

ETags are computed from SHA256 hash of document content:

var hash = SHA256.HashData(Encoding.UTF8.GetBytes(documentJson));
var etag = $"\"{Convert.ToHexString(hash)[..16]}\"";

Thread Safety

The cache uses locking to ensure thread-safe regeneration:

lock (_lock)
{
    if (_cachedDocument is null || IsExpired())
    {
        RegenerateDocument();
    }
}

ClaimSecurityMapper

Maps endpoint claim requirements to OpenAPI security schemes.

Security Scheme Generation

Always generates BearerAuth scheme. Generates OAuth2 scheme only when endpoints have claim requirements:

public static JsonObject GenerateSecuritySchemes(
    IEnumerable<EndpointDescriptor> endpoints,
    string tokenUrl)
{
    var schemes = new JsonObject();

    // Always add BearerAuth
    schemes["BearerAuth"] = new JsonObject { ... };

    // Collect scopes from all endpoints
    var scopes = CollectScopes(endpoints);

    // Add OAuth2 only if scopes exist
    if (scopes.Count > 0)
    {
        schemes["OAuth2"] = GenerateOAuth2Scheme(tokenUrl, scopes);
    }

    return schemes;
}

Per-Operation Security

Each endpoint with claims gets a security requirement:

public static JsonArray GenerateSecurityRequirement(EndpointDescriptor endpoint)
{
    if (endpoint.RequiringClaims.Count == 0)
        return new JsonArray(); // No security required

    return new JsonArray
    {
        new JsonObject
        {
            ["BearerAuth"] = new JsonArray(),
            ["OAuth2"] = new JsonArray(claims.Select(c => c.Type))
        }
    };
}

Configuration Reference

OpenApiAggregationOptions

Property Type Default Description
Title string "StellaOps Gateway API" API title
Description string "Unified API..." API description
Version string "1.0.0" API version
ServerUrl string "/" Base server URL
CacheTtlSeconds int 60 Cache TTL
Enabled bool true Enable/disable
LicenseName string "AGPL-3.0-or-later" License name
ContactName string? null Contact name
ContactEmail string? null Contact email
TokenUrl string "/auth/token" OAuth2 token URL

YAML Configuration

OpenApi:
  Title: "My Gateway API"
  Description: "Unified API for all microservices"
  Version: "2.0.0"
  ServerUrl: "https://api.example.com"
  CacheTtlSeconds: 60
  Enabled: true
  LicenseName: "AGPL-3.0-or-later"
  ContactName: "API Team"
  ContactEmail: "api@example.com"
  TokenUrl: "/auth/token"

Service Registration

Services are registered via dependency injection in ServiceCollectionExtensions:

services.Configure<OpenApiAggregationOptions>(
    configuration.GetSection("OpenApi"));
services.AddSingleton<IOpenApiDocumentGenerator, OpenApiDocumentGenerator>();
services.AddSingleton<IGatewayOpenApiDocumentCache, GatewayOpenApiDocumentCache>();

Endpoints are mapped in ApplicationBuilderExtensions:

app.MapGatewayOpenApiEndpoints();

Cache Invalidation

The ConnectionManager invalidates the cache on connection changes:

private Task HandleHelloReceivedAsync(ConnectionState state, HelloPayload payload)
{
    _routingState.AddConnection(state);
    _openApiCache?.Invalidate(); // Invalidate on new connection
    return Task.CompletedTask;
}

private Task HandleConnectionClosedAsync(string connectionId)
{
    _routingState.RemoveConnection(connectionId);
    _openApiCache?.Invalidate(); // Invalidate on disconnect
    return Task.CompletedTask;
}

Extension Points

Custom Routing Plugins

The Gateway supports custom routing plugins via IRoutingPlugin. While not directly related to OpenAPI, routing decisions can affect which endpoints are exposed.

Future Enhancements

Potential extension points for future development:

  • Schema Transformers: Modify schemas before aggregation
  • Tag Customization: Custom tag generation logic
  • Response Examples: Include example responses from connected services
  • Webhooks: Notify external systems on document changes

Testing

Unit tests are located in src/Gateway/__Tests/StellaOps.Gateway.WebService.Tests/OpenApi/:

Test File Coverage
OpenApiDocumentGeneratorTests.cs Document structure, schema merging, tag generation
GatewayOpenApiDocumentCacheTests.cs TTL expiry, invalidation, ETag consistency
ClaimSecurityMapperTests.cs Security scheme generation from claims

Test Patterns

[Fact]
public void GenerateDocument_WithConnections_GeneratesPaths()
{
    // Arrange
    var endpoint = new EndpointDescriptor { ... };
    var connection = CreateConnection("inventory", "1.0.0", endpoint);
    _routingState.Setup(x => x.GetAllConnections()).Returns([connection]);

    // Act
    var document = _sut.GenerateDocument();

    // Assert
    var doc = JsonDocument.Parse(document);
    doc.RootElement.GetProperty("paths")
        .TryGetProperty("/api/items", out _)
        .Should().BeTrue();
}

See Also