application/x-www-form-urlencoded forms

Parse classic HTML form posts with urlencoded bodies.

Full source

File: pwsh/tutorial/examples/22.3-Url-Encoded.ps1

<#!
    22.3-Url-Encoded application/x-www-form-urlencoded forms

    Client example (PowerShell):
        $body = 'name=Kestrun&role=admin&role=maintainer'
        Invoke-RestMethod -Method Post -Uri "http://127.0.0.1:$Port/form" -ContentType 'application/x-www-form-urlencoded' -Body $body

    Cleanup:
        Remove-Item -Recurse -Force (Join-Path ([System.IO.Path]::GetTempPath()) 'kestrun-uploads-22.3-urlencoded')
#>
param(
    [int]$Port = 5000,
    [IPAddress]$IPAddress = [IPAddress]::Loopback
)

New-KrLogger |
    Set-KrLoggerLevel -Value Debug |
    Add-KrSinkConsole |
    Register-KrLogger -Name 'console' -SetAsDefault

New-KrServer -Name 'Forms 22.3'

Add-KrEndpoint -Port $Port -IPAddress $IPAddress | Out-Null

# Upload directory
$scriptName = [System.IO.Path]::GetFileNameWithoutExtension($PSCommandPath)
$uploadRoot = Join-Path -Path ([System.IO.Path]::GetTempPath()) -ChildPath "kestrun-uploads-$scriptName"

# Opt-in: only multipart/form-data is enabled by default
New-KrFormPartRule -Name 'name' -Required |
    New-KrFormPartRule -Name 'role' |
    Add-KrFormOption -DefaultUploadPath $uploadRoot -AllowedRequestContentTypes 'application/x-www-form-urlencoded' |

    Add-KrFormRoute -Pattern '/form' -ScriptBlock {
        $fields = @{}
        foreach ($key in $FormPayload.Fields.Keys) {
            $fields[$key] = $FormPayload.Fields[$key]
        }
        Write-KrJsonResponse -InputObject @{ fields = $fields } -StatusCode 200
    }

Enable-KrConfiguration

# Start the server asynchronously
Start-KrServer

Step-by-step

  1. Logger: Enable console logging.
  2. Server: Create the host and bind a listener.
  3. Options: Opt in to application/x-www-form-urlencoded via AllowedRequestContentTypes.
  4. Route: Add /form with Add-KrFormRoute.
  5. Response: Return parsed fields as JSON.

Try it

$body = 'name=Kestrun&role=admin&role=maintainer'
Invoke-RestMethod -Method Post -Uri 'http://127.0.0.1:5000/form' -ContentType 'application/x-www-form-urlencoded' -Body $body
curl -X POST -H "Content-Type: application/x-www-form-urlencoded" -d "name=Kestrun&role=admin&role=maintainer" http://127.0.0.1:5000/form

Expected output

{
  "fields": {
    "name": ["Kestrun"],
    "role": ["admin", "maintainer"]
  }
}

Notes

  • Content types: Add-KrFormRoute defaults to multipart/form-data only; this script opts in to application/x-www-form-urlencoded.
  • Limits: MaxFieldValueBytes bounds each field value.
  • Security: Request body size can be capped via MaxRequestBodyBytes.
  • Logging: Parser logs metadata without field values.

Troubleshooting

  • 415 / Unsupported Content-Type: Ensure the request Content-Type is application/x-www-form-urlencoded and the route options allow it.
  • Missing multi-values: Repeat the key (e.g. role=admin&role=maintainer).

References


Previous / Next

Previous: Multiple files (same field name) Next: multipart/mixed ordered parts