Tags and External Docs
Group operations with tags and attach external documentation links to both the document and specific routes.
Full source
File: [pwsh/tutorial/examples/10.7-OpenAPI-Tags.ps1][10.7-OpenAPI-Tags.ps1]
<#
Sample: OpenAPI Tags and External Documentation
Purpose: Demonstrate organizing operations with hierarchical (OpenAPI 3.2) tags and linking external documentation to tags.
File: 10.7-OpenAPI-Tags.ps1
Notes: Shows hierarchical tags (parent/kind), tag extensions, and externalDocs extensions.
#>
param(
[int]$Port = 5000,
[IPAddress]$IPAddress = [IPAddress]::Loopback
)
# Configure logging
New-KrLogger |
Add-KrSinkConsole |
Set-KrLoggerLevel -Value Information |
Register-KrLogger -Name 'console' -SetAsDefault | Out-Null
# Create server instance
New-KrServer -Name 'OpenAPI Tags Demo'
# Configure endpoint
Add-KrEndpoint -Port $Port -IPAddress $IPAddress
# Set document-level metadata
Add-KrOpenApiInfo -Title 'Tags Demo API' -Version '1.0.0' -Description 'Demonstrates operation tags with external documentation links.'
# Define hierarchical tags (OpenAPI 3.2) and attach extensions.
# Note: Extension keys are normalized to the required `x-` prefix.
$opsTagExtensions = [ordered]@{
'x-displayName' = 'Operations'
'x-sortOrder' = 1
'x-icon' = 'tools'
}
$ordersTagExtensions = [ordered]@{
'x-displayName' = 'Orders'
'x-sortOrder' = 10
'x-owner' = 'commerce-team'
'x-releaseStage' = 'beta'
}
$healthTagExtensions = [ordered]@{
'x-displayName' = 'Health'
'x-sortOrder' = 20
'x-owner' = 'platform-team'
}
$ordersExternalDocsExtensions = [ordered]@{
'x-docType' = 'reference'
'x-audience' = 'public'
}
$ordersExternalDocs = New-KrOpenApiExternalDoc -Description 'Order docs' -Url 'https://example.com/orders' -Extensions $ordersExternalDocsExtensions
$apiPortalExtensions = [ordered]@{
'x-docType' = 'portal'
'x-audience' = 'internal'
'x-owner' = 'api-platform'
}
# Root tag
Add-KrOpenApiTag -Name 'operations' -Description 'Common operational endpoints' -Kind 'category' -Extensions $opsTagExtensions
# Resource tags
Add-KrOpenApiTag -Name 'orders' -Description 'Order operations' -Parent 'operations' -Kind 'resource' -ExternalDocs $ordersExternalDocs -Extensions $ordersTagExtensions
Add-KrOpenApiTag -Name 'health' -Description 'Service health endpoints' -Parent 'operations' -Kind 'resource' -Extensions $healthTagExtensions
# Leaf tags (operation groups) under resources
Add-KrOpenApiTag -Name 'orders.read' -Description 'Read-only order operations' -Parent 'orders' -Kind 'operation' -Extensions ([ordered]@{ 'x-scope' = 'orders:read' })
Add-KrOpenApiTag -Name 'orders.write' -Description 'Mutating order operations' -Parent 'orders' -Kind 'operation' -Extensions ([ordered]@{ 'x-scope' = 'orders:write' })
Add-KrOpenApiTag -Name 'health.status' -Description 'Health status endpoints' -Parent 'health' -Kind 'operation' -Extensions ([ordered]@{ 'x-scope' = 'health:read' })
# Add top-level external documentation link (document-level externalDocs + extensions)
Add-KrOpenApiExternalDoc -Description 'API portal' -Url 'https://example.com/api-portal' -Extensions $apiPortalExtensions
# Apply configuration and register documentation routes
Enable-KrConfiguration
Add-KrApiDocumentationRoute -DocumentType Swagger -OpenApiEndpoint '/openapi/v3.1/openapi.json'
Add-KrApiDocumentationRoute -DocumentType Redoc -OpenApiEndpoint '/openapi/v3.1/openapi.json'
Add-KrApiDocumentationRoute -DocumentType Elements -OpenApiEndpoint '/openapi/v3.2/openapi.json'
Add-KrApiDocumentationRoute -DocumentType Scalar -OpenApiEndpoint '/openapi/v3.2/openapi.json'
Add-KrApiDocumentationRoute -DocumentType Rapidoc -OpenApiEndpoint '/openapi/v3.2/openapi.json'
Add-KrOpenApiRoute
<#
.SYNOPSIS
Retrieves a list of demo orders.
.DESCRIPTION
This endpoint returns a simple list of order identifiers.
It is tagged with a hierarchical tag ('orders.read') plus its parents ('orders', 'operations').
#>
function getOrders {
[OpenApiPath(HttpVerb = 'get', Pattern = '/orders', Summary = 'List demo orders', Description = 'Returns a simple list of order identifiers.', Tags = ('orders.read', 'orders', 'operations'))]
[OpenApiResponse(StatusCode = '200', Description = 'List of orders', ContentType = 'application/json')]
param()
Write-KrJsonResponse -InputObject @{ orders = @('order-1001', 'order-2002') }
}
<#
.SYNOPSIS
Retrieves the health status of the service.
.DESCRIPTION
This endpoint returns a simple health status payload.
It is tagged with a hierarchical tag ('health.status') plus its parents ('health', 'operations').
#>
function getHealth {
[OpenApiPath(HttpVerb = 'get', Pattern = '/health', Summary = 'Service health', Description = 'Returns a simple health status payload.', Tags = ('health.status', 'health', 'operations'))]
[OpenApiResponse(StatusCode = '200', Description = 'Health status', ContentType = 'application/json')]
param()
Write-KrJsonResponse -InputObject @{ status = 'healthy' }
}
# Build and validate the OpenAPI specification
Build-KrOpenApiDocument
Test-KrOpenApiDocument
# Start the server and keep logs open until exit
Start-KrServer -CloseLogsOnExit
Step-by-step
- Register console logger and create the server.
- Add OpenAPI info and define document-level external docs (API portal + extensions).
- Declare hierarchical tags (OpenAPI 3.2): a root
operationstag, resource tags likeorders/health, and leaf tags likeorders.read. - Add tag extensions (
x-*) plus externalDocs extensions for theorderstag. - Enable configuration and register documentation UIs pointing at the OpenAPI 3.2 endpoint.
- Build and test the OpenAPI document, then start the server.
Try it
# View the spec with tag metadata
curl http://127.0.0.1:5000/openapi/v3.2/openapi.json | jq .tags
# View the document-level external docs
curl http://127.0.0.1:5000/openapi/v3.2/openapi.json | jq .externalDocs
# Hit tagged endpoints
curl http://127.0.0.1:5000/orders
curl http://127.0.0.1:5000/health
# Browse Swagger UI
# Visit http://127.0.0.1:5000/swagger in your browser
Key Concepts
- Hierarchical tags (OpenAPI 3.2): Use
parentandkindon tags to create a tree (e.g.operations→orders→orders.read). - Tag extensions: Add
x-*fields on tags and external docs for UI/tooling hints. - External docs: Attach URLs at document level and to tags.
- Route metadata: Use
OpenApiPath(with multiple tags) andOpenApiResponseattributes to describe operations. - Doc viewers: Swagger/ReDoc routes render tags and external docs automatically.
Troubleshooting
Issue: Tags not appearing on operations.
- Solution: Ensure each function includes
Tags = @('tag1','tag2')on[OpenApiPath].
Issue: External docs link missing.
- Solution: Provide a valid
-UrlonAdd-KrOpenApiExternalDocor pass-ExternalDocstoAdd-KrOpenApiTagand rebuild the document.
Issue: Tag external docs extensions not showing.
- Solution: Create the
OpenApiExternalDocsobject viaNew-KrOpenApiExternalDoc -Extensions $extensionsand pass it toAdd-KrOpenApiTag -ExternalDocs.
Issue: Swagger or ReDoc 404s.
- Solution: Confirm both
Add-KrApiDocumentationRouteandAdd-KrOpenApiRouteare called afterEnable-KrConfiguration.
References
- Add-KrOpenApiInfo
- Add-KrOpenApiTag
- Add-KrOpenApiExternalDoc
- New-KrOpenApiExternalDoc
- Add-KrApiDocumentationRoute
- Add-KrOpenApiRoute
- Build-KrOpenApiDocument
- Test-KrOpenApiDocument
- Write-KrJsonResponse
- OpenApiPath
- OpenApiResponse
Previous / Next
Previous: Complete Components Next: Document Information