Skip to main content

Getting Started with LambdaOpenAPI

Get up and running with LambdaOpenAPI in minutes. This guide walks you through installation, basic configuration, and generating your first OpenAPI specification.

Prerequisites

Before you begin, ensure you have:

  • .NET 6.0 or later installed
  • AWS Lambda Annotations package in your project
  • An existing AWS Lambda project (or create a new one)
New to Lambda Annotations?

If you're new to AWS Lambda Annotations, check out the official AWS documentation to get started.

Installation

Add LambdaOpenAPI to your AWS Lambda project via NuGet:

dotnet add package Oproto.Lambda.OpenApi

That's it! The source generator will automatically integrate with your build process.

Basic Usage

Step 1: Decorate Your Lambda Functions

Add OpenAPI attributes to your Lambda functions to describe your API:

using Amazon.Lambda.Annotations;
using Amazon.Lambda.Annotations.APIGateway;
using Oproto.Lambda.OpenApi.Attributes;

// Assembly-level API info (in AssemblyInfo.cs or any .cs file)
[assembly: OpenApiInfo("My API", "1.0.0", Description = "API for managing resources")]

public class Functions
{
[LambdaFunction]
[HttpApi(LambdaHttpMethod.Get, "/users/{userId}")]
[OpenApiOperation(Summary = "Get user by ID")]
[OpenApiTag("Users")]
public async Task<APIGatewayProxyResponse> GetUser(
[FromRoute] string userId,
[FromQuery] bool includeDetails = false)
{
// Your implementation
return new APIGatewayProxyResponse
{
StatusCode = 200,
Body = JsonSerializer.Serialize(new { UserId = userId })
};
}
}

Step 2: Build Your Project

When you build your project, the OpenAPI specification is automatically generated:

dotnet build

This creates an openapi.json file in your project directory — no manual YAML editing required!

Step 3: View Your Generated Specification

The generated OpenAPI specification includes:

  • Endpoint definitions with paths and HTTP methods
  • Parameter schemas for route, query, header, and body parameters
  • Response schemas based on your return types
  • Tags and descriptions for organization and documentation

Available Attributes

LambdaOpenAPI provides several attributes to customize your API documentation. All attributes are in the Oproto.Lambda.OpenApi.Attributes namespace:

Assembly-Level Attributes

Configure your API at the assembly level (typically in AssemblyInfo.cs or any .cs file):

AttributePurpose
[OpenApiInfo]Sets API title, version, description, and metadata
[OpenApiSecurityScheme]Defines security schemes (API Key, OAuth2, etc.)
[OpenApiServer]Defines server URLs (production, staging, etc.)
[OpenApiTagDefinition]Defines tags with descriptions
[OpenApiTagGroup]Groups tags for hierarchical navigation (x-tagGroups)
[OpenApiExternalDocs]Links to external API documentation
[OpenApiExampleConfig]Configures automatic example generation
[OpenApiOutput]Specifies output file configuration

Method-Level Attributes

AttributePurpose
[OpenApiOperation]Adds operation metadata (summary, description)
[OpenApiOperationId]Custom operation IDs for code generators
[OpenApiTag]Groups operations by tags
[OpenApiResponseType]Documents response types for IHttpResult methods
[OpenApiResponseHeader]Documents response headers
[OpenApiExample]Provides request/response examples
[OpenApiExternalDocs]Links to external documentation

Property/Parameter Attributes

AttributePurpose
[OpenApiSchema]Customizes type schemas with validation rules
[OpenApiIgnore]Excludes properties from schemas

Important Behaviors

FromServices Parameters Are Excluded

Parameters decorated with [FromServices] are automatically excluded from the OpenAPI specification. These are dependency injection parameters that are not part of the HTTP API contract:

[LambdaFunction]
[HttpApi(LambdaHttpMethod.Get, "/products")]
public async Task<IEnumerable<Product>> GetProducts(
[FromServices] IProductService productService, // Excluded from OpenAPI
[FromQuery] int limit = 10) // Included in OpenAPI
{
return await productService.GetProducts(limit);
}

API Gateway Integration Extension

The generated OpenAPI specification includes the x-amazon-apigateway-integration extension for each operation. This extension is required for deploying to AWS API Gateway:

{
"x-amazon-apigateway-integration": {
"type": "aws_proxy",
"httpMethod": "POST",
"uri": "${LambdaFunctionArn}",
"payloadFormatVersion": "2.0"
}
}

