This guide explains how to configure Oproto Lambda OpenAPI generation behavior in your project.
Oproto Lambda OpenAPI uses MSBuild properties and targets to control the OpenAPI specification generation process. Configuration is done through your project file (.csproj) and allows you to customize output paths, disable generation for specific builds, and fine-tune the generation behavior.
The following MSBuild properties can be set in your project file to customize OpenAPI generation:
| Property | Description | Default |
|---|---|---|
OpenApiOutputPath |
The file path where the generated OpenAPI specification will be written | $(ProjectDir)openapi.json |
EmitCompilerGeneratedFiles |
When set to true, outputs the source generator files to disk for debugging |
false |
CompilerGeneratedFilesOutputPath |
Directory where generated source files are written when EmitCompilerGeneratedFiles is enabled |
$(BaseIntermediateOutputPath)\GeneratedFiles |
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<!-- Enable generated file output for debugging -->
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
<CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)\GeneratedFiles</CompilerGeneratedFilesOutputPath>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Oproto.Lambda.OpenApi" Version="1.0.0" />
</ItemGroup>
</Project>By default, the OpenAPI specification is generated to openapi.json in your project directory. You can customize this location by modifying the MSBuild target.
To change the output path, you can override the GenerateOpenApi target in your project file:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Oproto.Lambda.OpenApi" Version="1.0.0" />
</ItemGroup>
<!-- Override the default output path -->
<Target Name="CustomOpenApiOutput" AfterTargets="GenerateOpenApi">
<Copy SourceFiles="$(ProjectDir)openapi.json"
DestinationFiles="$(ProjectDir)docs\api\openapi.json"
SkipUnchangedFiles="true" />
</Target>
</Project>If you need the specification in multiple locations (e.g., for deployment and documentation):
<Target Name="CopyOpenApiToMultipleLocations" AfterTargets="GenerateOpenApi">
<ItemGroup>
<OpenApiDestinations Include="$(ProjectDir)docs\openapi.json" />
<OpenApiDestinations Include="$(SolutionDir)api-docs\$(ProjectName).json" />
</ItemGroup>
<Copy SourceFiles="$(ProjectDir)openapi.json"
DestinationFiles="@(OpenApiDestinations)"
SkipUnchangedFiles="true" />
</Target>There are several ways to disable OpenAPI generation for specific scenarios.
To disable generation only for Release builds:
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
<OpenApiGenerationEnabled>false</OpenApiGenerationEnabled>
</PropertyGroup>
<Target Name="GenerateOpenApi" AfterTargets="Build"
Condition="'$(OpenApiGenerationEnabled)' != 'false'">
<!-- Generation logic -->
</Target>To completely disable OpenAPI generation for a project, you can remove the target:
<Target Name="GenerateOpenApi" />Or conditionally skip it:
<PropertyGroup>
<SkipOpenApiGeneration>true</SkipOpenApiGeneration>
</PropertyGroup>You can also disable generation when building from the command line:
dotnet build -p:SkipOpenApiGeneration=true<Target Name="GenerateOpenApi" AfterTargets="Build"
Condition="'$(CI)' != 'true'">
<!-- Only generate locally, not in CI -->
</Target>Oproto Lambda OpenAPI fully supports Native AOT builds without any special configuration. The OpenAPI specification is extracted during the Build phase (before AOT compilation), so it works seamlessly with AOT projects.
The build task runs AfterTargets="Build", which executes before AOT publishing:
- Build → IL assembly created with attributes → OpenAPI extraction runs →
openapi.jsongenerated - Publish → AOT compiles IL to native binary
The extraction uses MetadataLoadContext to read assembly metadata without loading dependencies, making it compatible with any project configuration.
No special configuration is required for 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>If you want to inspect the generated source code for debugging purposes, you can optionally enable compiler-generated file output:
<PropertyGroup>
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
</PropertyGroup>This is not required for OpenAPI generation to work - it's purely for debugging the source generator output.
When troubleshooting generation issues, enable compiler-generated file output:
<PropertyGroup>
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
<CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)\GeneratedFiles</CompilerGeneratedFilesOutputPath>
</PropertyGroup>Generated files will appear in:
obj/GeneratedFiles/Oproto.Lambda.OpenApi.SourceGenerator/
The source generator automatically maps .NET types to OpenAPI schema types. The following table shows the supported type mappings:
| .NET Type | OpenAPI Type | OpenAPI Format |
|---|---|---|
string |
string |
- |
int, Int32 |
integer |
int32 |
long, Int64 |
integer |
int64 |
short, Int16 |
integer |
int32 |
byte |
integer |
int32 |
float, Single |
number |
float |
double, Double |
number |
double |
decimal, Decimal |
number |
double |
bool, Boolean |
boolean |
- |
| .NET Type | OpenAPI Type | OpenAPI Format | Notes |
|---|---|---|---|
DateTime |
string |
date-time |
ISO 8601 format |
DateTimeOffset |
string |
date-time |
ISO 8601 format with timezone |
DateOnly |
string |
date |
.NET 6+ date without time (e.g., 2024-12-30) |
TimeOnly |
string |
time |
.NET 6+ time without date (e.g., 14:30:00) |
TimeSpan |
string |
duration |
ISO 8601 duration format |
| .NET Type | OpenAPI Type | OpenAPI Format |
|---|---|---|
Guid |
string |
uuid |
Uri |
string |
uri |
byte[] |
string |
byte |
All nullable variants (e.g., int?, DateTime?, DateOnly?, TimeOnly?) are mapped to the same OpenAPI type and format as their non-nullable counterparts, with nullable: true added to the schema.
| .NET Type | OpenAPI Type |
|---|---|
T[], List<T>, IEnumerable<T>, ICollection<T> |
array with items schema for T |
Dictionary<string, T> |
object with additionalProperties schema for T |
Any type not listed above is treated as a complex object type and generates a schema in the components/schemas section with properties for each public property of the type.
public class Appointment
{
[OpenApiSchema(Description = "The date of the appointment")]
public DateOnly Date { get; set; }
[OpenApiSchema(Description = "The start time of the appointment")]
public TimeOnly StartTime { get; set; }
[OpenApiSchema(Description = "The end time of the appointment (optional)")]
public TimeOnly? EndTime { get; set; }
}This generates the following OpenAPI schema:
{
"Appointment": {
"type": "object",
"properties": {
"date": {
"type": "string",
"format": "date",
"description": "The date of the appointment"
},
"startTime": {
"type": "string",
"format": "time",
"description": "The start time of the appointment"
},
"endTime": {
"type": "string",
"format": "time",
"nullable": true,
"description": "The end time of the appointment (optional)"
}
}
}
}Symptoms: Build succeeds but no openapi.json file is created.
Possible causes and solutions:
-
No
[GenerateOpenApiSpec]attribute on class- Ensure at least one class has the
[GenerateOpenApiSpec]attribute - The attribute should be on a class containing Lambda functions
- Ensure at least one class has the
-
No Lambda functions detected
- Verify methods have both
[LambdaFunction]and[HttpApi]or[RestApi]attributes - Check that Amazon.Lambda.Annotations package is referenced
- Verify methods have both
-
Build task not running
- Verify the package reference is correct
- Check build output for warnings or errors
Symptoms: The openapi.json file exists but contains no endpoints.
Possible causes and solutions:
-
Missing HTTP method attributes
- Each Lambda function needs
[HttpApi]or[RestApi]attribute with method and route
- Each Lambda function needs
-
Incorrect attribute usage
// Correct [LambdaFunction] [HttpApi(LambdaHttpMethod.Get, "/products")] public Task<Product[]> GetProducts() { } // Incorrect - missing HttpApi [LambdaFunction] public Task<Product[]> GetProducts() { }
Symptoms: Request/response models appear as empty objects in the spec.
Possible causes and solutions:
-
Properties are not public
- Ensure model properties have public getters
-
Properties marked with
[OpenApiIgnore]- Check if properties are accidentally ignored
-
Missing XML documentation
- While not required, XML docs improve schema descriptions
Symptoms: Build fails with errors mentioning the source generator.
Possible causes and solutions:
-
Version conflicts
- Ensure compatible versions of all packages
- Try cleaning and rebuilding:
dotnet clean && dotnet build
-
Missing dependencies
- Verify all required packages are installed:
<PackageReference Include="Amazon.Lambda.Annotations" Version="1.6.1" /> <PackageReference Include="Oproto.Lambda.OpenApi" Version="1.0.0" />
- Verify all required packages are installed:
-
IDE caching issues
- Restart your IDE
- Delete
objandbinfolders and rebuild
To see detailed output from the source generator:
-
Enable verbose MSBuild output:
dotnet build -v detailed
-
Look for messages starting with "OpenAPI Generation" in the build output
-
Enable generated file output to inspect the generated code:
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
If you continue to experience issues:
- Check the GitHub Issues for known problems
- Enable verbose logging and include the output when reporting issues
- Include your project configuration and attribute usage in bug reports