NativeOpenApi 1.7.0

dotnet add package NativeOpenApi --version 1.7.0
                    
NuGet\Install-Package NativeOpenApi -Version 1.7.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="NativeOpenApi" Version="1.7.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="NativeOpenApi" Version="1.7.0" />
                    
Directory.Packages.props
<PackageReference Include="NativeOpenApi" />
                    
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 NativeOpenApi --version 1.7.0
                    
#r "nuget: NativeOpenApi, 1.7.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 NativeOpenApi@1.7.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=NativeOpenApi&version=1.7.0
                    
Install as a Cake Addin
#tool nuget:?package=NativeOpenApi&version=1.7.0
                    
Install as a Cake Tool

NativeOpenApi

NuGet License: MIT

OpenAPI 3.1 primitives for Native AOT .NET 10 — document loading, linting, merging, HTML rendering, and a catalog of UX attributes consumed by NativeLambdaRouter.SourceGenerator.OpenApi.

  • Version: 1.7.0
  • Target: net10.0
  • Namespace root: Native.OpenApi
  • AOT: zero runtime reflection; serialization through source-generated contexts

API surface at a glance

Attributes — Native.OpenApi.Attributes

Attribute Target Purpose Wave 1 §
[HideFromDocs(reason?)] class/struct hide operation from generated YAML F01
[Deprecated(sunset, alternative, reason)] class/struct emit deprecated: true + x-sunset + x-swepay-alternative + x-swepay-deprecation-reason F03
[ApiExample(name, summary) { RequestJson, ResponseStatus, ResponseJson }] (multi-use) class/struct wire named examples into examples maps F09
[ErrorCatalog(typeof(T))] class/struct attach an error-code catalog to the operation F12
[ErrorDefinition(code, httpStatus, userMessage, recovery) { DocUrl }] field (const string) one entry inside a catalog F12
[ApiResponse(statusCode, responseType?, contentType = "application/json")] (multi-use) method (handler's Handle) document per-status responses without the .Produces<T>() fluent v1.6.0

Fluent extension — Native.OpenApi.Extensions

Method Effect
.ExcludeFromDocs() route-level sibling of [HideFromDocs]; identity pass-through at runtime, compile-time marker for the generator

Models — Native.OpenApi.Models

Type Role
SwepayProblemDetails RFC 9457 superset (code, recovery, requestId); generator auto-injects the matching components.schemas entry whenever any operation serves application/problem+json without a typed body (F13)

Rendering — Native.OpenApi.Rendering

Type Role
OpenApiRendererOptions aggregate; .Default = pre-Wave-1 behaviour (no brand, no footer, no Mermaid)
OpenApiBrandingOptions PrimaryColor, AccentColor, LogoUrl, FaviconUrl, FontFamily, ThemeJsonOverride
OpenApiFooterOptions StatusUrl, SupportUrl, ChangelogUrl, SlaUrl, TermsUrl

Core classes

Class Role
OpenApiHtmlRenderer renders Redoc + Scalar HTML; each method has a two-arg overload (legacy) and a three-arg options overload
OpenApiDocumentLoaderBase base for embedded-resource spec loading (JSON + YAML)
OpenApiDocumentMerger merges partial specs into a single document
OpenApiDocumentProvider orchestrates load → merge → lint
OpenApiLinter validates against OpenApiLintOptions rules
OpenApiResourceReader reads embedded resources from an assembly
IGeneratedOpenApiSpec polymorphic access to generator output (implemented automatically when this package is referenced)

Installation

dotnet add package NativeOpenApi

Quick reference — Wave 1 (v1.7.0)

Hide endpoints from docs — F01

[HideFromDocs("internal ops endpoint")]
public sealed record InternalHealthCommand(string Secret);

Or at the route level (handy when the same command is mapped to several paths and only one should be hidden):

using Native.OpenApi.Extensions;

routes.MapGet<ListUsersCommand, ListUsersResponse>("/v1/admin/internal/users", ...)
      .ExcludeFromDocs();

Effect: the operation never appears in paths:. If every operation on a path is hidden, the path itself is dropped.

Deprecation — F03

[Deprecated(
    sunset: "2026-12-31",
    alternative: "POST /v2/orders",
    reason: "v1 doesn't support split payments.")]
public sealed record CreateOrderV1Command(...);

Emits:

deprecated: true
x-sunset: "2026-12-31"
x-swepay-alternative: "POST /v2/orders"
x-swepay-deprecation-reason: "v1 doesn't support split payments."

Named examples — F09

[ApiExample(
    name: "happy-path",
    summary: "Simple order with 1 item",
    RequestJson = "examples/create-order/happy.json",
    ResponseStatus = 201,
    ResponseJson = "examples/create-order/happy-response.json")]
[ApiExample(
    name: "validation-error",
    summary: "Invalid CNPJ",
    ResponseStatus = 422,
    ResponseJson = "examples/create-order/invalid-cnpj.json")]
public sealed record CreateOrderCommand(...);

Examples reference their JSON payload through externalValue (inline payload reading is a Wave 2 follow-up — see docs/CHANGELOG.md).

Error catalog — F12

Declare once:

public static class SwepayErrors
{
    [ErrorDefinition(
        code: "PAYMENT_INSUFFICIENT_FUNDS",
        httpStatus: 402,
        userMessage: "Saldo insuficiente no método de pagamento.",
        recovery: "Tente outro método de pagamento ou adicione saldo.",
        DocUrl = "https://docs.swepay.com.br/errors/PAYMENT_INSUFFICIENT_FUNDS")]
    public const string PaymentInsufficientFunds = "PAYMENT_INSUFFICIENT_FUNDS";
}

Wire on commands:

[ErrorCatalog(typeof(SwepayErrors))]
public sealed record CreatePaymentCommand(...);

Emits at document root:

x-swepay-error-catalog:
  - code: "PAYMENT_INSUFFICIENT_FUNDS"
    httpStatus: 402
    userMessage: "Saldo insuficiente no método de pagamento."
    recovery: "Tente outro método de pagamento ou adicione saldo."
    docUrl: "https://docs.swepay.com.br/errors/PAYMENT_INSUFFICIENT_FUNDS"

Per operation (the generator slices only codes whose httpStatus matches a declared response on that operation):

x-swepay-errors:
  - "PAYMENT_INSUFFICIENT_FUNDS"

Canonical problem+json schema — F13

When any operation advertises application/problem+json without a typed body, the generator injects:

components:
  schemas:
    SwepayProblemDetails:
      type: object
      properties: { type, title, status, detail, instance, code, recovery, requestId }
      required: [type, title, status, detail, code, recovery, requestId]

Two ways to opt in:

// (a) fluent — no typed body
routes.MapPost<CreateOrderCommand, CreateOrderResponse>("/v1/orders", ...)
      .ProducesProblem(422);

// (b) handler attribute — null responseType
public sealed class CreateOrderHandler : IRequestHandler<CreateOrderCommand, CreateOrderResponse>
{
    [ApiResponse(422, null, "application/problem+json")]
    public ValueTask<CreateOrderResponse> Handle(...) => ...;
}

Renderer options — F15 / F16 / F17

using Native.OpenApi;
using Native.OpenApi.Rendering;

var options = new OpenApiRendererOptions
{
    Branding = new OpenApiBrandingOptions
    {
        PrimaryColor = "#0A2540",
        AccentColor  = "#00D4AA",
        LogoUrl      = "https://cdn.swepay.com.br/brand/logo-dark.svg",
        FaviconUrl   = "https://cdn.swepay.com.br/brand/favicon.ico",
        FontFamily   = "Inter, Roboto, sans-serif"
    },
    Footer = new OpenApiFooterOptions
    {
        StatusUrl     = "https://status.swepay.com.br",
        SupportUrl    = "https://docs.swepay.com.br/support",
        ChangelogUrl  = "https://docs.swepay.com.br/changelog",
        SlaUrl        = "https://docs.swepay.com.br/sla",
        TermsUrl      = "https://docs.swepay.com.br/terms"
    },
    EnableMermaid        = true,   // F17 — render fenced ```mermaid blocks as SVG
    MermaidFromLocalAsset = false  // true for air-gapped deployments (serves ./assets/mermaid.min.js)
};

var renderer = new OpenApiHtmlRenderer();
var redocHtml  = renderer.RenderRedoc ("/docs/openapi.json", "My API", options);
var scalarHtml = renderer.RenderScalar("/docs/openapi.json", "My API", options);

The legacy RenderRedoc(spec, title) / RenderScalar(spec, title) overloads are preserved (RFC principle O5).

Mermaid in descriptions — any fenced ```mermaid block inside summary/description text becomes inline SVG when EnableMermaid = true. Example description body:

## Flow

```mermaid
flowchart LR
  A[1. Create realm] --> B[2. Register client] --> C[3. Issue token]
```

Minimal document pipeline

1. Loader

public class MyOpenApiDocumentLoader : OpenApiDocumentLoaderBase
{
    public MyOpenApiDocumentLoader(OpenApiResourceReader reader) : base(reader) { }

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

    public override IReadOnlyList<OpenApiDocumentPart> LoadPartials() => new[]
    {
        Load("users",    "openapi/users/openapi.yaml"),
        Load("products", "openapi/products/openapi.json"),
    };
}

2. Merger (optional)

public class MyOpenApiDocumentMerger : OpenApiDocumentMerger
{
    protected override string GetServerUrl()
        => Environment.GetEnvironmentVariable("ENVIRONMENT") switch
        {
            "prd" => "https://api.swepay.com.br",
            "hml" => "https://sandbox.api.swepay.com.br",
            _     => "https://localhost:5001"
        };

    protected override string GetApiTitle()       => "Swepay API";
    protected override string GetApiDescription() => "Consolidated OpenAPI spec for partner integrations.";
}

3. Provider

var reader   = new OpenApiResourceReader(typeof(Program).Assembly, "MyApp.");
var loader   = new MyOpenApiDocumentLoader(reader);
var merger   = new MyOpenApiDocumentMerger();
var linter   = new OpenApiLinter(OpenApiLintOptions.Empty);
var provider = new OpenApiDocumentProvider(loader, merger, linter);

provider.WarmUp();

var json = provider.Document.Json;
var yaml = provider.Document.Yaml;

Linting

var options = new OpenApiLintOptions(
    RequiredErrorResponses: ["400", "401", "500"],
    SensitiveFieldNames:    ["password", "token", "secret"],
    DisallowedGenericSegments: ["data", "items"]);

var linter = new OpenApiLinter(options);

Checks:

  • OpenAPI version is 3.1.0
  • Every path is versioned (e.g. /v1/)
  • Every operation has a security block (or explicit security: [] for anonymous)
  • Required error responses are declared
  • Sensitive fields carry a description

[ApiResponse] on handler methods (v1.6.0+)

Co-locate per-status responses with the handler:

using Native.OpenApi;
using NativeMediator;

public class GetProductHandler : IRequestHandler<GetProductCommand, GetProductResponse>
{
    [ApiResponse(200, typeof(GetProductResponse))]
    [ApiResponse(404, typeof(ErrorResponse))]
    [ApiResponse(400, typeof(ProblemDetails), "application/problem+json")]
    [ApiResponse(422, null,                  "application/problem+json")]   // → SwepayProblemDetails (F13)
    public ValueTask<GetProductResponse> Handle(GetProductCommand r, CancellationToken ct) { ... }
}
Parameter Type Default Purpose
statusCode int HTTP status
responseType Type? null typed body; when null + application/problem+json, the generator points at SwepayProblemDetails
contentType string "application/json" content type

Native AOT

<PropertyGroup>
  <PublishAot>true</PublishAot>
  <IsAotCompatible>true</IsAotCompatible>
  <IsTrimmable>true</IsTrimmable>
</PropertyGroup>

All JSON/YAML serialization flows through source-generated JsonSerializerContext. No runtime reflection on consumer types.


License

MIT

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

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.7.0 113 4/17/2026
1.6.0 1,228 2/23/2026
1.5.1 469 2/19/2026
1.5.0 109 2/18/2026
1.4.1 101 2/18/2026
1.4.0 66 2/17/2026
1.3.3 137 2/13/2026
1.3.1 124 2/11/2026
1.3.0 71 2/11/2026
1.2.6 72 2/11/2026
1.2.5 78 2/11/2026
1.2.4 72 2/11/2026
1.2.3 74 2/9/2026
1.2.2 70 2/3/2026
1.2.1 79 2/3/2026
1.2.0 77 2/3/2026
1.1.0 81 2/2/2026
1.0.0 163 2/1/2026