Public/Route/Add-KrRouteGroup.ps1
<# .SYNOPSIS Creates a grouped route context (prefix + shared options) for nested Add-KrMapRoute calls. .DESCRIPTION While the ScriptBlock runs, all Add-KrMapRoute calls inherit: - Prefix (prepended to -Path) - AuthorizationSchema / AuthorizationPolicy - ExtraImports / ExtraRefs - Arguments (merged; child overrides keys) Supports nesting; inner groups inherit and can override unless -NoInherit is used. .PARAMETER Server The Kestrun server instance to which the route will be added. If not specified, the function will attempt to resolve the current server context. .PARAMETER Options The options to apply to all routes in the group. .PARAMETER Prefix The path prefix for the group (e.g. '/todoitems'). .PARAMETER AuthorizationSchema Authorization schemes required by all routes in the group. .PARAMETER AuthorizationPolicy Authorization policies required by all routes in the group. .PARAMETER ExtraImports Extra namespaces added to all routes in the group. .PARAMETER ExtraRefs Extra assemblies referenced by all routes in the group. .PARAMETER Arguments Extra arguments injected into all routes in the group. .PARAMETER ScriptBlock ScriptBlock within which you call Add-KrMapRoute for relative paths. .PARAMETER FileName Path to a script file containing the scriptblock to execute. .PARAMETER NoInherit If set, do not inherit options from the parent group; only apply the current parameters. .PARAMETER PassThru If specified, the function will return the created route object. .EXAMPLE Add-KrRouteGroup -Prefix '/todoitems' -AuthorizationPolicy 'RequireUser' -ScriptBlock { Add-KrMapRoute -Verbs Get -Path '/' -ScriptBlock { 'all todos' } Add-KrMapRoute -Verbs Get -Path '/{id}' -ScriptBlock { "todo $($Context.Request.RouteValues['id'])" } Add-KrMapRoute -Verbs Post -Path '/' -ScriptBlock { write-KrResponse -InputObject 'create' } } Adds a new route group to the specified Kestrun server with the given prefix and options. .EXAMPLE Add-KrRouteGroup -Prefix '/todoitems' -FileName 'C:\Scripts\TodoItems.ps1' Add the new route group defined in the specified file. .NOTES This function is part of the Kestrun PowerShell module and is used to manage routes #> function Add-KrRouteGroup { [KestrunRuntimeApi('Definition')] [CmdletBinding(DefaultParameterSetName = 'ScriptBlock', PositionalBinding = $true)] param( [Parameter(Mandatory = $false, ValueFromPipeline = $true)] [Kestrun.Hosting.KestrunHost]$Server, [Parameter(Mandatory, ParameterSetName = 'ScriptBlockWithOptions')] [Parameter(Mandatory, ParameterSetName = 'FileNameWithOptions')] [Kestrun.Hosting.Options.MapRouteOptions]$Options, [Parameter(ParameterSetName = 'ScriptBlock')] [Parameter(ParameterSetName = 'FileName')] [string]$Prefix, [Parameter(ParameterSetName = 'ScriptBlock')] [Parameter(ParameterSetName = 'FileName')] [string[]]$AuthorizationSchema, [Parameter(ParameterSetName = 'ScriptBlock')] [Parameter(ParameterSetName = 'FileName')] [string[]]$AuthorizationPolicy, [Parameter(ParameterSetName = 'ScriptBlock')] [Parameter(ParameterSetName = 'FileName')] [string[]]$ExtraImports, [Parameter(ParameterSetName = 'ScriptBlock')] [Parameter(ParameterSetName = 'FileName')] [System.Reflection.Assembly[]]$ExtraRefs, [Parameter(ParameterSetName = 'ScriptBlock')] [Parameter(ParameterSetName = 'FileName')] [hashtable]$Arguments, [Parameter(Mandatory, Position = 0, ParameterSetName = 'ScriptBlock')] [Parameter(Mandatory, Position = 0, ParameterSetName = 'ScriptBlockWithOptions')] [scriptblock]$ScriptBlock, [Parameter(Mandatory, ParameterSetName = 'FileName')] [Parameter(Mandatory, ParameterSetName = 'FileNameWithOptions')] [string]$FileName, [Parameter()] [switch]$NoInherit, [Parameter()] [switch]$PassThru ) process { # Ensure the server instance is resolved $Server = Resolve-KestrunServer -Server $Server if ($PSCmdlet.ParameterSetName -like 'FileName*') { if (-not (Test-Path -Path $FileName)) { throw "The specified file path does not exist: $FileName" } $code = Get-Content -Path $FileName -Raw $ScriptBlock = [scriptblock]::Create($code) } # Normalize prefix: allow "todoitems" or "/todoitems" if (-not [string]::IsNullOrWhiteSpace($Prefix) -and -not $Prefix.StartsWith('/')) { $Prefix = "/$Prefix" } # Discover parent template (stack always aims to hold MapRouteOptions) $parentOpts = $null if (-not $NoInherit -and $server.RouteGroupStack.Count) { $parentOpts = $server.RouteGroupStack.Peek() } $curr = if ($PSCmdlet.ParameterSetName -like '*WithOptions') { $Options } else { $dict = $null if ($Arguments) { $dict = [System.Collections.Generic.Dictionary[string, object]]::new() foreach ($k in $Arguments.Keys) { $dict[$k] = $Arguments[$k] } } New-KrMapRouteOption -Property @{ RequireSchemes = $AuthorizationSchema RequirePolicies = $AuthorizationPolicy ExtraImports = $ExtraImports ExtraRefs = $ExtraRefs Arguments = $dict Pattern = $Prefix } } # Merge with parent (parent first, then current overrides) if ($parentOpts) { $curr = _KrMerge-MRO -Parent $parentOpts -Child $curr } $Server.RouteGroupStack.Push($curr) try { & $ScriptBlock } catch { $msg = "Error inside route group '$($current.Prefix)': $($_.Exception.Message)" throw [System.Exception]::new($msg, $_.Exception) } finally { $null = $Server.RouteGroupStack.Pop() if ($restorePath) { Set-Location $restorePath } } if ($PassThru.IsPresent) { # if the PassThru switch is specified, return the server instance # Return the modified server instance return $Server } } } |