Parameter Components

Create reusable parameter components for query strings, path variables, headers, and cookies.

Full source

File: [pwsh/tutorial/examples/10.4-OpenAPI-Component-Parameter.ps1][10.4-OpenAPI-Component-Parameter.ps1]

<#
    Sample: OpenAPI Parameter Components
    Purpose: Demonstrate reusable parameter components for pagination, filtering, and sorting.
    File:    10.4-OpenAPI-Component-Parameter.ps1
    Notes:   Shows parameter location (Query), combined parameter components, and typed responses.
#>
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 Parameter Component' -PassThru

Add-KrEndpoint -Port $Port -IPAddress $IPAddress
# =========================================================
#                 TOP-LEVEL OPENAPI
# =========================================================

Add-KrOpenApiInfo -Title 'Parameter Component API' `
    -Version '1.0.0' `
    -Description 'Demonstrates reusable parameter components.'

# =========================================================
#                 COMPONENT PARAMETERS
# =========================================================

# Define reusable parameter components using class attributes
[OpenApiParameterComponent()]
class PaginationParameters {
    [OpenApiParameter(In = [OaParameterLocation]::Query, Description = 'Page number')]

    [OpenApiPropertyAttribute(Minimum = 1, Example = 1)]
    [int]$page = 1

    [OpenApiParameter(In = [OaParameterLocation]::Query, Description = 'Items per page')]
    [OpenApiPropertyAttribute(Minimum = 1, Maximum = 100, Example = 20)]
    [int]$limit = 20

    [OpenApiParameter(In = [OaParameterLocation]::Query, Description = 'Sort field (name, date, price)')]
    [OpenApiPropertyAttribute(Example = 'date')]
    [ValidateSet('name', 'date', 'price')]
    [string]$sortBy = 'date'

    [OpenApiParameter(In = [OaParameterLocation]::Query, Description = 'Filter by category')]
    [OpenApiPropertyAttribute(Example = 'electronics')]
    [string]$category

    [OpenApiParameter(In = [OaParameterLocation]::Query, Description = 'Filter by minimum price')]
    [OpenApiPropertyAttribute(Format = 'double', Example = 100)]
    [double]$minPrice

    [OpenApiParameter(In = [OaParameterLocation]::Query, Description = 'Filter by maximum price')]
    [OpenApiPropertyAttribute(Format = 'double', Example = 5000)]
    [double]$maxPrice
}

# =========================================================
#                      COMPONENT SCHEMAS
# =========================================================

[OpenApiSchemaComponent()]
class ProductItem {
    [OpenApiPropertyAttribute(Description = 'Product ID', Format = 'int64', Example = 1)]
    [long]$id

    [OpenApiPropertyAttribute(Description = 'Product name', Example = 'Laptop')]
    [string]$name

    [OpenApiPropertyAttribute(Description = 'Product category', Example = 'electronics')]
    [string]$category

    [OpenApiPropertyAttribute(Description = 'Product price', Format = 'double', Example = 999.99)]
    [double]$price
}

[OpenApiSchemaComponent()]
class ProductListResponse {
    [OpenApiPropertyAttribute(Description = 'Current page number', Example = 1)]
    [int]$page

    [OpenApiPropertyAttribute(Description = 'Items per page', Example = 20)]
    [int]$limit

    [OpenApiPropertyAttribute(Description = 'Total number of items', Example = 5)]
    [int]$total

    [OpenApiPropertyAttribute(Description = 'List of products')]
    [ProductItem[]]$items
}

# =========================================================
#                 ROUTES / OPERATIONS
# =========================================================

Enable-KrConfiguration

Add-KrApiDocumentationRoute -DocumentType Swagger
Add-KrApiDocumentationRoute -DocumentType Redoc

<#
.SYNOPSIS
    List products with filters and pagination.
.DESCRIPTION
    Retrieves a paginated list of products with optional filtering and sorting.
.PARAMETER page
    Page number (pagination component)
.PARAMETER limit
    Items per page (pagination component)
.PARAMETER sortBy
    Sort field (pagination component)
.PARAMETER category
    Filter by category (filter component)
.PARAMETER minPrice
    Minimum price filter (filter component)
.PARAMETER maxPrice
    Maximum price filter (filter component)
