Component Schemas
Define reusable request and response schemas using PowerShell classes decorated with OpenAPI attributes.
Full source
File: [pwsh/tutorial/examples/10.2-OpenAPI-Component-Schema.ps1][10.2-OpenAPI-Component-Schema.ps1]
<#
Sample: OpenAPI Component Schemas
Purpose: Demonstrate reusable component schemas for request and response payloads.
File: 10.2-OpenAPI-Component-Schema.ps1
Notes: Shows schema component definition with required fields, property attributes, 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 Component Schema' -PassThru
Add-KrEndpoint -Port $Port -IPAddress $IPAddress
# =========================================================
# TOP-LEVEL OPENAPI
# =========================================================
Add-KrOpenApiInfo -Title 'Component Schema API' `
-Version '1.0.0' `
-Description 'Demonstrates reusable component schemas passed as parameters and returned as responses.'
# =========================================================
# COMPONENT SCHEMAS
# =========================================================
# Request schema: User input for creating a user
[OpenApiSchemaComponent(Required = ('firstName', 'lastName', 'email'))]
class CreateUserRequest {
[OpenApiPropertyAttribute(Description = 'First name of the user', Example = 'John')]
[string]$firstName
[OpenApiPropertyAttribute(Description = 'Last name of the user', Example = 'Doe')]
[string]$lastName
[OpenApiPropertyAttribute(Description = 'Email address', Format = 'email', Example = 'john.doe@example.com')]
[string]$email
[OpenApiPropertyAttribute(Description = 'User age', Minimum = 0, Maximum = 150, Example = 30)]
[int]$age
}
# Response schema: User data returned from server
[OpenApiSchemaComponent(Required = ('id', 'firstName', 'lastName', 'email'))]
class UserResponse {
[OpenApiPropertyAttribute(Description = 'Unique user identifier', Format = 'int64', Example = 1)]
[long]$id
[OpenApiPropertyAttribute(Description = 'First name', Example = 'John')]
[string]$firstName
[OpenApiPropertyAttribute(Description = 'Last name', Example = 'Doe')]
[string]$lastName
[OpenApiPropertyAttribute(Description = 'Email address', Format = 'email', Example = 'john.doe@example.com')]
[string]$email
[OpenApiPropertyAttribute(Description = 'User age', Example = 30)]
[int]$age
[OpenApiPropertyAttribute(Description = 'ISO 8601 creation timestamp', Format = 'date-time')]
[string]$createdAt
}
# =========================================================
# ROUTES / OPERATIONS
# =========================================================
Enable-KrConfiguration
Add-KrApiDocumentationRoute -DocumentType Swagger
Add-KrApiDocumentationRoute -DocumentType Redoc
# POST endpoint: Accept CreateUserRequest, return UserResponse
<#
.SYNOPSIS
Create a new user.
.DESCRIPTION
Accepts user information and returns the created user with an assigned ID.
.PARAMETER body
User creation request payload
#>
function createUser {
[OpenApiPath(HttpVerb = 'post', Pattern = '/users')]
[OpenApiResponse(StatusCode = '201', Description = 'User created successfully', Schema = [UserResponse], ContentType = ('application/json', 'application/xml', 'application/yaml'))]
[OpenApiResponse(StatusCode = '400', Description = 'Invalid input')]
param(
[OpenApiRequestBody(ContentType = ('application/json', 'application/xml', 'application/yaml', 'application/x-www-form-urlencoded'))]
[CreateUserRequest]$body
)
# Simple validation
if (-not $body.firstName -or -not $body.lastName -or -not $body.email) {
Write-KrJsonResponse @{error = 'firstName, lastName, and email are required' } -StatusCode 400
return
}
# Create response
$response = @{
id = 1
firstName = $body.firstName
lastName = $body.lastName
email = $body.email
age = $body.age -as [int]
createdAt = (Get-Date).ToUniversalTime().ToString('o')
}
Write-KrResponse $response -StatusCode 201
}
# GET endpoint: Return a user by ID as UserResponse
<#
.SYNOPSIS
Get user by ID.
.DESCRIPTION
Retrieves a user resource by its identifier.
.PARAMETER userId
The user ID to retrieve
#>
function getUser {
[OpenApiPath(HttpVerb = 'get', Pattern = '/users/{userId}')]
[OpenApiResponse(StatusCode = '200', Description = 'User found', Schema = [UserResponse], ContentType = ('application/json', 'application/xml', 'application/yaml'))]
[OpenApiResponse(StatusCode = '404', Description = 'User not found')]
param(
[OpenApiParameter(In = [OaParameterLocation]::Path, Required = $true)]
[int]$userId
)
# Mock user data
[UserResponse]$response = [UserResponse]::new()
$response.id = $userId
$response.firstName = 'John'
$response.lastName = 'Doe'
$response.email = 'john.doe@example.com'
$response.age = 30
$response.createdAt = (Get-Date).AddDays(-1).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 Component Schema’.
- OpenAPI info: Add title, version, and description.
- Define
CreateUserRequestschema with required fields (firstName, lastName, email). - Define
UserResponseschema with all user fields including timestamps. - POST endpoint: Accept
CreateUserRequestbody (JSON/XML/YAML/form) and returnUserResponse(201) or 400. - GET endpoint: Return
UserResponse(200) for a given user ID or 404 when missing. - Build and test OpenAPI document, then start server.
Try it
# Create a new user (POST with CreateUserRequest)
curl -X POST http://127.0.0.1:5000/users `
-H "Content-Type: application/json" `
-d '{
"firstName": "Jane",
"lastName": "Smith",
"email": "jane.smith@example.com",
"age": 28
}'
# Get user by ID (returns UserResponse)
curl -i http://127.0.0.1:5000/users/1
# View the OpenAPI specification
curl http://127.0.0.1:5000/openapi/v1/openapi.json | ConvertFrom-Json | ConvertTo-Json
PowerShell equivalent for POST:
$body = @{
firstName = 'Jane'
lastName = 'Smith'
email = 'jane.smith@example.com'
age = 28
} | ConvertTo-Json
Invoke-WebRequest -Uri http://127.0.0.1:5000/users `
-Method Post `
-Headers @{ 'Content-Type' = 'application/json' } `
-Body $body | Select-Object StatusCode, Content
Schema Component Attributes
[OpenApiSchemaComponent(Required = ('firstName', 'lastName', 'email'))]
class CreateUserRequest {
[OpenApiPropertyAttribute(Description = 'First name', Example = 'John')]
[string]$firstName
}
- Required: Comma-separated field names that must be present.
- Description: Markdown-formatted component description.
- OpenApiPropertyAttribute: Decorates individual properties with constraints (Example, Format, MinLength, MaxLength, Pattern, etc.).
Key Concepts
- Request Schema: Defines the structure of incoming data (POST/PUT bodies).
- Response Schema: Defines the structure of outgoing data.
- Multiple content types: POST supports
application/json,application/xml,application/yaml, and form data. - Reusability: Schemas are registered as OpenAPI components and can be referenced across multiple endpoints.
- Validation: Use
Required,ValidateLength,ValidateRange,ValidateSeton properties for constraints. - Examples: Populate
Exampleattribute for clear documentation. - Write-KrResponse content type: Automatically chooses JSON/XML/YAML and supports
application/x-www-form-urlencoded, respecting[OpenApiResponse]ContentType.
Attribute decoration cheatsheet
[OpenApiPath]: Declares the route/verb and wires the function into OpenAPI generation.[OpenApiResponse]: Documents each status code, description, schema, and content types.[OpenApiRequestBody]: Documents inline bodies (or useRefvariants to point to components).[OpenApiSchemaComponent]/[OpenApiPropertyAttribute]: Define reusable schemas and property metadata (description, format, examples, validation ranges/sets).
Troubleshooting
Issue: Schema component not appearing in OpenAPI spec.
- Solution: Ensure the class has
[OpenApiSchemaComponent()]attribute and is referenced in a request body or response.
Issue: Required fields validation not working.
- Solution: Add
Required = ('field1', 'field2')parameter to[OpenApiSchemaComponent()]attribute.
Issue: Write-KrResponse returns wrong content type.
- Solution: Verify Accept header in request matches one of the
ContentTypevalues in[OpenApiResponse]attribute.
References
- OpenApiSchemaComponent
- OpenApiPropertyAttribute
- OpenApiRequestBody
- OpenApiResponse
- OpenApiPath
- Add-KrOpenApiInfo
- Build-KrOpenApiDocument
Previous / Next
Previous: Hello World Next: RequestBody Components