NativeLambdaRouter.SourceGenerator.OpenApi 1.4.0

There is a newer version of this package available.
See the version list below for details.
dotnet add package NativeLambdaRouter.SourceGenerator.OpenApi --version 1.4.0
                    
NuGet\Install-Package NativeLambdaRouter.SourceGenerator.OpenApi -Version 1.4.0
                    
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.4.0">
  <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.4.0" />
                    
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.4.0
                    
#r "nuget: NativeLambdaRouter.SourceGenerator.OpenApi, 1.4.0"
                    
#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.4.0
                    
#: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.4.0
                    
Install as a Cake Addin
#tool nuget:?package=NativeLambdaRouter.SourceGenerator.OpenApi&version=1.4.0
                    
Install as a Cake Tool

NativeLambdaRouter.SourceGenerator.OpenApi

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
  • Schema Property Introspection: Generates real properties and required from C# record/class types
  • Nullable-Aware: Nullable properties are excluded from required arrays
  • OpenAPI 3.1 Compliant: Generates valid OpenAPI 3.1 YAML specifications

Installation

dotnet add package NativeLambdaRouter.SourceGenerator.OpenApi

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

Schema Property Generation

The generator introspects C# types via Roslyn to produce real OpenAPI schemas with properties, types, formats, and required fields.

Supported Type Mappings

C# Type OpenAPI Type Format
string string
int integer int32
long integer int64
float number float
double number double
decimal number double
bool boolean
DateTime, DateTimeOffset string date-time
DateOnly string date
Guid string uuid
Uri string uri
List<T>, T[], IReadOnlyList<T> array items: {T}
Dictionary<K,V> object
Enum types string enum: [values]
Complex types $ref: "#/components/schemas/TypeName"

Example

public sealed record CreateRoleRequest(
    string RealmId,
    string Name,
    string? Description,        // nullable → not in required
    List<string>? PermissionIds, // nullable array → not in required
    string PerformedBy);

public sealed record CreateRoleResponse(string Id, string Name);

Generates:

components:
  schemas:
    CreateRoleRequest:
      type: object
      properties:
        realmId:
          type: string
        name:
          type: string
        description:
          type: string
        permissionIds:
          type: array
          items:
            type: string
        performedBy:
          type: string
      required:
        - realmId
        - name
        - performedBy
    CreateRoleResponse:
      type: object
      properties:
        id:
          type: string
        name:
          type: string
      required:
        - id
        - name

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="NativeLambdaRouter.SourceGenerator.OpenApi" Version="1.3.3" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
<PackageReference Include="NativeOpenApi" Version="1.3.3" />

And the consolidator project:


<PackageReference Include="NativeOpenApi" Version="1.3.3" />
<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.

Using ProjectReference Instead of NuGet

When developing locally or contributing to this repository, you may reference the Source Generator via ProjectReference instead of PackageReference:

<ProjectReference Include="path\to\NativeLambdaRouter.SourceGenerator.OpenApi.csproj"
                  OutputItemType="Analyzer"
                  ReferenceOutputAssembly="false" />

Important: The .props file that exposes OpenApiSpecName and OpenApiSpecTitle to the Roslyn analyzer is only auto-imported for NuGet packages. When using ProjectReference, you must manually declare CompilerVisibleProperty in your project or a Directory.Build.props:

<Project>
  <ItemGroup>
    <CompilerVisibleProperty Include="OpenApiSpecName" />
    <CompilerVisibleProperty Include="OpenApiSpecTitle" />
  </ItemGroup>
</Project>

Without this, the Source Generator cannot read MSBuild properties and will fall back to AssemblyName for namespace and title.

Automated YAML Extraction (Multi-Lambda)

For multi-Lambda architectures where producers cannot be referenced by the consumer (due to AssemblyName=bootstrap ambiguity), you can use an MSBuild inline task to automatically extract the generated YAML on every build. See the MultiLambdaSample for a complete working example with Directory.Build.targets.

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.6.0 191 2/23/2026
1.5.1 143 2/19/2026
1.5.0 120 2/18/2026
1.4.1 119 2/18/2026
1.4.0 87 2/17/2026
1.3.3 132 2/13/2026
1.3.1 130 2/11/2026
1.3.0 93 2/11/2026
1.2.6 87 2/11/2026
1.2.5 90 2/11/2026
1.2.4 87 2/11/2026
1.2.3 90 2/9/2026