#>
function listProducts {
    [OpenApiPath(HttpVerb = 'get', Pattern = '/products')]
    [OpenApiResponse(StatusCode = '200', Description = 'List of products', Schema = [ProductListResponse], ContentType = ('application/json', 'application/xml'))]
    [OpenApiResponse(StatusCode = '400', Description = 'Invalid parameters')]
    param(
        [OpenApiParameterRef(ReferenceId = 'page')]
        [int]$page,

        [OpenApiParameterRef(ReferenceId = 'limit')]
        [int]$limit,

        [OpenApiParameterRef(ReferenceId = 'sortBy')]
        [string]$sortBy,

        [OpenApiParameterRef(ReferenceId = 'category')]
        [string]$category,

        [OpenApiParameterRef(ReferenceId = 'minPrice')]
        [double]$minPrice,

        [OpenApiParameterRef(ReferenceId = 'maxPrice')]
        [double]$maxPrice
    )

    # Mock product data
    $allProducts = @(
        @{ id = 1; name = 'Laptop'; category = 'electronics'; price = 999.99 }
        @{ id = 2; name = 'Mouse'; category = 'electronics'; price = 29.99 }
        @{ id = 3; name = 'Keyboard'; category = 'electronics'; price = 79.99 }
        @{ id = 4; name = 'Monitor'; category = 'electronics'; price = 299.99 }
        @{ id = 5; name = 'Desk Lamp'; category = 'office'; price = 49.99 }
    )

    # Apply filters
    $filtered = $allProducts
    if ($category) {
        $filtered = $filtered | Where-Object { $_.category -eq $category }
    }
    if ($minPrice) {
        $filtered = $filtered | Where-Object { $_.price -ge [double]$minPrice }
    }
    if ($maxPrice) {
        $filtered = $filtered | Where-Object { $_.price -le [double]$maxPrice }
    }

    # Sort
    if ($sortBy -eq 'price') {
        $filtered = $filtered | Sort-Object -Property price
    } elseif ($sortBy -eq 'name') {
        $filtered = $filtered | Sort-Object -Property name
    }

    # Paginate
    $page = [int]$page
    $limit = [int]$limit
    $skip = ($page - 1) * $limit
    $paged = $filtered | Select-Object -Skip $skip -First $limit

    # Convert to ProductItem array
    $productItems = $paged | ForEach-Object {
        [ProductItem]@{
            id = $_.id
            name = $_.name
            category = $_.category
            price = $_.price
        }
    }

    # Build typed response
    $response = [ProductListResponse]@{
        page = $page
        limit = $limit
        total = $filtered.Count
        items = $productItems
    }

    Write-KrResponse $response -StatusCode 200
}

# =========================================================
#                OPENAPI DOC ROUTE / BUILD
# =========================================================

Add-KrOpenApiRoute

# =========================================================
#                      RUN SERVER
# =========================================================

Start-KrServer -Server $srv -CloseLogsOnExit


Step-by-step

  1. Logging: Register console logger as default.
  2. Server: Create server named ‘OpenAPI Parameter Component’ and add endpoint.
  3. OpenAPI info: Add title and description.
  4. Parameter component: Define PaginationParameters component with page, limit, sortBy, category, minPrice, and maxPrice fields.
  5. Schema components: Define ProductItem schema (id, name, category, price) and ProductListResponse schema (page, limit, total, items).
  6. Configuration: Enable configuration and add Swagger/Redoc documentation routes.
  7. GET endpoint: Define listProducts function with [OpenApiPath] attribute, reference parameters using [OpenApiParameterRef].
  8. Response attributes: Add [OpenApiResponse] attributes with Schema = [ProductListResponse] for 200 status.
  9. Filter and paginate: Apply category and price filters, sort results, paginate with page/limit.
  10. Typed response: Convert filtered results to [ProductItem] array, wrap in [ProductListResponse] object.
  11. Return response: Use Write-KrResponse to automatically handle JSON/XML/YAML content negotiation.

Try it

# List products with pagination
curl -i "http://127.0.0.1:5000/products?page=1&limit=10"

# List with sorting
curl -i "http://127.0.0.1:5000/products?page=1&limit=10&sortBy=price"

# List with category filter
curl -i "http://127.0.0.1:5000/products?category=electronics&limit=20"

# List with price range filter
curl -i "http://127.0.0.1:5000/products?minPrice=100&maxPrice=1000"

# Combine filters and pagination
curl -i "http://127.0.0.1:5000/products?category=office&minPrice=40&maxPrice=100&page=1&limit=5&sortBy=price"

PowerShell with parameter hashtable:

