RequestBody Components
Create reusable request body components that can be shared across multiple endpoints.
Full source
File: [pwsh/tutorial/examples/10.3-OpenAPI-Component-RequestBody.ps1][10.3-OpenAPI-Component-RequestBody.ps1]
<#
Sample: OpenAPI RequestBody Components
Purpose: Demonstrate reusable request body components with multiple content types.
File: 10.3-OpenAPI-Component-RequestBody.ps1
Notes: Shows class inheritance, component wrapping, and content type negotiation.
#>
param(
[int]$Port = 5000,
[IPAddress]$IPAddress = [IPAddress]::Loopback
)
# --- Logging / Server ---
New-KrLogger | Add-KrSinkConsole |
Set-KrLoggerLevel -Value Debug |
Register-KrLogger -Name 'console' -SetAsDefault
$srv = New-KrServer -Name 'OpenAPI RequestBody Component' -PassThru
Add-KrEndpoint -Port $Port -IPAddress $IPAddress
# =========================================================
# TOP-LEVEL OPENAPI
# =========================================================
Add-KrOpenApiInfo -Title 'RequestBody Component API' `
-Version '1.0.0' `
-Description 'Demonstrates reusable request body components.'
# =========================================================
# COMPONENT SCHEMAS
# =========================================================
[OpenApiSchemaComponent(Required = ('productName', 'price'))]
class Product {
[OpenApiPropertyAttribute(Description = 'Unique product identifier', Format = 'int64', Example = 1)]
[long]$id
[OpenApiPropertyAttribute(Description = 'Product name', Example = 'Laptop')]
[string]$productName
[OpenApiPropertyAttribute(Description = 'Product price', Format = 'double', Example = 999.99)]
[double]$price
[OpenApiPropertyAttribute(Description = 'Product description', Example = 'A high-performance laptop')]
[string]$description
[OpenApiPropertyAttribute(Description = 'Stock quantity', Minimum = 0, Example = 50)]
[int]$stock
[OpenApiPropertyAttribute(Description = 'Creation timestamp', Format = 'date-time', Example = '2024-01-01T12:00:00Z')]
[string]$createdAt
[OpenApiPropertyAttribute(Description = 'Update timestamp', Example = '2024-01-01T12:00:00Z')]
[datetime]$updatedAt
}
# =========================================================
# COMPONENT REQUEST BODIES (Reusable)
# =========================================================
# CreateProductRequest: RequestBody component that wraps Product schema
[OpenApiRequestBodyComponent(
Description = 'Product creation payload. Supports JSON and form data.',
IsRequired = $true,
ContentType = ('application/json', 'application/x-www-form-urlencoded')
)]
class CreateProductRequest:Product {
}
# UpdateProductRequest: RequestBody component that wraps UpdateProduct schema
[OpenApiRequestBodyComponent(
Description = 'Product update payload.',
IsRequired = $true,
ContentType = 'application/json',
Required = ('productName', 'price')
)]
class UpdateProductRequest {
[OpenApiPropertyAttribute(Description = 'Product name', Example = 'Laptop Pro')]
[string]$productName
[OpenApiPropertyAttribute(Description = 'Product price', Format = 'double', Example = 1299.99)]
[double]$price
[OpenApiPropertyAttribute(Description = 'Product description')]
[string]$description
[OpenApiPropertyAttribute(Description = 'Stock quantity', Minimum = 0)]
[int]$stock
}
# =========================================================
# ROUTES / OPERATIONS
# =========================================================
Enable-KrConfiguration
Add-KrApiDocumentationRoute -DocumentType Swagger
Add-KrApiDocumentationRoute -DocumentType Redoc
# POST endpoint: Create product using CreateProductRequest component
<#
.SYNOPSIS
Create a new product.
.DESCRIPTION
Creates a new product using the reusable CreateProductRequest component.
.PARAMETER body
Product creation request
#>
function createProduct {
[OpenApiPath(HttpVerb = 'post', Pattern = '/products')]
[OpenApiResponse(StatusCode = '201', Description = 'Product created successfully', Schema = [Product], ContentType = ('application/json', 'application/xml', 'application/x-www-form-urlencoded'))]
[OpenApiResponse(StatusCode = '400', Description = 'Invalid input')]
param(
[OpenApiRequestBodyRef(ReferenceId = 'CreateProductRequest')]
[CreateProductRequest]$body
)
if (-not $body.productName -or -not $body.price) {
Write-KrResponse @{error = 'productName and price are required' } -StatusCode 400
return
}
$response = [Product]@{
id = 1
productName = $body.productName
price = $body.price
description = $body.description
stock = $body.stock -as [int]
createdAt = (Get-Date).ToUniversalTime().ToString('o')
}
Write-KrResponse $response -StatusCode 201
}
# PUT endpoint: Update product using UpdateProductRequest component
<#
.SYNOPSIS
Update an existing product.
.DESCRIPTION
Updates product details using the reusable UpdateProductRequest component.
.PARAMETER productId
The product ID to update
.PARAMETER body
Product update request
#>
function updateProduct {
[OpenApiPath(HttpVerb = 'put', Pattern = '/products/{productId}')]
[OpenApiResponse(StatusCode = '200', Description = 'Product updated successfully', Schema = [Product], ContentType = ('application/json', 'application/xml', 'application/x-www-form-urlencoded'))]
[OpenApiResponse(StatusCode = '400', Description = 'Invalid input')]
[OpenApiResponse(StatusCode = '404', Description = 'Product not found')]
param(
[OpenApiParameter(In = [OaParameterLocation]::Path, Required = $true)]
[int]$productId,
[OpenApiRequestBodyRef(ReferenceId = 'UpdateProductRequest')]
$body
)
if (-not $body.productName -or -not $body.price) {
Write-KrJsonResponse @{error = 'productName and price are required' } -StatusCode 400
return
}
$response = [Product]@{
id = $productId
productName = $body.productName
price = $body.price
description = $body.description
stock = $body.stock -as [int]
updatedAt = (Get-Date).ToUniversalTime().ToString('o')
}
Write-KrResponse $response -StatusCode 200
}
# =========================================================
# OPENAPI DOC ROUTE / BUILD
# =========================================================
Add-KrOpenApiRoute
Build-KrOpenApiDocument
Test-KrOpenApiDocument
# =========================================================
# RUN SERVER
# =========================================================
Start-KrServer -Server $srv -CloseLogsOnExit
Step-by-step
- Logging: Register console logger as default.
- Server: Create server named ‘OpenAPI RequestBody Component’.
- OpenAPI info: Add title and description.
- Define
Productschema (id, productName, price, description, stock, createdAt). - Create
CreateProductRequestcomponent wrappingProduct(JSON + form data) viaOpenApiRequestBodyComponent. - Create
UpdateProductRequestcomponent (JSON) with required name/price viaOpenApiRequestBodyComponent. - POST endpoint: Accept
CreateProductRequest(viaOpenApiRequestBodyRef) and returnProduct(201) or 400. - PUT endpoint: Accept
UpdateProductRequest(viaOpenApiRequestBodyRef) and return updatedProduct(200) or 400/404. - Build and test OpenAPI document.
Try it
# Create product using CreateProductRequest component
curl -X POST http://127.0.0.1:5000/products `
-H "Content-Type: application/json" `
-d '{
"productName": "Gaming Laptop",
"price": 1599.99,
"description": "High-performance laptop for gaming",
"stock": 25
}'
# Update product using UpdateProductRequest component
curl -X PUT http://127.0.0.1:5000/products/1 `
-H "Content-Type: application/json" `
-d '{
"productName": "Gaming Laptop Pro",
"price": 1899.99,
"stock": 15
}'
# View request body components in OpenAPI spec
curl http://127.0.0.1:5000/openapi/v1/openapi.json | jq '.components.requestBodies'
PowerShell create example:
$createPayload = @{
productName = 'Gaming Laptop'
price = 1599.99
description = 'High-performance laptop for gaming'
stock = 25
} | ConvertTo-Json
Invoke-WebRequest -Uri http://127.0.0.1:5000/products `
-Method Post `
-Headers @{ 'Content-Type' = 'application/json' } `
-Body $createPayload
RequestBody Component Attributes
[OpenApiRequestBodyComponent(
Description = 'Product creation payload',
IsRequired = $true,
ContentType = ('application/json', 'application/x-www-form-urlencoded')
)]
class CreateProductRequest:Product {}
- Description: Human-readable description of the request body.
- IsRequired: Set to
$trueto mark the request body as required. - ContentType: Single or array of supported MIME types (e.g.,
'application/json','application/xml'). - Inheritance: The component inherits from a schema class using the colon syntax.
Key Concepts
- Reusability: Define once, reference with
OpenApiRequestBodyRefin multiple endpoints. - Multiple Content Types: Create supports JSON and form; update uses JSON.
- Schema Inheritance: Components inherit from base schema classes (e.g.,
CreateProductRequest:Product). - Typed responses: POST/PUT return the
Productschema with server-generated fields (id,createdAt). - Write-KrResponse content type: Automatically chooses JSON/XML and respects
[OpenApiResponse]ContentTypewhen serializing responses. - Separation: Distinct request components for different operations (Create vs. Update).
Attribute decoration cheatsheet
[OpenApiPath]: Declares verb + route; drives OpenAPI operation generation.[OpenApiResponse]: Documents status codes, descriptions, schemas, and content types.[OpenApiRequestBodyRef]/[OpenApiRequestBody]: Reuse component bodies or document inline payloads.[OpenApiSchemaComponent]/[OpenApiPropertyAttribute]: Define reusable schemas and property constraints (description, format, examples, validation).
Troubleshooting
Issue: Request body component not referenced correctly.
- Solution: Use
[OpenApiRequestBodyRef(ReferenceId = 'ClassName')]and ensure the component class has[OpenApiRequestBodyComponent()]attribute.
Issue: Class inheritance not working with request body components.
- Solution: Use colon syntax
class CreateRequest:BaseSchema {}to inherit properties from base schema.
Issue: Multiple content types not being accepted.
- Solution: Specify all content types in
ContentTypeparameter:ContentType = ('application/json', 'application/xml').
References
- OpenApiRequestBodyComponent
- OpenApiRequestBodyRef
- OpenApiResponse
- OpenApiPath
- Build-KrOpenApiDocument
Previous / Next
Previous: Component Schemas Next: Parameter Components