NativeLambdaRouter.SourceGenerator.OpenApi 1.3.1

dotnet add package NativeLambdaRouter.SourceGenerator.OpenApi --version 1.3.1
                    
NuGet\Install-Package NativeLambdaRouter.SourceGenerator.OpenApi -Version 1.3.1
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="NativeLambdaRouter.SourceGenerator.OpenApi" Version="1.3.1">
  <PrivateAssets>all</PrivateAssets>
  <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="NativeLambdaRouter.SourceGenerator.OpenApi" Version="1.3.1" />
                    
Directory.Packages.props
<PackageReference Include="NativeLambdaRouter.SourceGenerator.OpenApi">
  <PrivateAssets>all</PrivateAssets>
  <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add NativeLambdaRouter.SourceGenerator.OpenApi --version 1.3.1
                    
#r "nuget: NativeLambdaRouter.SourceGenerator.OpenApi, 1.3.1"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package NativeLambdaRouter.SourceGenerator.OpenApi@1.3.1
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=NativeLambdaRouter.SourceGenerator.OpenApi&version=1.3.1
                    
Install as a Cake Addin
#tool nuget:?package=NativeLambdaRouter.SourceGenerator.OpenApi&version=1.3.1
                    
Install as a Cake Tool

NativeOpenApiGenerator

NuGet License: MIT

A Roslyn Source Generator that automatically generates OpenAPI 3.1 specifications from NativeLambdaRouter endpoint configurations at compile time.

Features

  • Compile-Time Generation: OpenAPI specs are generated during build, not at runtime
  • Zero Runtime Overhead: No reflection or dynamic code generation
  • NativeLambdaRouter Integration: Automatic discovery of MapGet, MapPost, etc. endpoints
  • Type-Safe: Extracts request/response types from generic parameters
  • OpenAPI 3.1 Compliant: Generates valid OpenAPI 3.1 YAML specifications

Installation

dotnet add package NativeOpenApiGenerator

Quick Start

1. Define your routes

The generator automatically discovers endpoints in your ConfigureRoutes method:

public class MyRouter : RoutedApiGatewayFunction
{
    protected override void ConfigureRoutes(IRouteBuilder routes)
    {
        routes.MapGet<GetItemsCommand, GetItemsResponse>("/v1/items", ctx => new GetItemsCommand());
        routes.MapPost<CreateItemCommand, CreateItemResponse>("/v1/items", ctx => Deserialize<CreateItemCommand>(ctx.Body!));
        routes.MapGet<GetItemByIdCommand, GetItemByIdResponse>("/v1/items/{id}", ctx => new GetItemByIdCommand(ctx.PathParameters["id"]));
        routes.MapPut<UpdateItemCommand, UpdateItemResponse>("/v1/items/{id}", ctx => Deserialize<UpdateItemCommand>(ctx.Body!));
        routes.MapDelete<DeleteItemCommand, DeleteItemResponse>("/v1/items/{id}", ctx => new DeleteItemCommand(ctx.PathParameters["id"]));
    }
}

2. Build your project

The generator runs automatically during compilation. No additional configuration needed!

3. Access the generated spec

The class is generated in the {AssemblyName}.Generated namespace:

using MyProject.Generated;

// Get the full OpenAPI YAML specification
string yaml = GeneratedOpenApiSpec.YamlContent;

// Get endpoint count
int count = GeneratedOpenApiSpec.EndpointCount;

// Get list of all endpoints
foreach (var (method, path) in GeneratedOpenApiSpec.EndpointList)
{
    Console.WriteLine($"{method} {path}");
}

// Use as IGeneratedOpenApiSpec (when NativeOpenApi is referenced)
IGeneratedOpenApiSpec spec = GeneratedOpenApiSpec.Instance;

Generated Output

The generator creates a GeneratedOpenApiSpec class in the {AssemblyName}.Generated namespace.

When NativeOpenApi is referenced, it implements IGeneratedOpenApiSpec:

// For assembly "MyProject" with NativeOpenApi referenced
namespace MyProject.Generated;