The payloadFormatVersion is automatically set based on the API type:

  • 2.0 for HTTP APIs ([HttpApi])
  • 1.0 for REST APIs ([RestApi])

Async Return Types

The generator automatically unwraps Task<T> and ValueTask<T> return types. For example:

// This method returns Task<Product>
public async Task<Product> GetProduct(string id) { ... }

// The OpenAPI response schema will be for Product, not Task<Product>

Methods returning non-generic Task or ValueTask generate a 204 No Content response.

IHttpResult Return Types

When your Lambda functions return IHttpResult (from Lambda Annotations), the generator cannot infer the actual response type. Use [OpenApiResponseType] to explicitly document responses:

[LambdaFunction]
[HttpApi(LambdaHttpMethod.Get, "/products/{id}")]
[OpenApiResponseType(typeof(Product), 200, Description = "Returns the product")]
[OpenApiResponseType(typeof(ErrorResponse), 404, Description = "Product not found")]
public async Task<IHttpResult> GetProduct(string id)
{
var product = await _service.GetProduct(id);
if (product == null)
return HttpResults.NotFound(new ErrorResponse { Message = "Not found" });
return HttpResults.Ok(product);
}

Deprecation with [Obsolete]

The generator automatically detects the standard .NET [Obsolete] attribute and marks operations as deprecated:

[LambdaFunction]
[HttpApi(LambdaHttpMethod.Delete, "/products/{id}")]
[Obsolete("Use the archive endpoint instead. This will be removed in v2.0.")]
public Task DeleteProduct(string id)
{
// Implementation
}

Response Headers

Document response headers using [OpenApiResponseHeader]:

[LambdaFunction]
[HttpApi(LambdaHttpMethod.Get, "/products")]
[OpenApiResponseHeader("X-Total-Count", Description = "Total products", Type = typeof(int))]
[OpenApiResponseHeader("X-Page-Size", Description = "Page size", Type = typeof(int))]
public Task<IEnumerable<Product>> GetProducts([FromQuery] int page = 1)
{
// Implementation
}

Request and Response Examples

Provide JSON examples using [OpenApiExample]:

[LambdaFunction]
[HttpApi(LambdaHttpMethod.Post, "/products")]
[OpenApiExample("Create Request",
"{\"name\": \"Widget\", \"price\": 19.99}",
IsRequestExample = true)]
[OpenApiExample("Success Response",
"{\"id\": \"123\", \"name\": \"Widget\", \"price\": 19.99}",
StatusCode = 200)]
public Task<Product> CreateProduct([FromBody] CreateProductRequest request)
{
// Implementation
}

Operation IDs

Customize operation IDs for code generators using [OpenApiOperationId]:

[LambdaFunction]
[HttpApi(LambdaHttpMethod.Get, "/products")]
[OpenApiOperationId("listAllProducts")]
public Task<IEnumerable<Product>> GetProducts()
{
// Implementation
}

AOT Compatibility

LambdaOpenAPI fully supports Native AOT builds without any special configuration. The OpenAPI specification is extracted during the Build phase (before AOT compilation) using MetadataLoadContext, so it works seamlessly with AOT projects.

<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<PublishAot>true</PublishAot>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Oproto.Lambda.OpenApi" Version="1.0.0" />
</ItemGroup>
</Project>

See the Configuration Options for more details.

Security Schemes

Security schemes are only added to the OpenAPI specification when you define them using assembly-level attributes:

// In your project (e.g., AssemblyInfo.cs)
[assembly: OpenApiSecurityScheme("apiKey",
Type = OpenApiSecuritySchemeType.ApiKey,
ApiKeyName = "x-api-key",
ApiKeyLocation = ApiKeyLocation.Header)]

OAuth2 Example:

[assembly: OpenApiSecurityScheme("oauth2",
Type = OpenApiSecuritySchemeType.OAuth2,
AuthorizationUrl = "https://auth.example.com/authorize",
TokenUrl = "https://auth.example.com/token",
Scopes = "read:Read access,write:Write access")]

See the Attribute Reference for more details.

Next Steps

Ready to dive deeper? Check out these resources:

Zero Runtime Cost

LambdaOpenAPI generates your OpenAPI spec at build time using source generators. There's no runtime reflection or scanning, making it perfect for Native AOT deployments with fast cold starts.