Runtime Contract Enforcement
This is the part that makes Kestrun feel different: OpenAPI is not just documentation. It can become an allow-list for what the endpoint accepts and returns.
Response content types
If an operation declares that it produces JSON, then returning a different format like YAML is a contract violation.
Practical rule of thumb
- Use
Write-KrResponsewhen you want content negotiation - Use
Write-KrJsonResponse/Write-KrYamlResponse/Write-KrXmlResponsewhen you want to force a specific format
If you force a format, make sure your OpenAPI response content types match what you actually return.
Request body content types (415)
If you declare request body content types via [OpenApiRequestBody(ContentType = 'application/json')], Kestrun rejects mismatches with 415 Unsupported Media Type.
This is intentional: clients must send one of the declared Content-Type values.
Parameter and body schemas
OpenAPI parameter schemas and model schemas are typically derived from:
- Parameter types such as
[int],[string], and PowerShell class types - Validation attributes such as
[ValidateRange],[ValidateSet],[ValidatePattern],[ValidateNotNullOrEmpty] - OpenAPI component metadata such as
[OpenApiParameterComponent],[OpenApiSchemaComponent], and[OpenApiPropertyAttribute]
At runtime, Kestrun applies these rules during binding and validation.
Auto client-error responses
When OpenAPI metadata enables runtime contract checks, Kestrun can add matching client-error responses to the OpenAPI operation.
- 400 Bad Request: malformed JSON, invalid route/query conversions, request binding/parsing failures
- 422 Unprocessable Entity: validation failures after successful parsing/binding
- 415 Unsupported Media Type: request
Content-Typenot allowed by the request body contract - 406 Not Acceptable: no overlap between the client
Acceptheader and the operation response content types
These responses use a shared schema component (default name: KestrunErrorResponse) and default media type application/problem+json.
Configure the generated error contract
Use Set-KrOpenApiErrorSchema to control both the schema component name and one or more response media types.
# Default behavior
Set-KrOpenApiErrorSchema -Name 'KestrunErrorResponse'
# Custom schema name + multiple media types
Set-KrOpenApiErrorSchema -Name 'ApiError' -ContentType @('application/problem+json', 'application/json')
Configure this before Build-KrOpenApiDocument or Add-KrOpenApiRoute so generated output stays stable for tests and clients.
Customize the runtime error payload
Use Set-KrPowerShellErrorResponse when you also want to customize the runtime error payload shape for PowerShell route execution, while keeping the OpenAPI error contract aligned.
Set-KrOpenApiErrorSchema -Name 'ApiError' -ContentType @('application/problem+json', 'application/json')
Set-KrPowerShellErrorResponse -ScriptBlock {
$payload = [ordered]@{
status = $StatusCode
title = 'Request failed'
detail = $ErrorMessage
path = [string]$Context.Request.Path
timestamp = (Get-Date).ToUniversalTime().ToString('o')
}
Write-KrJsonResponse -InputObject $payload -StatusCode $StatusCode -ContentType 'application/problem+json'
}
If no custom script is configured, or if the custom script fails, Kestrun falls back to the default error writer.
Why this matters
The result is simple and powerful:
- your generated OpenAPI document stays aligned with real behavior
- content negotiation is documented and enforced
- validation rules show up in docs and in runtime behavior
- client error responses can be generated consistently
That is what turns OpenAPI from “nice docs” into a real API contract in Kestrun.