public sealed class GeneratedOpenApiSpec : Native.OpenApi.IGeneratedOpenApiSpec
{
    public static readonly GeneratedOpenApiSpec Instance = new();

    public const string YamlContent = @"
openapi: ""3.1.0""
info:
  title: ""MyProject""
  version: ""1.0.0""
paths:
  /v1/items:
    get:
      operationId: getV1Items
      ...
";

    public const int EndpointCount = 5;
    
    public static readonly (string Method, string Path)[] EndpointList = new[]
    {
        ("DELETE", "/v1/items/{id}"),
        ("GET", "/v1/items"),
        ("GET", "/v1/items/{id}"),
        ("POST", "/v1/items"),
        ("PUT", "/v1/items/{id}"),
    };
}

Without NativeOpenApi, the class is standalone (no interface).

Supported Mapping Methods

The generator detects all NativeLambdaRouter mapping methods:

Method HTTP Verb
MapGet<TCommand, TResponse> GET
MapPost<TCommand, TResponse> POST
MapPut<TCommand, TResponse> PUT
MapDelete<TCommand, TResponse> DELETE
MapPatch<TCommand, TResponse> PATCH
Map<TCommand, TResponse> Custom (first argument)

Generated Features

For each endpoint, the generator creates:

  • Operation ID: Auto-generated from HTTP method and path (e.g., getV1Items)
  • Summary: Generated from command type name
  • Tags: Extracted from path segments for grouping
  • Security: JWT Bearer authentication by default
  • Parameters: Path parameters extracted from route template
  • Request Body: For POST, PUT, PATCH methods with schema reference
  • Responses: Success response with schema + standard error responses

Integration with NativeOpenApi

Combine with NativeOpenApi for a complete solution:

using Native.OpenApi;
using MyProject.Generated;

// Use the generated spec as part of your document loading
public class MyOpenApiDocumentLoader : OpenApiDocumentLoaderBase
{
    public MyOpenApiDocumentLoader(OpenApiResourceReader reader) : base(reader) { }

    public override IReadOnlyList<OpenApiDocumentPart> LoadCommon() => [];

    public override IReadOnlyList<OpenApiDocumentPart> LoadPartials()
    {
        return new List<OpenApiDocumentPart>
        {
            // Load from generated spec via IGeneratedOpenApiSpec
            LoadFromGeneratedSpec("my-api", GeneratedOpenApiSpec.Instance),
            // Load additional partials
            Load("schemas", "openapi/schemas.yaml")
        };
    }
}

Multi-Project Architecture

The generator uses the assembly name as namespace, so each project gets its own unique class:

Functions.Admin      → namespace Functions.Admin.Generated      → GeneratedOpenApiSpec
Functions.Identity   → namespace Functions.Identity.Generated   → GeneratedOpenApiSpec
Functions.OpenId     → namespace Functions.OpenId.Generated     → GeneratedOpenApiSpec

When NativeOpenApi is referenced, the generated class implements IGeneratedOpenApiSpec, enabling the Functions.OpenApi project to merge all specs polymorphically:

// In Functions.OpenApi — merges all generated specs into a single document
public class ConsolidatedOpenApiDocumentLoader : OpenApiDocumentLoaderBase
{
    public ConsolidatedOpenApiDocumentLoader(OpenApiResourceReader reader) : base(reader) { }

    public override IReadOnlyList<OpenApiDocumentPart> LoadCommon()
    {
        return [Load("schemas", "openapi/schemas.yaml"),
                Load("responses", "openapi/responses.yaml"),
                Load("security", "openapi/security.yaml")];
    }

    public override IReadOnlyList<OpenApiDocumentPart> LoadPartials()
    {
        return [LoadFromGeneratedSpec("admin", Functions.Admin.Generated.GeneratedOpenApiSpec.Instance),
                LoadFromGeneratedSpec("identity", Functions.Identity.Generated.GeneratedOpenApiSpec.Instance),
                LoadFromGeneratedSpec("openid", Functions.OpenId.Generated.GeneratedOpenApiSpec.Instance)];
    }
}

