Install
| Product | Versions |
|---|---|
| .NET |
README
render_with_liquid: false
Oxpecker.OpenApi
Oxpecker.OpenApi extends Oxpecker framework with functionality to automatically generate OpenApi spec from code.
It works on top of Microsoft.AspNetCore.OpenApi package.
Nuget package dotnet add package Oxpecker.OpenApi
Usages example:
open Oxpecker
open Oxpecker.OpenApi
open System.Threading.Tasks
let endpoints = [
// addOpenApi supports passing detailed configuration
POST [
route "/product" (text "Product posted!")
|> addOpenApi (OpenApiConfig(
requestBody = RequestBody(typeof<Product>),
responseBodies = [| ResponseBody(typeof<string>) |],
configureOperation = (fun o _ _ -> o.OperationId <- "PostProduct"; Task.CompletedTask)
))
]
// addOpenApiSimple is a shortcut for simple cases
GET [
routef "/product/{%i}" (
fun id ->
products
|> Array.find (fun f -> f.Id = num)
|> json
)
|> configureEndpoint _.WithName("GetProduct")
|> addOpenApiSimple<int, Product>
]
// such route won't work with OpenAPI, since HTTP method is not specified
route "/hello" <| text "Hello, world!"
]
Note: you MUST specify HTTP method (GET, POST etc.), because routes with ANY method are not supported by OpenApi
Configuration
Option 1 (for ASP.NET Core 9+)
- Install
Microsoft.AspNetCore.OpenApipackage - Follow standard steps:
let configureApp (appBuilder: IApplicationBuilder) =
appBuilder
.UseRouting()
.Use(errorHandler)
.UseOxpecker(endpoints)
.Run(notFoundHandler)
let configureServices (services: IServiceCollection) =
services
.AddRouting()
.AddOxpecker()
.AddOpenApi(fun o ->
o
// support for Option<_> and ValueOption<_>
.AddSchemaTransformer<FSharpOptionSchemaTransformer>()
// support for discriminated unions (ASP.NET Core 11+)
.AddSchemaTransformer<FSharpUnionSchemaTransformer>()
|> ignore
) // OpenAPI dependencies
|> ignore
[<EntryPoint>]
let main args =
let builder = WebApplication.CreateBuilder(args)
configureServices builder.Services
let app = builder.Build()
configureApp app
app.MapOpenApi() |> ignore // for json OpenAPI endpoint
app.Run()
0
Option 2 (for ASP.NET Core 8+)
- Install
Microsoft.AspNetCore.OpenApipackage - Install
Swashbuckle.AspNetCorepackage - Do standard steps:
let configureApp (appBuilder: IApplicationBuilder) =
appBuilder
.UseRouting()
.Use(errorHandler)
.UseOxpecker(endpoints)
.UseSwagger() // for json OpenAPI endpoint
.UseSwaggerUI() // for viewing Swagger UI
.Run(notFoundHandler)
let configureServices (services: IServiceCollection) =
services
.AddRouting()
.AddOxpecker()
.AddEndpointsApiExplorer() // use the API Explorer to discover and describe endpoints
.AddSwaggerGen() // swagger dependencies
|> ignore
[<EntryPoint>]
let main args =
let builder = WebApplication.CreateBuilder(args)
configureServices builder.Services
let app = builder.Build()
configureApp app
app.Run()
0
Note: Option<_> and ValueOption<_> are not supported by Swashbuckle (issue).
APIs
To make endpoints discoverable by OpenApi, you need to call one of the following functions: addOpenApi or addOpenApiSimple on the endpoint.
Note1: you don't have to describe routing parameters when using those functions, they will be inferred from the route template automatically when using routef function from Oxpecker.OpenApi namespace.
Note2: use [<CLIMutable>] attribute on your records and [<Required>] or [<JsonRequired>] on their fields to control required fields in schema.
Note3: use <Nullable>enable</Nullable> in your project to disallow null value for reference types.
Note4: .NET 11 added System.Text.Json support for F# discriminated unions: fieldless cases are serialized as JSON strings, cases with fields as JSON objects with a type discriminator property ("$type" by default, customizable via JsonPolymorphicAttribute on the union type). Register FSharpUnionSchemaTransformer to get matching OpenAPI schemas: unions where every case is fieldless become a string enum; a union whose only case has fields becomes that case's object schema directly; otherwise each case becomes a oneOf branch in declaration order — a const string for a fieldless case, an object with a const discriminator for a case with fields (recursive unions are supported via schema references); option, voption and nullable reference (string | null) fields are documented as nullable. The nullary case of a union marked UseNullAsTrueValue is serialized as JSON null, so it is documented as a null branch instead of a string. Object schemas get additionalProperties: false when JsonUnmappedMemberHandling.Disallow applies to the union. Case and field names respect JsonPropertyNameAttribute and the configured PropertyNamingPolicy.
addOpenApi
This method is used to add OpenApi metadata to the endpoint. It accepts OpenApiConfig object with the following optional parameters:
type OpenApiConfig (?requestBody : RequestBody,
?responseBodies : ResponseBody seq,
?configureOperation : OpenApiOperation -> OpenApiOperationTransformerContext -> CancellationToken -> Task) =
// ...
Response body schema will be inferred from the types passed to requestBody and responseBodies parameters. Each ResponseBody object in sequence must have different status code.
configureOperation parameter is a function that allows you to do very low-level modifications the OpenApiOperation object.
addOpenApiSimple
This method is a shortcut for simple cases. It accepts two generic type parameters - request and response, so the schema can be inferred from them.
let addOpenApiSimple<'Req, 'Res> = ...
If your handler doesn't accept any input, you can pass unit as a request type (works for response as well).
Changes from Previous Version
Adoption Assessment
Assess this package against its supported frameworks, license, maintenance signals and dependency graph before making it a project standard.
Related Guides & Workflows
Learn how to evaluate, integrate, or audit this package in your .NET project.