$params = @{
    page    = 1
    limit   = 10
    sortBy  = 'price'
    category = 'electronics'
}

$uri = "http://127.0.0.1:5000/products?" + ($params.GetEnumerator() | ForEach-Object { "$($_.Key)=$($_.Value)" } -join '&')

Invoke-WebRequest -Uri $uri | Select-Object StatusCode, Content

Parameter Component Attributes

[OpenApiParameterComponent()]
class PaginationParameters {
    [OpenApiParameter(In = [OaParameterLocation]::Query, Description = 'Page number')]
    [OpenApiPropertyAttribute(Minimum = 1, Example = 1)]
    [int]$page

    [OpenApiParameter(In = [OaParameterLocation]::Query, Description = 'Items per page')]
    [OpenApiPropertyAttribute(Minimum = 1, Maximum = 100, Example = 20)]
    [int]$limit

    [OpenApiParameter(In = [OaParameterLocation]::Query, Description = 'Sort field (name, date, price)')]
    [OpenApiPropertyAttribute(Example = 'date')]
    [ValidateSet('name', 'date', 'price')]
    [string]$sortBy
}

Attribute Pattern:

  • [OpenApiParameterComponent()]: Marks a class as a reusable parameter component.
  • [OpenApiParameter(In = ..., Description = ...)]: Defines parameter location (Query, Path, Header, Cookie) and description.
  • [OpenApiPropertyAttribute(...)]: Decorates properties with schema constraints (Minimum, Maximum, Format, Example).
  • [ValidateSet(...)]: Restricts values to enumerated list; appears in OpenAPI as enum.

Usage in Functions:

function listProducts {
    param(
        [OpenApiParameterRef(ReferenceId = 'page')]
        [int]$page = 1,

        [OpenApiParameterRef(ReferenceId = 'limit')]
        [int]$limit = 20
    )
}

Parameter Locations

Parameters can be in different locations:

  • Query: ?page=1&limit=10 (most common for filtering/pagination).
  • Path: /products/{productId} (dynamic route segments).
  • Header: Custom HTTP headers.
  • Cookie: Cookie values.

Key Concepts

  • Parameter Components: Define reusable query, path, header, or cookie parameters once, reference with [OpenApiParameterRef(ReferenceId = 'paramName')].
  • Attribute Layering: Combine [OpenApiParameter] (location, description) with [OpenApiPropertyAttribute] (schema constraints).
  • Schema Components: Use [OpenApiSchemaComponent()] classes to define response structures (ProductItem, ProductListResponse).
  • Typed Responses: Convert hashtables to typed PowerShell class instances for accurate OpenAPI schema documentation.
  • Content Negotiation: Write-KrResponse automatically handles JSON, XML, YAML, and form-urlencoded based on Accept header.
  • Pagination: Use page and limit parameters for result limiting and offset.
  • Filtering: Combine filter parameters to narrow results (category, price range, date range).
  • Sorting: Allow clients to specify sort order via sortBy parameter.
  • Validation: Use constraints (Minimum, Maximum, Format) to document and validate parameter values.

Attribute Decoration Cheatsheet

Purpose Attribute Usage
Parameter component class [OpenApiParameterComponent()] Marks class as reusable parameter definition
Parameter location [OpenApiParameter(In = [OaParameterLocation]::Query)] Defines where parameter appears (Query/Path/Header/Cookie)
Parameter reference [OpenApiParameterRef(ReferenceId = 'name')] References parameter component in function params
Schema component class [OpenApiSchemaComponent()] Marks class as reusable schema definition
Property schema [OpenApiPropertyAttribute(...)] Defines property constraints (Minimum, Maximum, Format, Example)
Route definition [OpenApiPath(HttpVerb = 'get', Pattern = '/path')] Maps function to HTTP endpoint
Response schema [OpenApiResponse(StatusCode = '200', Schema = [ClassName])] Documents response status and schema

Troubleshooting

Issue: Parameter reference not found in OpenAPI spec.

  • Solution: Ensure property name in [OpenApiParameterRef(ReferenceId = 'propertyName')] matches the property name in the parameter component class.

Issue: Query parameters not being parsed correctly.

  • Solution: Verify In = [OaParameterLocation]::Query is set on each parameter property in the component class.

Issue: Validation constraints not appearing in OpenAPI.

  • Solution: Add validation using [OpenApiPropertyAttribute(Minimum = ..., Maximum = ...)] on parameter properties.

References


Previous / Next

Previous: RequestBody Components Next: Response Components