Each Function project only needs:


<PackageReference Include="NativeOpenApiGenerator" Version="1.3.1" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
<PackageReference Include="NativeOpenApi" Version="1.3.0" />

And the consolidator project:


<PackageReference Include="NativeOpenApi" Version="1.3.0" />
<ProjectReference Include="..\Functions.Admin\Functions.Admin.csproj" />
<ProjectReference Include="..\Functions.Identity\Functions.Identity.csproj" />
<ProjectReference Include="..\Functions.OpenId\Functions.OpenId.csproj" />

Custom Namespace with OpenApiSpecName (v1.3.1+)

By default the generator uses the assembly name as the namespace base. This works fine in most cases, but AWS Lambda custom runtime projects typically set AssemblyName=bootstrap for all functions — causing namespace collisions.

Use the OpenApiSpecName MSBuild property to override the namespace base:


<PropertyGroup>
  <AssemblyName>bootstrap</AssemblyName>
  <OpenApiSpecName>NativeGuardBackend.Functions.Admin</OpenApiSpecName>
  <OpenApiSpecTitle>Admin API</OpenApiSpecTitle> 
</PropertyGroup>

This generates:

namespace NativeGuardBackend.Functions.Admin.Generated;

public sealed class GeneratedOpenApiSpec : Native.OpenApi.IGeneratedOpenApiSpec
{
    // YAML title: "Admin API"
    public const string YamlContent = @"...";
}

Priority:

Property Fallback Used For
OpenApiSpecName AssemblyName Namespace base ({value}.Generated)
OpenApiSpecTitle OpenApiSpecName (dots → spaces) YAML info.title field

Example for multi-Lambda setup:


<PropertyGroup>
  <AssemblyName>bootstrap</AssemblyName>
  <OpenApiSpecName>NativeGuardBackend.Functions.Admin</OpenApiSpecName>
</PropertyGroup>


<PropertyGroup>
  <AssemblyName>bootstrap</AssemblyName>
  <OpenApiSpecName>NativeGuardBackend.Functions.Identity</OpenApiSpecName>
</PropertyGroup>


<PropertyGroup>
  <AssemblyName>bootstrap</AssemblyName>
  <OpenApiSpecName>NativeGuardBackend.Functions.OpenId</OpenApiSpecName>
</PropertyGroup>

Each produces a unique namespace even though all assemblies are named bootstrap.

Requirements

  • .NET 6.0 or later (for Source Generator support)
  • NativeLambdaRouter for endpoint definitions
  • C# 9.0 or later

How It Works

  1. Syntax Analysis: The generator scans your code for Map* method invocations
  2. Semantic Analysis: Validates that calls are on IRouteBuilder and extracts type information
  3. Code Generation: Creates the GeneratedOpenApiSpec class with the OpenAPI YAML
  4. Build Integration: The generated file is automatically included in compilation — no extra configuration needed

Note: The generated class is injected directly into the compilation in memory. You do not need to add EmitCompilerGeneratedFiles to your .csproj for the generator to work. That setting only saves a physical copy of the generated .cs files to disk for inspection/debug purposes.

<details> <summary>🔍 Debug: Inspecting generated files on disk</summary>

If you want to see the generated .cs files physically on disk, add to your .csproj:

<PropertyGroup>
  
  <EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
</PropertyGroup>

The files will be saved to:

obj/Debug/net10.0/generated/NativeLambdaRouter.SourceGenerator.OpenApi/
    NativeLambdaRouter.SourceGenerator.OpenApi.OpenApiSourceGenerator/
        GeneratedOpenApiSpec.g.cs

</details>

  • NativeOpenApi - OpenAPI document loading, linting, merging, and rendering

License

MIT

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

This package has no dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.3.1 28 2/11/2026
1.3.0 30 2/11/2026
1.2.6 28 2/11/2026
1.2.5 32 2/11/2026
1.2.4 31 2/11/2026
1.2.3 38 2/9/2026