Generate a .NET Bicep extension from any OpenAPI 3.0 document — including auto-generated reference documentation.
OpenAPI 3.0 (JSON/YAML) ──► bicepextgen ──► .NET Bicep extension (+ docs/)
The generated extension follows the bicep-local-docgen local-deploy template shape
(a REST-calling handler base, an extension Configuration, and fully documentation-annotated
model classes), so it builds with dotnet build, packages with bicep publish-extension, and
its docs are produced by bicep-local-docgen. The structure mirrors the
bicep-extension-template project layout.
bicepextgen is published as a .NET tool. Install it globally:
dotnet tool install --global Tankerkiller125.BicepExtensionGen…or add it to a tool manifest for a specific repository (recommended for reproducible builds):
dotnet new tool-manifest # once per repo, if you don't already have .config/dotnet-tools.json
dotnet tool install Tankerkiller125.BicepExtensionGenUpdate or remove it later with:
dotnet tool update --global Tankerkiller125.BicepExtensionGen
dotnet tool uninstall --global Tankerkiller125.BicepExtensionGenGlobal installs expose the bicepextgen command directly; manifest-local installs run via
dotnet bicepextgen.
-
Parse the OpenAPI document with
Microsoft.OpenApi. -
Infer resources by pairing collection/item paths (e.g.
/pets+/pets/{petId}) and mapping HTTP verbs onto CRUD:OpenAPI Bicep handler POST(collection)Create GET(item)Read / Preview PUT/PATCH(item)Update DELETE(item)Delete -
Map schemas to C#: component schemas → annotated model classes, string enums → C# enums, nested objects → nested classes,
readOnlyfields → read-only outputs, path parameters → resource identifiers. Nested paths (/zones/{id}/dns_records/{id}) carry the parent key as an identifier, and colliding resource names are disambiguated by parent path (AccountUservsZoneUser), never numeric suffixes. -
Map security from
components.securitySchemestoConfigurationcredentials. Every OpenAPI 3.0 scheme is supported — apiKey (header/query/cookie), HTTP Basic, HTTP Bearer, OAuth 2.0, and OpenID Connect. Each becomes an optional, secure config property; the handler applies whichever the user supplies (so "email + key" and "either/or token" APIs both work). -
Emit the project:
[ResourceType]/[TypeProperty]models with docgen attributes ([BicepDocHeading],[BicepFrontMatter],[BicepDocExample]), wired REST handlers,Program.cs,build.ps1, and a tool manifest. -
Document (with
--docs): runbicep-local-docgenover the generated models.
bicepextgen generate \
--input ./openapi.yaml \
--output ./out \
--name Contoso.PetStore \
--docs| Option | Description |
|---|---|
-i, --input |
OpenAPI 3.0 document (JSON or YAML); local path or http(s) URL. Required. |
-o, --output |
Directory to write the generated extension into. Required. |
-n, --name |
Extension name, e.g. Contoso.PetStore (also the C# root namespace). Required. |
--version |
Extension version (default 0.1.0). |
--namespace |
C# root namespace (default: derived from --name). |
--mapping |
Resource mapping mode: path (default) or schema. |
--resource-prefix |
Namespace for Bicep resource types, e.g. Cloudflare.Dns → Cloudflare.Dns/DnsRecordA. |
--resource-path |
Hierarchical (Azure-style) child-path types derived from the API path, e.g. Zone/DnsRecord/A. Composes with --resource-prefix. |
--exclude |
Glob(s) to drop matching paths (path mode) or schemas (schema mode). Comma-separated and/or repeatable. |
--exclude-tag |
Glob(s) to drop operations by OpenAPI tag. Comma-separated and/or repeatable. |
--docs |
Run bicep-local-docgen to produce markdown docs under docs/. |
--force |
Overwrite a non-empty output directory. |
Large public specs often bundle areas you don't care about. --exclude and --exclude-tag
prune them before any code is generated (and their schemas drop out automatically, since nothing
reachable references them). Globs match the full string, case-insensitively: * matches within a
path segment, ** matches across segments, ? matches one character.
# Drop every Workers-AI model endpoint from the Cloudflare spec, by path or by tag:
bicepextgen generate \
--input ./openapi.yaml --output ./out --name Cloudflare.Api \
--exclude "**/ai/run/**" \
--exclude-tag "Workers AI*"A path is dropped if its template matches an --exclude glob, or if any of its operations carries a
tag matching an --exclude-tag glob.
Exit codes: 0 success, 1 error, 2 success with warnings.
out/
├── build.ps1 # build → publish (win/linux/osx) → bicep publish-extension
├── script/publish.ps1 # publish to an OCI registry (e.g. ACR)
├── .config/dotnet-tools.json # pins bicep-local-docgen
├── src/
│ ├── <name>.csproj
│ ├── Program.cs # registers every resource handler
│ ├── Models/
│ │ ├── Configuration.cs # extension baseUrl
│ │ ├── Common.cs # shared enums + nested types
│ │ └── <Resource>/<Resource>.cs
│ └── Handlers/
│ ├── ResourceHandlerBase.cs
│ └── <Resource>Handler.cs
└── docs/<resource>.md # when --docs is used
- .NET SDK 10.0 or later (the generated extension targets
net10.0). - Bicep CLI — only needed to package the generated extension (
build.ps1).
dotnet build Tankerkiller125.BicepExtensionGen.slnx
dotnet testThe test suite (tests/Tankerkiller125.BicepExtensionGen.Tests) covers resource inference, type
mapping, and file emission against fixtures/petstore.yaml.
See CONTRIBUTING.md for the full contributor workflow.
This project was developed largely with the assistance of AI coding tools — most of the source, tests, and supporting files were AI-generated under human direction and review. Contributions (whether human- or AI-authored) are still expected to meet the project's quality bar: they must build warning-free, pass the test suite, and be reviewed before merging. If you build on this project, evaluate the generated output for your own use case rather than assuming correctness.