From a545aae3b4c043b098bb0af6283523e6e2753bfb Mon Sep 17 00:00:00 2001 From: mdaneri Date: Mon, 24 Jun 2024 09:30:46 -0700 Subject: [PATCH 01/10] Add new Rename-PodeOADefinitionTagName function make the OpenAPI DefaultDefinitionTag in line with the Pode standard --- docs/Tutorials/OpenAPI/Overview.md | 26 ++++++++- src/Pode.psd1 | 1 + src/Private/Context.ps1 | 9 ++- src/Private/OpenApi.ps1 | 11 +--- src/Public/OpenApi.ps1 | 76 ++++++++++++++++++++---- tests/unit/OpenApi.Tests.ps1 | 69 ++++++++++++++++++++++ tests/unit/PrivateOpenApi.Tests.ps1 | 89 ++++++++++++++--------------- 7 files changed, 213 insertions(+), 68 deletions(-) diff --git a/docs/Tutorials/OpenAPI/Overview.md b/docs/Tutorials/OpenAPI/Overview.md index 66098b2e5..5c4bdbb15 100644 --- a/docs/Tutorials/OpenAPI/Overview.md +++ b/docs/Tutorials/OpenAPI/Overview.md @@ -987,12 +987,36 @@ The default `Definition Tag` is named "default". This can be changed using the ` @{ Web=@{ OpenApi=@{ - DefaultDefinitionTag= 'NewDfault' + DefaultDefinitionTag= 'NewDefault' } } } ``` +### Renaming a Definition Tag + +A `Definition Tag` can be renamed at any time using the `Rename-PodeOADefinitionTagName` function. This allows you to update the tag name for an existing OpenAPI definition, ensuring your tags remain organized and meaningful. + +```powershell +Rename-PodeOADefinitionTagName -Tag 'v.3' -NewTag 'v.3.0.3' +``` + +In this example, the tag `'v.3'` is renamed to `'v.3.0.3'`. + +### Renaming the Default Definition Tag + +You can also rename the default `Definition Tag` without specifying the `Tag` parameter. This updates the default tag to the new name provided. + +```powershell +Rename-PodeOADefinitionTagName -NewTag 'NewDefault' +``` + +In this example, the default definition tag is renamed to `'NewDefault'`. + +!!! note +The `Rename-PodeOADefinitionTagName` function cannot be used inside a `Select-PodeOADefinition` `[Scriptblock]`. Attempting to do so will result in an error. + + ### OpenAPI example A simple OpenAPI definition diff --git a/src/Pode.psd1 b/src/Pode.psd1 index 6df13ad50..d0295957c 100644 --- a/src/Pode.psd1 +++ b/src/Pode.psd1 @@ -313,6 +313,7 @@ 'New-PodeOARequestBody', 'Test-PodeOADefinitionTag', 'Test-PodeOADefinition', + 'Rename-PodeOADefinitionTagName', # properties 'New-PodeOAIntProperty', diff --git a/src/Private/Context.ps1 b/src/Private/Context.ps1 index d7139aedd..4771d9035 100644 --- a/src/Private/Context.ps1 +++ b/src/Private/Context.ps1 @@ -373,7 +373,7 @@ function New-PodeContext { $ctx.Server.Sessions = @{} #OpenApi Definition Tag - $ctx.Server.OpenAPI = Initialize-PodeOpenApiTable -DefaultDefinitionTag $ctx.Server.Configuration.Web.OpenApi.DefaultDefinitionTag + $ctx.Server.OpenAPI = Initialize-PodeOpenApiTable -DefaultDefinitionTag $ctx.Server.Web.OpenApi.DefaultDefinitionTag # server metrics $ctx.Metrics = @{ @@ -934,6 +934,13 @@ function Set-PodeWebConfiguration { Compression = @{ Enabled = [bool]$Configuration.Compression.Enable } + OpenApi = @{ + DefaultDefinitionTag = [string](Protect-PodeValue -Value $Configuration.OpenApi.DefaultDefinitionTag -Default 'default') + } + } + + if ($Configuration.OpenApi -and $Configuration.OpenApi.ContainsKey('UsePodeYamlInternal')) { + $Context.Server.Web.OpenApi.UsePodeYamlInternal = $Configuration.OpenApi.UsePodeYamlInternal } # setup content type route patterns for forced content types diff --git a/src/Private/OpenApi.ps1 b/src/Private/OpenApi.ps1 index ada70c012..c351bdf4f 100644 --- a/src/Private/OpenApi.ps1 +++ b/src/Private/OpenApi.ps1 @@ -1284,22 +1284,15 @@ This is an internal function and may change in future releases of Pode. function Initialize-PodeOpenApiTable { param( [string] - $DefaultDefinitionTag = $null + $DefaultDefinitionTag = 'default' ) # Initialization of the OpenAPI table with default settings $OpenAPI = @{ DefinitionTagSelectionStack = New-Object 'System.Collections.Generic.Stack[System.Object]' } - # Set the default definition tag - if ([string]::IsNullOrEmpty($DefaultDefinitionTag)) { - $OpenAPI['DefaultDefinitionTag'] = 'default' - } - else { - $OpenAPI['DefaultDefinitionTag'] = $DefaultDefinitionTag - } # Set the currently selected definition tag - $OpenAPI['SelectedDefinitionTag'] = $OpenAPI['DefaultDefinitionTag'] + $OpenAPI['SelectedDefinitionTag'] = $DefaultDefinitionTag # Initialize the Definitions dictionary with a base OpenAPI object for the selected definition tag $OpenAPI['Definitions'] = @{ $OpenAPI['SelectedDefinitionTag'] = Get-PodeOABaseObject } diff --git a/src/Public/OpenApi.ps1 b/src/Public/OpenApi.ps1 index 6482621f3..1238b6341 100644 --- a/src/Public/OpenApi.ps1 +++ b/src/Public/OpenApi.ps1 @@ -183,7 +183,7 @@ function Enable-PodeOpenApi { } Write-PodeHost -ForegroundColor Yellow "WARNING: Title, Version, and Description on 'Enable-PodeOpenApi' are deprecated. Please use 'Add-PodeOAInfo' instead." } - if ( $DefinitionTag -ine $PodeContext.Server.OpenAPI.DefaultDefinitionTag ) { + if ( $DefinitionTag -ine $PodeContext.Server.Web.OpenApi.DefaultDefinitionTag) { $PodeContext.Server.OpenAPI.Definitions[$DefinitionTag] = Get-PodeOABaseObject } $PodeContext.Server.OpenAPI.Definitions[$DefinitionTag].hiddenComponents.enableMinimalDefinitions = !$DisableMinimalDefinitions.IsPresent @@ -978,7 +978,7 @@ function Test-PodeOAJsonSchemaCompliance { } } else { - $DefinitionTag = $PodeContext.Server.OpenAPI.DefaultDefinitionTag + $DefinitionTag = $PodeContext.Server.Web.OpenApi.DefaultDefinitionTag } if ($Json -isnot [string]) { @@ -3186,9 +3186,6 @@ New-PodeOAServerEndpoint -Url 'https://myserver.io/api' -Description 'My test se .EXAMPLE New-PodeOAServerEndpoint -Url '/api' -Description 'My local server' - - -} #> function New-PodeOAServerEndpoint { param ( @@ -3226,8 +3223,6 @@ function New-PodeOAServerEndpoint { } } - - <# .SYNOPSIS Sets metadate for the supplied route. @@ -3303,7 +3298,6 @@ function Add-PodeOAWebhook { } } - <# .SYNOPSIS Select a group of OpenAPI Definions for modification. @@ -3345,15 +3339,13 @@ function Select-PodeOADefinition { [Parameter(Mandatory = $true)] [scriptblock] $Scriptblock - - ) if (Test-PodeIsEmpty $Scriptblock) { throw 'No scriptblock for -Scriptblock passed' } if (Test-PodeIsEmpty -Value $Tag) { - $Tag = $PodeContext.Server.OpenAPI.DefaultDefinitionTag + $Tag = $PodeContext.Server.Web.OpenApi.DefaultDefinitionTag } else { $Tag = Test-PodeOADefinitionTag -Tag $Tag @@ -3369,10 +3361,72 @@ function Select-PodeOADefinition { } +<# +.SYNOPSIS +Renames an existing OpenAPI definition tag in Pode. + +.DESCRIPTION +This function renames an existing OpenAPI definition tag to a new tag name. +If the specified tag is the default definition tag, it updates the default tag as well. +It ensures that the new tag name does not already exist and that the function is not used within a Select-PodeOADefinition ScriptBlock. + +.PARAMETER Tag +The current tag name of the OpenAPI definition. If not specified, the default definition tag is used. + +.PARAMETER NewTag +The new tag name for the OpenAPI definition. This parameter is mandatory. +.EXAMPLES +# Example 1: Rename a specific OpenAPI definition tag +Rename-PodeOADefinitionTagName -Tag 'oldTag' -NewTag 'newTag' +# Example 2: Rename the default OpenAPI definition tag +Rename-PodeOADefinitionTagName -NewTag 'newDefaultTag' +.NOTES +This function will throw an error if: +- It is used inside a Select-PodeOADefinition ScriptBlock. +- The new tag name already exists. +- The current tag name does not exist. +#> +function Rename-PodeOADefinitionTagName { + param ( + [Parameter(Mandatory = $false)] + [string]$Tag, + [Parameter(Mandatory = $true)] + [string]$NewTag + ) + + # Check if the function is being used inside a Select-PodeOADefinition ScriptBlock + if ($PodeContext.Server.OpenApi.DefinitionTagSelectionStack.Count -gt 0) { + throw "Rename-PodeOADefinitionTagName cannot be used inside a Select-PodeOADefinition 'ScriptBlock'" + } + + # Check if the new tag name already exists in the OpenAPI definitions + if ($PodeContext.Server.OpenAPI.Definitions.ContainsKey($NewTag)) { + throw "OpenAPI definition named $NewTag already exist." + } + + # If the Tag parameter is null or whitespace, use the default definition tag + if ([string]::IsNullOrWhiteSpace($Tag)) { + $Tag = $PodeContext.Server.Web.OpenApi.DefaultDefinitionTag + $PodeContext.Server.Web.OpenApi.DefaultDefinitionTag = $NewTag # Update the default definition tag + } + else { + # Test if the specified tag exists in the OpenAPI definitions + Test-PodeOADefinitionTag -Tag $Tag + } + + # Rename the definition tag in the OpenAPI definitions + $PodeContext.Server.OpenAPI.Definitions[$NewTag] = $PodeContext.Server.OpenAPI.Definitions[$Tag] + $PodeContext.Server.OpenAPI.Definitions.Remove($Tag) + + # Update the selected definition tag if it matches the old tag + if ($PodeContext.Server.OpenAPI.SelectedDefinitionTag -eq $Tag) { + $PodeContext.Server.OpenAPI.SelectedDefinitionTag = $NewTag + } +} diff --git a/tests/unit/OpenApi.Tests.ps1 b/tests/unit/OpenApi.Tests.ps1 index a9ceced07..ec0e042e7 100644 --- a/tests/unit/OpenApi.Tests.ps1 +++ b/tests/unit/OpenApi.Tests.ps1 @@ -3034,6 +3034,75 @@ Describe 'OpenApi' { } } + Describe 'Rename-PodeOADefinitionTagName' { + # Mocking the PodeContext to simulate the environment + BeforeEach { + $PodeContext = @{ + Server = @{ + OpenAPI = @{ + Definitions = @{ + 'oldTag' = @{ + # Mock definition details + Description = 'Old tag description' + } + } + SelectedDefinitionTag = 'oldTag' + DefinitionTagSelectionStack = [System.Collections.Stack]@() + } + Web = @{ + OpenApi = @{ + DefaultDefinitionTag = 'oldTag' + } + } + } + } + } + + # Test case: Renaming a specific tag + It 'Renames a specific OpenAPI definition tag' { + Rename-PodeOADefinitionTagName -Tag 'oldTag' -NewTag 'newTag' + + # Check if the new tag exists + $PodeContext.Server.OpenAPI.Definitions.ContainsKey('newTag') | Should -BeTrue + # Check if the old tag is removed + $PodeContext.Server.OpenAPI.Definitions.ContainsKey('oldTag') | Should -BeFalse + # Check if the selected definition tag is updated + $PodeContext.Server.OpenAPI.SelectedDefinitionTag | Should -Be 'newTag' + } + + # Test case: Renaming the default tag + It 'Renames the default OpenAPI definition tag when Tag parameter is not specified' { + Rename-PodeOADefinitionTagName -NewTag 'newDefaultTag' + + # Check if the new default tag is set + $PodeContext.Server.Web.OpenApi.DefaultDefinitionTag | Should -Be 'newDefaultTag' + # Check if the new tag exists + $PodeContext.Server.OpenAPI.Definitions.ContainsKey('newDefaultTag') | Should -BeTrue + # Check if the old tag is removed + $PodeContext.Server.OpenAPI.Definitions.ContainsKey('oldTag') | Should -BeFalse + } + + # Test case: Error when new tag already exists + It 'Throws an error when the new tag name already exists' { + $PodeContext.Server.OpenAPI.Definitions['existingTag'] = @{ + # Mock definition details + Description = 'Existing tag description' + } + + { Rename-PodeOADefinitionTagName -Tag 'oldTag' -NewTag 'existingTag' } | Should -Throw 'OpenAPI definition named existingTag already exist.' + } + + # Test case: Error when used inside Select-PodeOADefinition ScriptBlock + It 'Throws an error when used inside a Select-PodeOADefinition ScriptBlock' { + $PodeContext.Server.OpenApi.DefinitionTagSelectionStack.Push('dummy') + + { Rename-PodeOADefinitionTagName -Tag 'oldTag' -NewTag 'newTag' } | Should -Throw "Rename-PodeOADefinitionTagName cannot be used inside a Select-PodeOADefinition 'ScriptBlock'" + + # Clear the stack after test + $PodeContext.Server.OpenApi.DefinitionTagSelectionStack.Clear() + } + } + Context 'Pet Object example' { diff --git a/tests/unit/PrivateOpenApi.Tests.ps1 b/tests/unit/PrivateOpenApi.Tests.ps1 index c9b1c4a89..caf54faf5 100644 --- a/tests/unit/PrivateOpenApi.Tests.ps1 +++ b/tests/unit/PrivateOpenApi.Tests.ps1 @@ -13,11 +13,11 @@ Describe 'PrivateOpenApi' { function GetPodeContext { return @{ Server = @{ - Security = @{ + Security = @{ autoheaders = $false } - Authentications=@{} - OpenAPI = @{ + Authentications = @{} + OpenAPI = @{ SelectedDefinitionTag = 'default' Definitions = @{ default = Get-PodeOABaseObject @@ -287,32 +287,32 @@ Describe 'PrivateOpenApi' { } - Describe "Set-PodeOAAuth Tests" { + Describe 'Set-PodeOAAuth Tests' { BeforeAll { # Mock Test-PodeAuthExists to simulate authentication method existence Mock Test-PodeAuthExists { return $true } } - It "Applies multiple authentication methods to a route" { + It 'Applies multiple authentication methods to a route' { $route = @{ OpenApi = @{} } { Set-PodeOAAuth -Route @($route) -Name @('BasicAuth', 'ApiKeyAuth') } | Should -Not -Throw $route.OpenApi.Authentication.Count | Should -Be 2 } - It "Throws an exception for non-existent authentication method" { + It 'Throws an exception for non-existent authentication method' { Mock Test-PodeAuthExists { return $false } $route = @{ OpenApi = @{} } { Set-PodeOAAuth -Route @($route) -Name 'InvalidAuth' } | Should -Throw } - It "Allows anonymous access" { + It 'Allows anonymous access' { $route = @{ OpenApi = @{ Authentication = @{} } } { Set-PodeOAAuth -Route @($route) -Name 'BasicAuth' -AllowAnon } | Should -Not -Throw $route.OpenApi.Authentication.keys -contains '%_allowanon_%' | Should -Be $true $route.OpenApi.Authentication['%_allowanon_%'] | Should -BeNullOrEmpty } - It "Applies both authenticated and anonymous access to a route" { + It 'Applies both authenticated and anonymous access to a route' { $route = @{ OpenApi = @{} } { Set-PodeOAAuth -Route @($route) -Name @('BasicAuth') -AllowAnon } | Should -Not -Throw $route.OpenApi.Authentication.Count | Should -Be 2 @@ -321,8 +321,8 @@ Describe 'PrivateOpenApi' { } } - Describe "Get-PodeOABaseObject Tests" { - It "Returns the correct base OpenAPI object structure" { + Describe 'Get-PodeOABaseObject Tests' { + It 'Returns the correct base OpenAPI object structure' { $baseObject = Get-PodeOABaseObject $baseObject | Should -BeOfType [hashtable] @@ -335,30 +335,27 @@ Describe 'PrivateOpenApi' { } } - Describe "Initialize-PodeOpenApiTable Tests" { - It "Initializes OpenAPI table with default settings" { + Describe 'Initialize-PodeOpenApiTable Tests' { + It 'Initializes OpenAPI table with default settings' { $openApiTable = Initialize-PodeOpenApiTable $openApiTable | Should -BeOfType [hashtable] - $openApiTable.DefinitionTagSelectionStack -is [System.Collections.Generic.Stack[System.Object]] | Should -BeTrue - $openApiTable.DefaultDefinitionTag | Should -Be "default" - $openApiTable.SelectedDefinitionTag | Should -Be "default" + $openApiTable.DefinitionTagSelectionStack -is [System.Collections.Generic.Stack[System.Object]] | Should -BeTrue + $openApiTable.SelectedDefinitionTag | Should -Be 'default' $openApiTable.Definitions | Should -BeOfType [hashtable] - $openApiTable.Definitions["default"] | Should -BeOfType [hashtable] + $openApiTable.Definitions['default'] | Should -BeOfType [hashtable] } - It "Initializes OpenAPI table with custom definition tag" { - $customTag = "api-v1" + It 'Initializes OpenAPI table with custom definition tag' { + $customTag = 'api-v1' $openApiTable = Initialize-PodeOpenApiTable -DefaultDefinitionTag $customTag - - $openApiTable.DefaultDefinitionTag | Should -Be $customTag $openApiTable.SelectedDefinitionTag | Should -Be $customTag $openApiTable.Definitions | Should -BeOfType [hashtable] $openApiTable.Definitions[$customTag] | Should -BeOfType [hashtable] } } - Describe "ConvertTo-PodeOASchemaObjectProperty Tests" { + Describe 'ConvertTo-PodeOASchemaObjectProperty Tests' { BeforeAll { # Mock ConvertTo-PodeOASchemaProperty to simulate its behavior Mock ConvertTo-PodeOASchemaProperty { return @{ type = $_.type; processed = $true } } @@ -366,57 +363,57 @@ Describe 'PrivateOpenApi' { It "Converts a list of properties excluding 'allOf', 'oneOf', 'anyOf'" { $properties = @( - @{ name = "prop1"; type = "string" }, - @{ name = "prop2"; type = "integer" }, - @{ name = "prop3"; type = "allOf" } + @{ name = 'prop1'; type = 'string' }, + @{ name = 'prop2'; type = 'integer' }, + @{ name = 'prop3'; type = 'allOf' } ) - $result = ConvertTo-PodeOASchemaObjectProperty -Properties $properties -DefinitionTag "myTag" + $result = ConvertTo-PodeOASchemaObjectProperty -Properties $properties -DefinitionTag 'myTag' $result.Count | Should -Be 2 - $result["prop1"].processed | Should -Be $true - $result["prop2"].processed | Should -Be $true - $result.ContainsKey("prop3") | Should -Be $false + $result['prop1'].processed | Should -Be $true + $result['prop2'].processed | Should -Be $true + $result.ContainsKey('prop3') | Should -Be $false } - It "Forms valid schema object for non-excluded properties" { + It 'Forms valid schema object for non-excluded properties' { $properties = @( - @{ name = "prop1"; type = "string" } + @{ name = 'prop1'; type = 'string' } ) - $result = ConvertTo-PodeOASchemaObjectProperty -Properties $properties -DefinitionTag "myTag" + $result = ConvertTo-PodeOASchemaObjectProperty -Properties $properties -DefinitionTag 'myTag' $result.Count | Should -Be 1 - $result["prop1"].type | Should -Be "string" - $result["prop1"].processed | Should -Be $true + $result['prop1'].type | Should -Be 'string' + $result['prop1'].processed | Should -Be $true } } - Describe "ConvertTo-PodeOAObjectSchema Tests" { + Describe 'ConvertTo-PodeOAObjectSchema Tests' { Mock ConvertTo-PodeOASchemaProperty { return @{ mockedResult = $true } } Mock Test-PodeOAComponentInternal { return $true } Mock Test-PodeOAVersion { param($Version) $Version -le 3.0 } - It "Converts valid content to schema object" { + It 'Converts valid content to schema object' { $content = @{ - "application/json" = @{ type = "String" } + 'application/json' = @{ type = 'String' } } - $result = ConvertTo-PodeOAObjectSchema -Content $content -DefinitionTag "myTag" + $result = ConvertTo-PodeOAObjectSchema -Content $content -DefinitionTag 'myTag' - $result.ContainsKey("application/json") | Should -Be $true - $result["application/json"].schema.type | Should -Be 'string' + $result.ContainsKey('application/json') | Should -Be $true + $result['application/json'].schema.type | Should -Be 'string' } - It "Handles array structures correctly" { + It 'Handles array structures correctly' { $content = @{ - "application/json" = @{ - __array = $true - __content = @{ type = "String" } + 'application/json' = @{ + __array = $true + __content = @{ type = 'String' } } } - $result = ConvertTo-PodeOAObjectSchema -Content $content -DefinitionTag "myTag" + $result = ConvertTo-PodeOAObjectSchema -Content $content -DefinitionTag 'myTag' - $result["application/json"].schema.type | Should -Be "array" - $result["application/json"].schema.Items.type | Should -Be 'string' + $result['application/json'].schema.type | Should -Be 'array' + $result['application/json'].schema.Items.type | Should -Be 'string' } } From a9af2601808b9f1aa6510eb67a3043444fa93763 Mon Sep 17 00:00:00 2001 From: mdaneri Date: Mon, 24 Jun 2024 09:42:36 -0700 Subject: [PATCH 02/10] fix the header --- src/Public/OpenApi.ps1 | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/Public/OpenApi.ps1 b/src/Public/OpenApi.ps1 index 1238b6341..efc381ad0 100644 --- a/src/Public/OpenApi.ps1 +++ b/src/Public/OpenApi.ps1 @@ -3376,19 +3376,21 @@ The current tag name of the OpenAPI definition. If not specified, the default de .PARAMETER NewTag The new tag name for the OpenAPI definition. This parameter is mandatory. -.EXAMPLES -# Example 1: Rename a specific OpenAPI definition tag +.EXAMPLE Rename-PodeOADefinitionTagName -Tag 'oldTag' -NewTag 'newTag' -# Example 2: Rename the default OpenAPI definition tag +Rename a specific OpenAPI definition tag + +.EXAMPLE Rename-PodeOADefinitionTagName -NewTag 'newDefaultTag' +Rename the default OpenAPI definition tag + .NOTES This function will throw an error if: - It is used inside a Select-PodeOADefinition ScriptBlock. - The new tag name already exists. - The current tag name does not exist. - #> function Rename-PodeOADefinitionTagName { param ( From d854cb288010dae2052824e14e126e35cb2eb2d4 Mon Sep 17 00:00:00 2001 From: mdaneri Date: Tue, 2 Jul 2024 18:47:10 -0700 Subject: [PATCH 03/10] fix languages --- src/Locales/ar/Pode.psd1 | 3 ++- src/Locales/de/Pode.psd1 | 5 +++-- src/Locales/en-us/Pode.psd1 | 5 +++-- src/Locales/en/Pode.psd1 | 2 ++ src/Locales/es/Pode.psd1 | 2 ++ src/Locales/fr/Pode.psd1 | 2 ++ src/Locales/it/Pode.psd1 | 5 +++-- src/Locales/ja/Pode.psd1 | 3 ++- src/Locales/ko/Pode.psd1 | 3 ++- src/Locales/pl/Pode.psd1 | 3 ++- src/Locales/pt/Pode.psd1 | 5 +++-- src/Locales/zh/Pode.psd1 | 2 ++ src/Public/OpenApi.ps1 | 4 ++-- tests/unit/OpenApi.Tests.ps1 | 4 ++-- tests/unit/PrivateOpenApi.Tests.ps1 | 1 - 15 files changed, 32 insertions(+), 17 deletions(-) diff --git a/src/Locales/ar/Pode.psd1 b/src/Locales/ar/Pode.psd1 index 274731000..252dca504 100644 --- a/src/Locales/ar/Pode.psd1 +++ b/src/Locales/ar/Pode.psd1 @@ -283,5 +283,6 @@ adModuleWindowsOnlyExceptionMessage = 'وحدة Active Directory متاحة فقط على نظام Windows.' requestLoggingAlreadyEnabledExceptionMessage = 'تم تمكين تسجيل الطلبات بالفعل.' invalidAccessControlMaxAgeDurationExceptionMessage = 'مدة Access-Control-Max-Age غير صالحة المقدمة: {0}. يجب أن تكون أكبر من 0.' + openApiDefinitionAlreadyExistsExceptionMessage = 'تعريف OpenAPI باسم {0} موجود بالفعل.' + renamePodeOADefinitionTagNameExceptionMessage = "لا يمكن استخدام Rename-PodeOADefinitionTagName داخل Select-PodeOADefinition 'ScriptBlock'." } - diff --git a/src/Locales/de/Pode.psd1 b/src/Locales/de/Pode.psd1 index 6ae1aaa24..2a11af441 100644 --- a/src/Locales/de/Pode.psd1 +++ b/src/Locales/de/Pode.psd1 @@ -283,5 +283,6 @@ adModuleWindowsOnlyExceptionMessage = 'Active Directory-Modul nur unter Windows verfügbar.' requestLoggingAlreadyEnabledExceptionMessage = 'Die Anforderungsprotokollierung wurde bereits aktiviert.' invalidAccessControlMaxAgeDurationExceptionMessage = 'Ungültige Access-Control-Max-Age-Dauer angegeben: {0}. Sollte größer als 0 sein.' -} - + openApiDefinitionAlreadyExistsExceptionMessage = 'Die OpenAPI-Definition mit dem Namen {0} existiert bereits.' + renamePodeOADefinitionTagNameExceptionMessage = "Rename-PodeOADefinitionTagName kann nicht innerhalb eines 'ScriptBlock' von Select-PodeOADefinition verwendet werden." +} \ No newline at end of file diff --git a/src/Locales/en-us/Pode.psd1 b/src/Locales/en-us/Pode.psd1 index b3cde218b..e8a1d57ae 100644 --- a/src/Locales/en-us/Pode.psd1 +++ b/src/Locales/en-us/Pode.psd1 @@ -283,5 +283,6 @@ adModuleWindowsOnlyExceptionMessage = 'Active Directory module only available on Windows OS.' requestLoggingAlreadyEnabledExceptionMessage = 'Request Logging has already been enabled.' invalidAccessControlMaxAgeDurationExceptionMessage = 'Invalid Access-Control-Max-Age duration supplied: {0}. Should be greater than 0.' -} - + openApiDefinitionAlreadyExistsExceptionMessage = 'OpenAPI definition named {0} already exists.' + renamePodeOADefinitionTagNameExceptionMessage = "Rename-PodeOADefinitionTagName cannot be used inside a Select-PodeOADefinition 'ScriptBlock'." +} \ No newline at end of file diff --git a/src/Locales/en/Pode.psd1 b/src/Locales/en/Pode.psd1 index 04eff1509..079d5f852 100644 --- a/src/Locales/en/Pode.psd1 +++ b/src/Locales/en/Pode.psd1 @@ -283,5 +283,7 @@ adModuleWindowsOnlyExceptionMessage = 'Active Directory module only available on Windows OS.' requestLoggingAlreadyEnabledExceptionMessage = 'Request Logging has already been enabled.' invalidAccessControlMaxAgeDurationExceptionMessage = 'Invalid Access-Control-Max-Age duration supplied: {0}. Should be greater than 0.' + openApiDefinitionAlreadyExistsExceptionMessage = 'OpenAPI definition named {0} already exists.' + renamePodeOADefinitionTagNameExceptionMessage = "Rename-PodeOADefinitionTagName cannot be used inside a Select-PodeOADefinition 'ScriptBlock'." } diff --git a/src/Locales/es/Pode.psd1 b/src/Locales/es/Pode.psd1 index 4610ed29c..0ad047839 100644 --- a/src/Locales/es/Pode.psd1 +++ b/src/Locales/es/Pode.psd1 @@ -283,5 +283,7 @@ adModuleWindowsOnlyExceptionMessage = 'El módulo de Active Directory solo está disponible en Windows.' requestLoggingAlreadyEnabledExceptionMessage = 'El registro de solicitudes ya está habilitado.' invalidAccessControlMaxAgeDurationExceptionMessage = 'Duración inválida para Access-Control-Max-Age proporcionada: {0}. Debe ser mayor que 0.' + openApiDefinitionAlreadyExistsExceptionMessage = 'La definición de OpenAPI con el nombre {0} ya existe.' + renamePodeOADefinitionTagNameExceptionMessage = "Rename-PodeOADefinitionTagName no se puede usar dentro de un 'ScriptBlock' de Select-PodeOADefinition." } diff --git a/src/Locales/fr/Pode.psd1 b/src/Locales/fr/Pode.psd1 index c92181571..92dd448b7 100644 --- a/src/Locales/fr/Pode.psd1 +++ b/src/Locales/fr/Pode.psd1 @@ -283,5 +283,7 @@ adModuleWindowsOnlyExceptionMessage = 'Le module Active Directory est uniquement disponible sur Windows.' requestLoggingAlreadyEnabledExceptionMessage = 'La journalisation des requêtes est déjà activée.' invalidAccessControlMaxAgeDurationExceptionMessage = 'Durée Access-Control-Max-Age invalide fournie : {0}. Doit être supérieure à 0.' + openApiDefinitionAlreadyExistsExceptionMessage = 'La définition OpenAPI nommée {0} existe déjà.' + renamePodeOADefinitionTagNameExceptionMessage = "Rename-PodeOADefinitionTagName ne peut pas être utilisé à l'intérieur d'un 'ScriptBlock' de Select-PodeOADefinition." } diff --git a/src/Locales/it/Pode.psd1 b/src/Locales/it/Pode.psd1 index 239b1a9e9..7a865dce9 100644 --- a/src/Locales/it/Pode.psd1 +++ b/src/Locales/it/Pode.psd1 @@ -283,5 +283,6 @@ adModuleWindowsOnlyExceptionMessage = 'Il modulo Active Directory è disponibile solo su Windows OS.' requestLoggingAlreadyEnabledExceptionMessage = 'La registrazione delle richieste è già abilitata.' invalidAccessControlMaxAgeDurationExceptionMessage = 'Durata non valida fornita per Access-Control-Max-Age: {0}. Deve essere maggiore di 0.' -} - + openApiDefinitionAlreadyExistsExceptionMessage = 'La definizione OpenAPI denominata {0} esiste già.' + renamePodeOADefinitionTagNameExceptionMessage = "Rename-PodeOADefinitionTagName non può essere utilizzato all'interno di un 'ScriptBlock' di Select-PodeOADefinition." +} \ No newline at end of file diff --git a/src/Locales/ja/Pode.psd1 b/src/Locales/ja/Pode.psd1 index 66543eb99..f20c56401 100644 --- a/src/Locales/ja/Pode.psd1 +++ b/src/Locales/ja/Pode.psd1 @@ -283,5 +283,6 @@ adModuleWindowsOnlyExceptionMessage = 'Active DirectoryモジュールはWindowsでのみ利用可能です。' requestLoggingAlreadyEnabledExceptionMessage = 'リクエストロギングは既に有効になっています。' invalidAccessControlMaxAgeDurationExceptionMessage = '無効な Access-Control-Max-Age 期間が提供されました:{0}。0 より大きくする必要があります。' + openApiDefinitionAlreadyExistsExceptionMessage = '名前が {0} の OpenAPI 定義は既に存在します。' + renamePodeOADefinitionTagNameExceptionMessage = "Rename-PodeOADefinitionTagName は Select-PodeOADefinition 'ScriptBlock' 内で使用できません。" } - diff --git a/src/Locales/ko/Pode.psd1 b/src/Locales/ko/Pode.psd1 index 82f96b665..c718999f0 100644 --- a/src/Locales/ko/Pode.psd1 +++ b/src/Locales/ko/Pode.psd1 @@ -283,5 +283,6 @@ adModuleWindowsOnlyExceptionMessage = 'Active Directory 모듈은 Windows에서만 사용할 수 있습니다.' requestLoggingAlreadyEnabledExceptionMessage = '요청 로깅이 이미 활성화되었습니다.' invalidAccessControlMaxAgeDurationExceptionMessage = '잘못된 Access-Control-Max-Age 기간이 제공되었습니다: {0}. 0보다 커야 합니다.' + openApiDefinitionAlreadyExistsExceptionMessage = '이름이 {0}인 OpenAPI 정의가 이미 존재합니다.' + renamePodeOADefinitionTagNameExceptionMessage = "Rename-PodeOADefinitionTagName은 Select-PodeOADefinition 'ScriptBlock' 내에서 사용할 수 없습니다." } - diff --git a/src/Locales/pl/Pode.psd1 b/src/Locales/pl/Pode.psd1 index 17cbabd57..5f11f96f1 100644 --- a/src/Locales/pl/Pode.psd1 +++ b/src/Locales/pl/Pode.psd1 @@ -283,5 +283,6 @@ adModuleWindowsOnlyExceptionMessage = 'Moduł Active Directory jest dostępny tylko w systemie Windows.' requestLoggingAlreadyEnabledExceptionMessage = 'Rejestrowanie żądań jest już włączone.' invalidAccessControlMaxAgeDurationExceptionMessage = 'Podano nieprawidłowy czas trwania Access-Control-Max-Age: {0}. Powinien być większy niż 0.' + openApiDefinitionAlreadyExistsExceptionMessage = 'Definicja OpenAPI o nazwie {0} już istnieje.' + renamePodeOADefinitionTagNameExceptionMessage = "Rename-PodeOADefinitionTagName nie może być używany wewnątrz 'ScriptBlock' Select-PodeOADefinition." } - diff --git a/src/Locales/pt/Pode.psd1 b/src/Locales/pt/Pode.psd1 index a3df34515..e8c9feb0e 100644 --- a/src/Locales/pt/Pode.psd1 +++ b/src/Locales/pt/Pode.psd1 @@ -283,5 +283,6 @@ adModuleWindowsOnlyExceptionMessage = 'O módulo Active Directory está disponível apenas no Windows.' requestLoggingAlreadyEnabledExceptionMessage = 'O registro de solicitações já está habilitado.' invalidAccessControlMaxAgeDurationExceptionMessage = 'Duração inválida fornecida para Access-Control-Max-Age: {0}. Deve ser maior que 0.' -} - + openApiDefinitionAlreadyExistsExceptionMessage = 'A definição OpenAPI com o nome {0} já existe.' + renamePodeOADefinitionTagNameExceptionMessage = "Rename-PodeOADefinitionTagName não pode ser usado dentro de um 'ScriptBlock' Select-PodeOADefinition." +} \ No newline at end of file diff --git a/src/Locales/zh/Pode.psd1 b/src/Locales/zh/Pode.psd1 index 6bc71fb10..0b8c012d6 100644 --- a/src/Locales/zh/Pode.psd1 +++ b/src/Locales/zh/Pode.psd1 @@ -283,5 +283,7 @@ adModuleWindowsOnlyExceptionMessage = '仅支持 Windows 的 Active Directory 模块。' requestLoggingAlreadyEnabledExceptionMessage = '请求日志记录已启用。' invalidAccessControlMaxAgeDurationExceptionMessage = '提供的 Access-Control-Max-Age 时长无效:{0}。应大于 0。' + openApiDefinitionAlreadyExistsExceptionMessage = '名为 {0} 的 OpenAPI 定义已存在。' + renamePodeOADefinitionTagNameExceptionMessage = "Rename-PodeOADefinitionTagName 不能在 Select-PodeOADefinition 'ScriptBlock' 内使用。" } diff --git a/src/Public/OpenApi.ps1 b/src/Public/OpenApi.ps1 index 36024d78b..2fa9c6b18 100644 --- a/src/Public/OpenApi.ps1 +++ b/src/Public/OpenApi.ps1 @@ -3456,12 +3456,12 @@ function Rename-PodeOADefinitionTagName { # Check if the function is being used inside a Select-PodeOADefinition ScriptBlock if ($PodeContext.Server.OpenApi.DefinitionTagSelectionStack.Count -gt 0) { - throw "Rename-PodeOADefinitionTagName cannot be used inside a Select-PodeOADefinition 'ScriptBlock'" + throw ($PodeLocale.renamePodeOADefinitionTagNameExceptionMessage) } # Check if the new tag name already exists in the OpenAPI definitions if ($PodeContext.Server.OpenAPI.Definitions.ContainsKey($NewTag)) { - throw "OpenAPI definition named $NewTag already exist." + throw ($PodeLocale.openApiDefinitionAlreadyExistsExceptionMessage -f $NewTag ) } # If the Tag parameter is null or whitespace, use the default definition tag diff --git a/tests/unit/OpenApi.Tests.ps1 b/tests/unit/OpenApi.Tests.ps1 index deaa86fc1..2c06adef8 100644 --- a/tests/unit/OpenApi.Tests.ps1 +++ b/tests/unit/OpenApi.Tests.ps1 @@ -3090,14 +3090,14 @@ Describe 'OpenApi' { Description = 'Existing tag description' } - { Rename-PodeOADefinitionTagName -Tag 'oldTag' -NewTag 'existingTag' } | Should -Throw 'OpenAPI definition named existingTag already exist.' + { Rename-PodeOADefinitionTagName -Tag 'oldTag' -NewTag 'existingTag' } | Should -Throw -ExpectedMessage ($PodeLocale.openApiDefinitionAlreadyExistsExceptionMessage -f 'existingTag') } # Test case: Error when used inside Select-PodeOADefinition ScriptBlock It 'Throws an error when used inside a Select-PodeOADefinition ScriptBlock' { $PodeContext.Server.OpenApi.DefinitionTagSelectionStack.Push('dummy') - { Rename-PodeOADefinitionTagName -Tag 'oldTag' -NewTag 'newTag' } | Should -Throw "Rename-PodeOADefinitionTagName cannot be used inside a Select-PodeOADefinition 'ScriptBlock'" + { Rename-PodeOADefinitionTagName -Tag 'oldTag' -NewTag 'newTag' } | Should -Throw -ExpectedMessage ($PodeLocale.renamePodeOADefinitionTagNameExceptionMessage) # Clear the stack after test $PodeContext.Server.OpenApi.DefinitionTagSelectionStack.Clear() diff --git a/tests/unit/PrivateOpenApi.Tests.ps1 b/tests/unit/PrivateOpenApi.Tests.ps1 index b79b09608..ff07225a1 100644 --- a/tests/unit/PrivateOpenApi.Tests.ps1 +++ b/tests/unit/PrivateOpenApi.Tests.ps1 @@ -342,7 +342,6 @@ Describe 'PrivateOpenApi' { $openApiTable | Should -BeOfType [hashtable] $openApiTable.DefinitionTagSelectionStack -is [System.Collections.Generic.Stack[System.Object]] | Should -BeTrue - $openApiTable.DefaultDefinitionTag | Should -Be 'default' $openApiTable.SelectedDefinitionTag | Should -Be 'default' $openApiTable.Definitions | Should -BeOfType [hashtable] $openApiTable.Definitions['default'] | Should -BeOfType [hashtable] From 4ce49cc1794bb7a2379076de9e313605fc8073f3 Mon Sep 17 00:00:00 2001 From: mdaneri Date: Mon, 8 Jul 2024 17:25:02 -0700 Subject: [PATCH 04/10] remove redundant code --- src/Private/Context.ps1 | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/Private/Context.ps1 b/src/Private/Context.ps1 index b908987e6..3e3395551 100644 --- a/src/Private/Context.ps1 +++ b/src/Private/Context.ps1 @@ -945,12 +945,6 @@ function Set-PodeWebConfiguration { $Context.Server.Web.OpenApi.UsePodeYamlInternal = $Configuration.OpenApi.UsePodeYamlInternal } - if ($Configuration.OpenApi -and $Configuration.OpenApi.ContainsKey('UsePodeYamlInternal')) { - $Context.Server.Web.OpenApi = @{ - UsePodeYamlInternal = $Configuration.OpenApi.UsePodeYamlInternal - } - } - # setup content type route patterns for forced content types $Configuration.ContentType.Routes.Keys | Where-Object { ![string]::IsNullOrWhiteSpace($_) } | ForEach-Object { $_type = $Configuration.ContentType.Routes[$_] From 1bed3e39fc4bf8574768da377c4a6ad04ca09323 Mon Sep 17 00:00:00 2001 From: mdaneri Date: Mon, 8 Jul 2024 17:31:08 -0700 Subject: [PATCH 05/10] Update server.psd1 --- examples/server.psd1 | 3 +++ 1 file changed, 3 insertions(+) diff --git a/examples/server.psd1 b/examples/server.psd1 index 4d9b598b8..d1858842e 100644 --- a/examples/server.psd1 +++ b/examples/server.psd1 @@ -24,6 +24,9 @@ Compression = @{ Enable = $false } + OpenApi = @{ + UsePodeYamlInternal = $true + } } Server = @{ FileMonitor = @{ From 302296642bd992f3df05d4dbfa908183836e7c78 Mon Sep 17 00:00:00 2001 From: mdaneri Date: Mon, 8 Jul 2024 18:15:25 -0700 Subject: [PATCH 06/10] adding documentation --- docs/Tutorials/Routes/Overview.md | 200 +++++++++++++++++++++++++++++- 1 file changed, 198 insertions(+), 2 deletions(-) diff --git a/docs/Tutorials/Routes/Overview.md b/docs/Tutorials/Routes/Overview.md index 9fbcae868..320308821 100644 --- a/docs/Tutorials/Routes/Overview.md +++ b/docs/Tutorials/Routes/Overview.md @@ -43,6 +43,8 @@ You can add your routes straight into the [`Start-PodeServer`](../../../Function The following is an example of using data from a request's payload - ie, the data in the body of POST request. To retrieve values from the payload you can use the `.Data` property on the `$WebEvent` variable to a route's logic. +Alternatively, you can use the Get-PodeBody function to retrieve the body data. + Depending the the Content-Type supplied, Pode has inbuilt body-parsing logic for JSON, XML, CSV, and Form data. This example will get the `userId` and "find" user, returning the users data: @@ -76,9 +78,39 @@ Invoke-WebRequest -Uri 'http://localhost:8080/users' -Method Post -Body '{ "user !!! important On PowerShell 5 referencing JSON data on `$WebEvent.Data` must be done as `$WebEvent.Data.userId`. This also works in PowerShell 6+, but you can also use `$WebEvent.Data['userId']` on PowerShell 6+. +Alternatively, you can use the Get-PodeBody function to retrieve the body data. This function works similarly to the .Data property on $WebEvent and supports the same content types. + +Here is the same example using Get-PodeBody: + +```powershell +Start-PodeServer { + Add-PodeEndpoint -Address * -Port 8080 -Protocol Http + + Add-PodeRoute -Method Post -Path '/users' -ScriptBlock { + # get the body data + $body = Get-PodeBody + + # get the user + $user = Get-DummyUser -UserId $body.userId + + # return the user + Write-PodeJsonResponse -Value @{ + Username = $user.username + Age = $user.age + } + } +} +``` + ## Query Strings -The following is an example of using data from a request's query string. To retrieve values from the query string you can use the `.Query` property from the `$WebEvent` variable. This example will return a user based on the `userId` supplied: +The following is an example of using data from a request's payload - i.e., the data in the body of a POST request. To retrieve values from the payload, you can use the `Data` property on the `$WebEvent` variable in a route's logic. + +Alternatively, you can use the `Get-PodeBody` function to retrieve the body data. + +Depending on the Content-Type supplied, Pode has inbuilt body-parsing logic for JSON, XML, CSV, and Form data. + +This example will return a user based on the `userId` supplied: ```powershell Start-PodeServer { @@ -103,9 +135,37 @@ The following request will invoke the above route: Invoke-WebRequest -Uri 'http://localhost:8080/users?userId=12345' -Method Get ``` +Alternatively, you can use the Get-PodeQuery function to retrieve the query data. This function works similarly to the `Query` property on `$WebEvent`. + +Here is the same example using `Get-PodeQuery`: + +```powershell +Start-PodeServer { + Add-PodeEndpoint -Address * -Port 8080 -Protocol Http + + Add-PodeRoute -Method Get -Path '/users' -ScriptBlock { + # get the query data + $userId = Get-PodeQuery -Name 'userId' + + # get the user + $user = Get-DummyUser -UserId $userId + + # return the user + Write-PodeJsonResponse -Value @{ + Username = $user.username + Age = $user.age + } + } +} +``` + ## Parameters -The following is an example of using values supplied on a request's URL using parameters. To retrieve values that match a request's URL parameters you can use the `.Parameters` property from the `$WebEvent` variable. This example will get the `:userId` and "find" user, returning the users data: +The following is an example of using values supplied on a request's URL using parameters. To retrieve values that match a request's URL parameters, you can use the `Parameters` property from the `$WebEvent` variable. + +Alternatively, you can use the `Get-PodeParameter` function to retrieve the parameter data. + +This example will get the `:userId` and "find" user, returning the users data: ```powershell Start-PodeServer { @@ -130,6 +190,142 @@ The following request will invoke the above route: Invoke-WebRequest -Uri 'http://localhost:8080/users/12345' -Method Get ``` +Alternatively, you can use the Get-PodeParameter function to retrieve the parameter data. This function works similarly to the `Parameters` property on `$WebEvent`. + +Here is the same example using Get-PodeParameter: + +```powershell +Start-PodeServer { + Add-PodeEndpoint -Address * -Port 8080 -Protocol Http + + Add-PodeRoute -Method Get -Path '/users/:userId' -ScriptBlock { + # get the parameter data + $userId = Get-PodeParameter -Name 'userId' + + # get the user + $user = Get-DummyUser -UserId $userId + + # return the user + Write-PodeJsonResponse -Value @{ + Username = $user.username + Age = $user.age + } + } +} +``` + +## Headers + +The following is an example of using values supplied in a request's headers. To retrieve values from the headers, you can use the `Headers` property from the `$WebEvent.Request` variable. Alternatively, you can use the Get-PodeHeader function to retrieve the header data. + +This example will get the Authorization header and validate the token, returning a success message: + +```powershell +Start-PodeServer { + Add-PodeEndpoint -Address * -Port 8080 -Protocol Http + + Add-PodeRoute -Method Get -Path '/validate' -ScriptBlock { + # get the token + $token = $WebEvent.Request.Headers['Authorization'] + + # validate the token + $isValid = Test-PodeJwt -payload $token + + # return the result + Write-PodeJsonResponse -Value @{ + Success = $isValid + } + } +} +``` + +The following request will invoke the above route: + +```powershell +Invoke-WebRequest -Uri 'http://localhost:8080/validate' -Method Get -Headers @{ Authorization = 'Bearer some_token' } +``` + + +Alternatively, you can use the Get-PodeHeader function to retrieve the header data. This function works similarly to the `Headers` property on `$WebEvent.Request`. + +Here is the same example using Get-PodeHeader: + +```powershell +Start-PodeServer { + Add-PodeEndpoint -Address * -Port 8080 -Protocol Http + + Add-PodeRoute -Method Get -Path '/validate' -ScriptBlock { + # get the token + $token = Get-PodeHeader -Name 'Authorization' + + # validate the token + $isValid = Test-PodeJwt -payload $token + + # return the result + Write-PodeJsonResponse -Value @{ + Success = $isValid + } + } +} +``` + + +## Cookies + +The following is an example of using values supplied in a request's cookies. To retrieve values from the cookies, you can use the `Cookies` property from the `$WebEvent` variable. + +Alternatively, you can use the `Get-PodeCookie` function to retrieve the cookie data. + +This example will get the `SessionId` cookie and use it to authenticate the user, returning a success message: + +```powershell +Start-PodeServer { + Add-PodeEndpoint -Address * -Port 8080 -Protocol Http + + Add-PodeRoute -Method Get -Path '/authenticate' -ScriptBlock { + # get the session ID from the cookie + $sessionId = $WebEvent.Cookies['SessionId'] + + # authenticate the session + $isAuthenticated = Authenticate-Session -SessionId $sessionId + + # return the result + Write-PodeJsonResponse -Value @{ + Authenticated = $isAuthenticated + } + } +} +``` + +The following request will invoke the above route: + +```powershell +Invoke-WebRequest -Uri 'http://localhost:8080/authenticate' -Method Get -Headers @{ Cookie = 'SessionId=abc123' } +``` + +Alternatively, you can use the `Get-PodeCookie` function to retrieve the cookie data. This function works similarly to the `Cookies` property on `$WebEvent`. + +Here is the same example using `Get-PodeCookie`: + +```powershell +Start-PodeServer { + Add-PodeEndpoint -Address * -Port 8080 -Protocol Http + + Add-PodeRoute -Method Get -Path '/authenticate' -ScriptBlock { + # get the session ID from the cookie + $sessionId = Get-PodeCookie -Name 'SessionId' + + # authenticate the session + $isAuthenticated = Authenticate-Session -SessionId $sessionId + + # return the result + Write-PodeJsonResponse -Value @{ + Authenticated = $isAuthenticated + } + } +} +``` + ## Script from File You normally define a route's script using the `-ScriptBlock` parameter however, you can also reference a file with the required scriptblock using `-FilePath`. Using the `-FilePath` parameter will dot-source a scriptblock from the file, and set it as the route's script. From d6f5553ba27fcb2939f875a80cc6801fb31e0f28 Mon Sep 17 00:00:00 2001 From: mdaneri Date: Tue, 9 Jul 2024 14:25:40 -0700 Subject: [PATCH 07/10] Update Overview.md --- docs/Tutorials/Routes/Overview.md | 202 +----------------------------- 1 file changed, 3 insertions(+), 199 deletions(-) diff --git a/docs/Tutorials/Routes/Overview.md b/docs/Tutorials/Routes/Overview.md index 320308821..a9acd7efe 100644 --- a/docs/Tutorials/Routes/Overview.md +++ b/docs/Tutorials/Routes/Overview.md @@ -43,8 +43,6 @@ You can add your routes straight into the [`Start-PodeServer`](../../../Function The following is an example of using data from a request's payload - ie, the data in the body of POST request. To retrieve values from the payload you can use the `.Data` property on the `$WebEvent` variable to a route's logic. -Alternatively, you can use the Get-PodeBody function to retrieve the body data. - Depending the the Content-Type supplied, Pode has inbuilt body-parsing logic for JSON, XML, CSV, and Form data. This example will get the `userId` and "find" user, returning the users data: @@ -78,39 +76,9 @@ Invoke-WebRequest -Uri 'http://localhost:8080/users' -Method Post -Body '{ "user !!! important On PowerShell 5 referencing JSON data on `$WebEvent.Data` must be done as `$WebEvent.Data.userId`. This also works in PowerShell 6+, but you can also use `$WebEvent.Data['userId']` on PowerShell 6+. -Alternatively, you can use the Get-PodeBody function to retrieve the body data. This function works similarly to the .Data property on $WebEvent and supports the same content types. - -Here is the same example using Get-PodeBody: - -```powershell -Start-PodeServer { - Add-PodeEndpoint -Address * -Port 8080 -Protocol Http - - Add-PodeRoute -Method Post -Path '/users' -ScriptBlock { - # get the body data - $body = Get-PodeBody - - # get the user - $user = Get-DummyUser -UserId $body.userId - - # return the user - Write-PodeJsonResponse -Value @{ - Username = $user.username - Age = $user.age - } - } -} -``` - ## Query Strings -The following is an example of using data from a request's payload - i.e., the data in the body of a POST request. To retrieve values from the payload, you can use the `Data` property on the `$WebEvent` variable in a route's logic. - -Alternatively, you can use the `Get-PodeBody` function to retrieve the body data. - -Depending on the Content-Type supplied, Pode has inbuilt body-parsing logic for JSON, XML, CSV, and Form data. - -This example will return a user based on the `userId` supplied: +The following is an example of using data from a request's query string. To retrieve values from the query string you can use the `.Query` property from the `$WebEvent` variable. This example will return a user based on the `userId` supplied: ```powershell Start-PodeServer { @@ -135,37 +103,9 @@ The following request will invoke the above route: Invoke-WebRequest -Uri 'http://localhost:8080/users?userId=12345' -Method Get ``` -Alternatively, you can use the Get-PodeQuery function to retrieve the query data. This function works similarly to the `Query` property on `$WebEvent`. - -Here is the same example using `Get-PodeQuery`: - -```powershell -Start-PodeServer { - Add-PodeEndpoint -Address * -Port 8080 -Protocol Http - - Add-PodeRoute -Method Get -Path '/users' -ScriptBlock { - # get the query data - $userId = Get-PodeQuery -Name 'userId' - - # get the user - $user = Get-DummyUser -UserId $userId - - # return the user - Write-PodeJsonResponse -Value @{ - Username = $user.username - Age = $user.age - } - } -} -``` - ## Parameters -The following is an example of using values supplied on a request's URL using parameters. To retrieve values that match a request's URL parameters, you can use the `Parameters` property from the `$WebEvent` variable. - -Alternatively, you can use the `Get-PodeParameter` function to retrieve the parameter data. - -This example will get the `:userId` and "find" user, returning the users data: +The following is an example of using values supplied on a request's URL using parameters. To retrieve values that match a request's URL parameters you can use the `.Parameters` property from the `$WebEvent` variable. This example will get the `:userId` and "find" user, returning the users data: ```powershell Start-PodeServer { @@ -190,142 +130,6 @@ The following request will invoke the above route: Invoke-WebRequest -Uri 'http://localhost:8080/users/12345' -Method Get ``` -Alternatively, you can use the Get-PodeParameter function to retrieve the parameter data. This function works similarly to the `Parameters` property on `$WebEvent`. - -Here is the same example using Get-PodeParameter: - -```powershell -Start-PodeServer { - Add-PodeEndpoint -Address * -Port 8080 -Protocol Http - - Add-PodeRoute -Method Get -Path '/users/:userId' -ScriptBlock { - # get the parameter data - $userId = Get-PodeParameter -Name 'userId' - - # get the user - $user = Get-DummyUser -UserId $userId - - # return the user - Write-PodeJsonResponse -Value @{ - Username = $user.username - Age = $user.age - } - } -} -``` - -## Headers - -The following is an example of using values supplied in a request's headers. To retrieve values from the headers, you can use the `Headers` property from the `$WebEvent.Request` variable. Alternatively, you can use the Get-PodeHeader function to retrieve the header data. - -This example will get the Authorization header and validate the token, returning a success message: - -```powershell -Start-PodeServer { - Add-PodeEndpoint -Address * -Port 8080 -Protocol Http - - Add-PodeRoute -Method Get -Path '/validate' -ScriptBlock { - # get the token - $token = $WebEvent.Request.Headers['Authorization'] - - # validate the token - $isValid = Test-PodeJwt -payload $token - - # return the result - Write-PodeJsonResponse -Value @{ - Success = $isValid - } - } -} -``` - -The following request will invoke the above route: - -```powershell -Invoke-WebRequest -Uri 'http://localhost:8080/validate' -Method Get -Headers @{ Authorization = 'Bearer some_token' } -``` - - -Alternatively, you can use the Get-PodeHeader function to retrieve the header data. This function works similarly to the `Headers` property on `$WebEvent.Request`. - -Here is the same example using Get-PodeHeader: - -```powershell -Start-PodeServer { - Add-PodeEndpoint -Address * -Port 8080 -Protocol Http - - Add-PodeRoute -Method Get -Path '/validate' -ScriptBlock { - # get the token - $token = Get-PodeHeader -Name 'Authorization' - - # validate the token - $isValid = Test-PodeJwt -payload $token - - # return the result - Write-PodeJsonResponse -Value @{ - Success = $isValid - } - } -} -``` - - -## Cookies - -The following is an example of using values supplied in a request's cookies. To retrieve values from the cookies, you can use the `Cookies` property from the `$WebEvent` variable. - -Alternatively, you can use the `Get-PodeCookie` function to retrieve the cookie data. - -This example will get the `SessionId` cookie and use it to authenticate the user, returning a success message: - -```powershell -Start-PodeServer { - Add-PodeEndpoint -Address * -Port 8080 -Protocol Http - - Add-PodeRoute -Method Get -Path '/authenticate' -ScriptBlock { - # get the session ID from the cookie - $sessionId = $WebEvent.Cookies['SessionId'] - - # authenticate the session - $isAuthenticated = Authenticate-Session -SessionId $sessionId - - # return the result - Write-PodeJsonResponse -Value @{ - Authenticated = $isAuthenticated - } - } -} -``` - -The following request will invoke the above route: - -```powershell -Invoke-WebRequest -Uri 'http://localhost:8080/authenticate' -Method Get -Headers @{ Cookie = 'SessionId=abc123' } -``` - -Alternatively, you can use the `Get-PodeCookie` function to retrieve the cookie data. This function works similarly to the `Cookies` property on `$WebEvent`. - -Here is the same example using `Get-PodeCookie`: - -```powershell -Start-PodeServer { - Add-PodeEndpoint -Address * -Port 8080 -Protocol Http - - Add-PodeRoute -Method Get -Path '/authenticate' -ScriptBlock { - # get the session ID from the cookie - $sessionId = Get-PodeCookie -Name 'SessionId' - - # authenticate the session - $isAuthenticated = Authenticate-Session -SessionId $sessionId - - # return the result - Write-PodeJsonResponse -Value @{ - Authenticated = $isAuthenticated - } - } -} -``` - ## Script from File You normally define a route's script using the `-ScriptBlock` parameter however, you can also reference a file with the required scriptblock using `-FilePath`. Using the `-FilePath` parameter will dot-source a scriptblock from the file, and set it as the route's script. @@ -494,4 +298,4 @@ Static routes have a slightly different format: | OpenApi | hashtable[] | The OpenAPI definition/settings for the route | | Path | string | The path of the route - this path will have regex in place of dynamic file names | | Source | string | The source path within the server that is used for the route | -| TransferEncoding | string | The transfer encoding to use when parsing the payload in the request | +| TransferEncoding | string | The transfer encoding to use when parsing the payload in the request | \ No newline at end of file From 2def7ebd20e37b5ce40824420abe308676b2e6e7 Mon Sep 17 00:00:00 2001 From: mdaneri Date: Tue, 9 Jul 2024 14:39:14 -0700 Subject: [PATCH 08/10] Update 6MultipleDefinitions.md --- .../Tutorials/OpenAPI/6MultipleDefinitions.md | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/docs/Tutorials/OpenAPI/6MultipleDefinitions.md b/docs/Tutorials/OpenAPI/6MultipleDefinitions.md index aa7458e5d..ce50775d3 100644 --- a/docs/Tutorials/OpenAPI/6MultipleDefinitions.md +++ b/docs/Tutorials/OpenAPI/6MultipleDefinitions.md @@ -56,6 +56,29 @@ The default `Definition Tag` is named "default". This can be changed using the ` } ``` +### Renaming a Definition Tag + +A Definition Tag can be renamed at any time using the `Rename-PodeOADefinitionTagName` function. This allows you to update the tag name for an existing OpenAPI definition, ensuring your tags remain organized and meaningful. + +```powershell +Rename-PodeOADefinitionTagName -Tag 'v.3' -NewTag 'v.3.0.3' +``` + +In this example, the tag `'v.3'` is renamed to `'v.3.0.3'`. + +### Renaming the Default Definition Tag + +You can also rename the default `Definition Tag` without specifying the `Tag` parameter. This updates the default tag to the new name provided. + +```powershell +Rename-PodeOADefinitionTagName -NewTag 'NewDefault' +``` + +In this example, the default definition tag is renamed to `'NewDefault'`. + +!!! note +The `Rename-PodeOADefinitionTagName` function cannot be used inside a `Select-PodeOADefinition` `[Scriptblock]`. Attempting to do so will result in an error. + ### OpenAPI example A simple OpenAPI definition From 8a5e4c844c251a8b24e5393641c6bfcfcde7ea78 Mon Sep 17 00:00:00 2001 From: mdaneri Date: Wed, 10 Jul 2024 21:12:25 -0700 Subject: [PATCH 09/10] Delete Overview.md --- .../Tutorials/OpenAPI/6MultipleDefinitions.md | 2 +- docs/Tutorials/OpenAPI/Overview.md | 1067 ----------------- 2 files changed, 1 insertion(+), 1068 deletions(-) delete mode 100644 docs/Tutorials/OpenAPI/Overview.md diff --git a/docs/Tutorials/OpenAPI/6MultipleDefinitions.md b/docs/Tutorials/OpenAPI/6MultipleDefinitions.md index ce50775d3..ef0161873 100644 --- a/docs/Tutorials/OpenAPI/6MultipleDefinitions.md +++ b/docs/Tutorials/OpenAPI/6MultipleDefinitions.md @@ -77,7 +77,7 @@ Rename-PodeOADefinitionTagName -NewTag 'NewDefault' In this example, the default definition tag is renamed to `'NewDefault'`. !!! note -The `Rename-PodeOADefinitionTagName` function cannot be used inside a `Select-PodeOADefinition` `[Scriptblock]`. Attempting to do so will result in an error. + The `Rename-PodeOADefinitionTagName` function cannot be used inside a `Select-PodeOADefinition` `[Scriptblock]`. Attempting to do so will result in an error. ### OpenAPI example diff --git a/docs/Tutorials/OpenAPI/Overview.md b/docs/Tutorials/OpenAPI/Overview.md deleted file mode 100644 index 5c4bdbb15..000000000 --- a/docs/Tutorials/OpenAPI/Overview.md +++ /dev/null @@ -1,1067 +0,0 @@ -# Overview - -Pode has built-in support for converting your routes into OpenAPI 3.0 definitions. There is also support for enabling simple Swagger and/or ReDoc viewers and others. - -The OpenApi module has been extended with many more functions, and some old ones have been improved. - -For more detailed information regarding OpenAPI and Pode, please refer to [OpenAPI Specification and Pode](../Specification/v3_0_3.md) - -You can enable OpenAPI in Pode, and a straightforward definition will be generated. However, to get a more complex definition with request bodies, parameters, and response payloads, you'll need to use the relevant OpenAPI functions detailed below. - -## Enabling OpenAPI - -To enable support for generating OpenAPI definitions you'll need to use the [`Enable-PodeOpenApi`](../../../Functions/OpenApi/Enable-PodeOpenApi) function. This will allow you to set a title and version for your API. You can also set a default route to retrieve the OpenAPI definition for tools like Swagger or ReDoc, the default is at `/openapi`. - -You can also set a route filter (such as `/api/*`, the default is `/*` for everything), so only those routes are included in the definition. - -An example of enabling OpenAPI is a follows: - -```powershell -Enable-PodeOpenApi -Title 'My Awesome API' -Version 9.0.0.1 -``` - -An example of setting the OpenAPI route is a follows. This will create a route accessible at `/docs/openapi`: - -```powershell -Enable-PodeOpenApi -Path '/docs/openapi' -Title 'My Awesome API' -Version 9.0.0.1 -``` - -### Default Setup - -In the very simplest of scenarios, just enabling OpenAPI will generate a minimal definition. It can be viewed in Swagger/ReDoc etc, but won't be usable for trying calls. - -When you enable OpenAPI, and don't set any other OpenAPI data, the following is the minimal data that is included: - -* Every route will have a 200 and Default response -* Although routes will be included, no request bodies, parameters or response payloads will be defined -* If you have multiple endpoints, then the servers section will be included -* Any authentication will be included - -This can be changed with [`Enable-PodeOpenApi`](../../../Functions/OpenApi/Enable-PodeOpenApi) - -For example to change the default response 404 and 500 - -```powershell -Enable-PodeOpenApi -Path '/docs/openapi' -OpenApiVersion '3.0.3' -DefaultResponses ( - New-PodeOAResponse -StatusCode 404 -Description 'User not found' | Add-PodeOAResponse -StatusCode 500 - ) -``` - -For disabling the Default Response use: - -```powershell -Enable-PodeOpenApi -Path '/docs/openapi' -OpenApiVersion '3.0.3' -NoDefaultResponses -``` - -For disabling the Minimal Definitions feature use: - -```powershell -Enable-PodeOpenApi -Path '/docs/openapi' -OpenApiVersion '3.0.3' -DisableMinimalDefinitions -``` - -### Get Definition - -Instead of defining a route to return the definition, you can write the definition to the response whenever you want, and in any route, using the [`Get-PodeOADefinition`](../../../Functions/OpenApi/Get-PodeOADefinition) function. This could be useful in certain scenarios like in Azure Functions, where you can enable OpenAPI, and then write the definition to the response of a GET request if some query parameter is set; eg: `?openapi=1`. - -For example: - -```powershell -Add-PodeRoute -Method Get -Path '/' -ScriptBlock { - if ($WebEvent.Query.openapi -eq 1) { - Get-PodeOpenApiDefinition | Write-PodeJsonResponse - } -} -``` - -## OpenAPI Info object - -In previous releases some of the Info object properties like Version and Title were defined by [`Enable-PodeOpenApi`](../../../Functions/OpenApi/Enable-PodeOpenApi). -Starting from version 2.10 a new [`Add-PodeOAInfo`](../../../Functions/OpenApi/Add-PodeOAInfo) function has been added to create a full OpenAPI Info spec. - -```powershell -Add-PodeOAInfo -Title 'Swagger Petstore - OpenAPI 3.0' ` - -Version 1.0.17 ` - -Description $InfoDescription ` - -TermsOfService 'http://swagger.io/terms/' ` - -LicenseName 'Apache 2.0' ` - -LicenseUrl 'http://www.apache.org/licenses/LICENSE-2.0.html' ` - -ContactName 'API Support' ` - -ContactEmail 'apiteam@swagger.io' -``` - -## OpenAPI configuration Best Practice - -Pode is rich of functions to create and configure an complete OpenApi spec. Here is a typical code you should use to initiate an OpenApi spec - -```powershell -#Initialize OpenApi -Enable-PodeOpenApi -Path '/docs/openapi' -Title 'Swagger Petstore - OpenAPI 3.0' ` - -OpenApiVersion 3.1 -DisableMinimalDefinitions -NoDefaultResponses - -# OpenApi Info -Add-PodeOAInfo -Title 'Swagger Petstore - OpenAPI 3.0' ` - -Version 1.0.17 ` - -Description 'This is a sample Pet Store Server based on the OpenAPI 3.0 specification. ...' ` - -TermsOfService 'http://swagger.io/terms/' ` - -LicenseName 'Apache 2.0' ` - -LicenseUrl 'http://www.apache.org/licenses/LICENSE-2.0.html' ` - -ContactName 'API Support' ` - -ContactEmail 'apiteam@swagger.io' ` - -ContactUrl 'http://example.com/support' - -# Endpoint for the API - Add-PodeOAServerEndpoint -url '/api/v3.1' -Description 'default endpoint' - - # OpenApi external documentation links - $extDoc = New-PodeOAExternalDoc -Name 'SwaggerDocs' -Description 'Find out more about Swagger' -Url 'http://swagger.io' - $extDoc | Add-PodeOAExternalDoc - - # OpenApi documentation viewer - Enable-PodeOAViewer -Type Swagger -Path '/docs/swagger' - Enable-PodeOAViewer -Type ReDoc -Path '/docs/redoc' - Enable-PodeOAViewer -Type RapiDoc -Path '/docs/rapidoc' - Enable-PodeOAViewer -Type StopLight -Path '/docs/stoplight' - Enable-PodeOAViewer -Type Explorer -Path '/docs/explorer' - Enable-PodeOAViewer -Bookmarks -Path '/docs' -``` - -## Authentication - -Any authentication defined, either by [`Add-PodeAuthMiddleware`](../../../Functions/Authentication/Add-PodeAuthMiddleware), or using the `-Authentication` parameter on Routes, will be automatically added to the `security` section of the OpenAPI definition. - - -## Tags - -In OpenAPI, a "tag" is used to group related operations. Tags are often used to organize and categorize endpoints in an API specification, making it easier to understand and navigate the API documentation. Each tag can be associated with one or more API operations, and these tags are then used in tools like Swagger UI to group and display operations in a more organized way. - -Here's an example of how to define and use tags: - -```powershell -# create an External Doc reference -$swaggerDocs = New-PodeOAExternalDoc -Description 'Find out more about Swagger' -Url 'http://swagger.io' - -# create a Tag -Add-PodeOATag -Name 'pet' -Description 'Everything about your Pets' -ExternalDoc $swaggerDocs - -Add-PodeRoute -PassThru -Method get -Path '/pet/findByStatus' -Authentication 'Login-OAuth2' -Scope 'read' -AllowAnon -ScriptBlock { - #route code -} | Set-PodeOARouteInfo -Summary 'Finds Pets by status' -Description 'Multiple status values can be provided with comma-separated strings' ` - -Tags 'pet' -OperationId 'findPetsByStatus' -``` - -## Routes - -To extend the definition of a route, you can use the `-PassThru` switch on the [`Add-PodeRoute`](../../../Functions/Routes/Add-PodeRoute) function. This will cause the route that was created to be returned, so you can pass it down the pipe into more OpenAPI functions. - -To add metadata to a route's definition you can use the [`Set-PodeOARouteInfo`](../../../Functions/OpenApi/Set-PodeOARouteInfo) function. This will allow you to define a summary/description for the route, as well as tags for grouping: - -```powershell -Add-PodeRoute -Method Get -Path "/api/resources" -ScriptBlock { - Set-PodeResponseStatus -Code 200 -} -PassThru | - Set-PodeOARouteInfo -Summary 'Retrieve some resources' -Tags 'Resources' -``` - -Each of the following OpenAPI functions have a `-PassThru` switch, allowing you to chain many of them together. - -### Responses - -You can define multiple responses for a route, but only one of each status code, using the [`Add-PodeOAResponse`](../../../Functions/OpenApi/Add-PodeOAResponse) function. You can either just define the response and status code, with a custom description, or with a schema defining the payload of the response. - -The following is an example of defining simple 200 and 404 responses on a route: - -```powershell -Add-PodeRoute -Method Get -Path "/api/user/:userId" -ScriptBlock { - # logic -} -PassThru | - Add-PodeOAResponse -StatusCode 200 -PassThru | - Add-PodeOAResponse -StatusCode 404 -Description 'User not found' -``` - -Whereas the following is a more complex definition, which also defines the responses JSON payload. This payload is defined as an object with a string Name, and integer UserId: - -```powershell -Add-PodeRoute -Method Get -Path '/api/users/:userId' -ScriptBlock { - Write-PodeJsonResponse -Value @{ - Name = 'Rick' - UserId = $WebEvent.Parameters['userId'] - } -} -PassThru | - Add-PodeOAResponse -StatusCode 200 -Description 'A user object' --Content @{ - 'application/json' = (New-PodeOAStringProperty -Name 'Name'| - New-PodeOAIntProperty -Name 'UserId'| New-PodeOAObjectProperty) - } -``` - -the JSON response payload defined is as follows: - -```json -{ - "Name": [string], - "UserId": [integer] -} -``` - -In case the response JSON payload is an array - -```powershell -Add-PodeRoute -Method Get -Path '/api/users/:userId' -ScriptBlock { - Write-PodeJsonResponse -Value @{ - Name = 'Rick' - UserId = $WebEvent.Parameters['userId'] - } - } -PassThru | - Add-PodeOAResponse -StatusCode 200 -Description 'A user object' -Content ( - New-PodeOAContentMediaType -ContentMediaType 'application/json' -Array -Content ( - New-PodeOAStringProperty -Name 'Name' | - New-PodeOAIntProperty -Name 'UserId' | - New-PodeOAObjectProperty - ) - ) -``` - -```json -[ - { - "Name": [string], - "UserId": [integer] - } -] -``` - -Internally, each route is created with an empty default 200 and 500 response. You can remove these, or other added responses, by using [`Remove-PodeOAResponse`](../../../Functions/OpenApi/Remove-PodeOAResponse): - -```powershell -Add-PodeRoute -Method Get -Path "/api/user/:userId" -ScriptBlock { - # route logic -} -PassThru | - Remove-PodeOAResponse -StatusCode 200 -``` - -### Requests - -#### Parameters - -You can set route parameter definitions, such as parameters passed in the path/query, by using the [`Set-PodeOARequest`](../../../Functions/OpenApi/Set-PodeOARequest) function with the `-Parameters` parameter. The parameter takes an array of properties converted into parameters, using the [`ConvertTo-PodeOAParameter`](../../../Functions/OpenApi/ConvertTo-PodeOAParameter) function. - -For example, to create some integer `userId` parameter that is supplied in the path of the request, the following will work: - -```powershell -Add-PodeRoute -Method Get -Path '/api/users/:userId' -ScriptBlock { - Write-PodeJsonResponse -Value @{ - Name = 'Rick' - UserId = $WebEvent.Parameters['userId'] - } -} -PassThru | - Set-PodeOARequest -Parameters @( - (New-PodeOAIntProperty -Name 'userId' -Required | ConvertTo-PodeOAParameter -In Path) - ) -``` - -Whereas you could use the next example to define 2 query parameters, both strings: - -```powershell -Add-PodeRoute -Method Get -Path '/api/users' -ScriptBlock { - Write-PodeJsonResponse -Value @{ - Name = 'Rick' - UserId = $WebEvent.Query['name'] - } -} -PassThru | - Set-PodeOARequest -Parameters ( - (New-PodeOAStringProperty -Name 'name' -Required | ConvertTo-PodeOAParameter -In Query), - (New-PodeOAStringProperty -Name 'city' -Required | ConvertTo-PodeOAParameter -In Query) - ) -``` - -#### Payload - -You can set request payload schemas by using the [`Set-PodeOARequest`](../../../Functions/OpenApi/Set-PodeOARequest)function, with the `-RequestBody` parameter. The request body can be defined using the [`New-PodeOARequestBody`](../../../Functions/OpenApi/New-PodeOARequestBody) function, and supplying schema definitions for content types - this works in very much a similar way to defining responses above. - -For example, to define a request JSON payload of some `userId` and `name` you could use the following: - -```powershell -Add-PodeRoute -Method Patch -Path '/api/users' -ScriptBlock { - Write-PodeJsonResponse -Value @{ - Name = $WebEvent.Data.name - UserId = $WebEvent.Data.userId - } -} -PassThru | - Set-PodeOARequest -RequestBody ( - New-PodeOARequestBody -Required -Content ( - New-PodeOAContentMediaType -ContentMediaType 'application/json','application/xml' -Content ( New-PodeOAStringProperty -Name 'Name'| New-PodeOAIntProperty -Name 'UserId'| New-PodeOAObjectProperty ) ) - - ) -``` - -The expected payload would look as follows: - -```json -{ - "name": [string], - "userId": [integer] -} -``` - -```xml - - - - - -``` - -## Components - -You can define reusable OpenAPI components in Pode. Currently supported are Schemas, Parameters, Request Bodies, and Responses. - -### Schemas - -To define a reusable schema that can be used in request bodies, and responses, you can use the [`Add-PodeOAComponentSchema`](../../../Functions/OAComponents/Add-PodeOAComponentSchema) function. You'll need to supply a Name, and a Schema that can be reused. - -The following is an example of defining a schema which is a object of Name, UserId, and Age: - -```powershell -# define a reusable schema user object -New-PodeOAStringProperty -Name 'Name' | - New-PodeOAIntProperty -Name 'UserId' | - New-PodeOAIntProperty -Name 'Age' | - New-PodeOAObjectProperty | - Add-PodeOAComponentSchema -Name 'UserSchema' - -# reuse the above schema in a response -Add-PodeRoute -Method Get -Path '/api/users/:userId' -ScriptBlock { - Write-PodeJsonResponse -Value @{ - Name = 'Rick' - UserId = $WebEvent.Parameters['userId'] - Age = 42 - } -} -PassThru | - Add-PodeOAResponse -StatusCode 200 -Description 'A list of users' -Content @{ - 'application/json' = 'UserSchema' - } -``` - -### Request Bodies - -To define a reusable request bodies you can use the [`Add-PodeOAComponentRequestBody`](../../../Functions/OAComponents/Add-PodeOAComponentRequestBody) function. You'll need to supply a Name, as well as the needed schemas for each content type. - -The following is an example of defining a JSON object that a Name, UserId, and an Enable flag: - -```powershell -# define a reusable request body -New-PodeOAContentMediaType -ContentMediaType 'application/json', 'application/x-www-form-urlencoded' -Content ( - New-PodeOAStringProperty -Name 'Name' | - New-PodeOAIntProperty -Name 'UserId' | - New-PodeOABoolProperty -Name 'Enabled' | - New-PodeOAObjectProperty - ) | Add-PodeOAComponentRequestBody -Name 'UserBody' -Required - -# use the request body in a route -Add-PodeRoute -Method Patch -Path '/api/users' -ScriptBlock { - Set-PodeResponseStatus -StatusCode 200 -} -PassThru | - Set-PodeOARequest -RequestBody (New-PodeOARequestBody -Reference 'UserBody') -``` - -The JSON payload expected is of the format: - -```json -{ - "Name": [string], - "UserId": [integer], - "Enabled": [boolean] -} -``` - -### Parameters - -To define reusable parameters that are used on requests, you can use the [`Add-PodeOAComponentParameter`](../../../Functions/OAComponents/Add-PodeOAComponentParameter) function. You'll need to supply a Name and the Parameter definition. - -The following is an example of defining an integer path parameter for a `userId`, and then using that parameter on a route. - -```powershell -# define a reusable {userid} path parameter -New-PodeOAIntProperty -Name 'userId' -Required | ConvertTo-PodeOAParameter -In Path |Add-PodeOAComponentParameter -Name 'UserId' - -# use this parameter in a route -Add-PodeRoute -Method Get -Path '/api/users/:userId' -ScriptBlock { - Write-PodeJsonResponse -Value @{ - Name = 'Rick' - UserId = $WebEvent.Parameters['userId'] - } -} -PassThru | - Set-PodeOARequest -Parameters @(ConvertTo-PodeOAParameter -Reference 'UserId') -``` - -### Responses - -To define a reusable response definition you can use the [`Add-PodeOAComponentResponse`](../../../Functions/OAComponents/Add-PodeOAComponentResponse) function. You'll need to supply a Name, and optionally any Content/Header schemas that define the responses payload. - -The following is an example of defining a 200 response with a JSON payload of an array of objects for Name/UserId. The Response component can be used by a route referencing the name: - -```powershell -# defines a response with a json payload using New-PodeOAContentMediaType -Add-PodeOAComponentResponse -Name 'OK' -Description 'A user object' -Content ( - New-PodeOAContentMediaType -MediaType 'application/json' -Array -Content ( - New-PodeOAStringProperty -Name 'Name' | - New-PodeOAIntProperty -Name 'UserId' | - New-PodeOAObjectProperty - ) - ) - -# reuses the above response on a route using its "OK" name -Add-PodeRoute -Method Get -Path "/api/users" -ScriptBlock { - Write-PodeJsonResponse -Value @( - @{ Name = 'Rick'; UserId = 123 }, - @{ Name = 'Geralt'; UserId = 124 } - ) -} -PassThru | - Add-PodeOAResponse -StatusCode 200 -Reference 'OK' -``` - -the JSON response payload defined is as follows: - -```json -[ - { - "Name": [string], - "UserId": [integer] - } -] -``` - - -### Examples - -To define a reusable example definition you can use the [`Add-PodeOAComponentExample`](../../../Functions/OAComponents/Add-PodeOAComponentExample) function. You'll need to supply a Name, a Summary and a list of value representing the object. - -The following is an example that defines three Pet examples request bodies, and how they're used in a Route's OpenAPI definition: - -```powershell - # defines the frog example -Add-PodeOAComponentExample -name 'frog-example' -Summary "An example of a frog with a cat's name" -Value @{ - name = 'Jaguar'; petType = 'Panthera'; color = 'Lion'; gender = 'Male'; breed = 'Mantella Baroni' -} -# defines the cat example -Add-PodeOAComponentExample -Name 'cat-example' -Summary 'An example of a cat' -Value @{ - name = 'Fluffy'; petType = 'Cat'; color = 'White'; gender = 'male'; breed = 'Persian' -} -# defines the dog example -Add-PodeOAComponentExample -Name 'dog-example' -Summary "An example of a dog with a cat's name" -Value @{ - name = 'Puma'; petType = 'Dog'; color = 'Black'; gender = 'Female'; breed = 'Mixed' -} - -# reuses the examples -Add-PodeRoute -PassThru -Method Put -Path '/pet/:petId' -ScriptBlock { - # route code -} | Set-PodeOARouteInfo -Summary 'Updates a pet in the store with form data' -Tags 'pet' ` - -OperationId 'updatepet' -PassThru | - Set-PodeOARequest -Parameters @( - (New-PodeOAStringProperty -Name 'petId' -Description 'ID of pet that needs to be updated' | ConvertTo-PodeOAParameter -In Path -Required) - ) -RequestBody ( - New-PodeOARequestBody -Description 'user to add to the system' -Content @{ 'application/json' = 'Pet' } -Examples ( - New-PodeOAExample -ContentMediaType 'application/json', 'application/xml' -Reference 'cat-example' | - New-PodeOAExample -ContentMediaType 'application/json', 'application/xml' -Reference 'dog-example' | - New-PodeOAExample -ContentMediaType 'application/json', 'application/xml' -Reference 'frog-example' - ) - ) -PassThru | - Add-PodeOAResponse -StatusCode 200 -Description 'Pet updated.' -``` - -### Headers - -To define a reusable header definition you can use the [`Add-PodeOAComponentHeader`](../../../Functions/OAComponents/Add-PodeOAComponentHeader) function. You'll need to supply a Name, and optionally any Content/Header schemas that define the responses payload. - -```powershell - # define Headers -New-PodeOAIntProperty -Format Int32 -Description 'calls per hour allowed by the user' | - Add-PodeOAComponentHeader -Name 'X-Rate-Limit' -New-PodeOAStringProperty -Format Date-Time -Description 'date in UTC when token expires' | - Add-PodeOAComponentHeader -Name 'X-Expires-After' - -Add-PodeRoute -PassThru -Method Get -Path '/user/login' -ScriptBlock { - # route code -} | Set-PodeOARouteInfo -Summary 'Logs user into the system.' -Description 'Logs user into the system.' ` - -Tags 'user' -OperationId 'loginUser' -PassThru | - Add-PodeOAResponse -StatusCode 200 -Description 'Successful operation' ` - -Header @('X-Rate-Limit', 'X-Expires-After') -Content ( - New-PodeOAContentMediaType -MediaType 'application/json', 'application/xml' -Content 'string' - ) -PassThru | - Add-PodeOAResponse -StatusCode 400 -Description 'Invalid username/password supplied' -``` - - -### CallBacks - -To define a reusable callback definition you can use the [`Add-PodeOAComponentCallBack`](../../../Functions/OAComponents/Add-PodeOAComponentCallBack) function. You'll need to supply a Name, and optionally any Content/Header schemas that define the responses payload. - -```powershell -Add-PodeRoute -PassThru -Method Post -Path '/petcallbackReference' -Authentication 'Login-OAuth2' ` - -Scope 'write' -ScriptBlock { - #route code -} | Set-PodeOARouteInfo -Summary 'Add a new pet to the store' -Description 'Add a new pet to the store' ` - -Tags 'pet' -OperationId 'petcallbackReference' -PassThru | - Set-PodeOARequest -RequestBody ( New-PodeOARequestBody -Reference 'PetBodySchema' ) -PassThru | - Add-PodeOAResponse -StatusCode 200 -Description 'Successful operation' -Content ( - New-PodeOAContentMediaType -MediaType 'application/json', 'application/xml' -Content 'Pet' - ) -PassThru | - Add-PodeOAResponse -StatusCode 405 -Description 'Validation exception' -Content @{ - 'application / json' = ( New-PodeOAStringProperty -Name 'result' | - New-PodeOAStringProperty -Name 'message' | - New-PodeOAObjectProperty ) - } -PassThru | - Add-PodeOACallBack -Name 'test1' -Reference 'test' -``` - -### Response Links - -To define a reusable response link definition you can use the [`Add-PodeOAComponentResponseLink`](../../../Functions/OAComponents/Add-PodeOAComponentResponseLink) function. You'll need to supply a Name, and optionally any Content/Header schemas that define the responses payload. - -```powershell -#Add link reference -Add-PodeOAComponentResponseLink -Name 'address' -OperationId 'getUserByName' -Parameters @{ - 'username' = '$request.path.username' -} - -#use link reference -Add-PodeRoute -PassThru -Method Put -Path '/userLinkByRef/:username' -ScriptBlock { - Write-PodeJsonResponse -Value 'done' -StatusCode 200 -} | Set-PodeOARouteInfo -Summary 'Update user' -Description 'This can only be done by the logged in user.' ` - -Tags 'user' -OperationId 'updateUserLinkByRef' -PassThru | - Set-PodeOARequest -Parameters ( - ( New-PodeOAStringProperty -Name 'username' -Description ' name that need to be updated.' -Required | ConvertTo-PodeOAParameter -In Path ) - ) -RequestBody ( - New-PodeOARequestBody -Required -Content ( - New-PodeOAContentMediaType -MediaType 'application/json', 'application/xml', 'application/x-www-form-urlencoded' -Content 'User' ) - ) -PassThru | - Add-PodeOAResponse -StatusCode 200 -Content @{'application/json' = 'User' } -PassThru -Links ( - New-PodeOAResponseLink -Name 'address2' -Reference 'address' - ) | - Add-PodeOAResponse -StatusCode 400 -Description 'Invalid username supplied' -PassThru | - Add-PodeOAResponse -StatusCode 404 -Description 'User not found' -PassThru | - Add-PodeOAResponse -StatusCode 405 -Description 'Invalid Input' -``` - -## Properties - -Properties are used to create all Parameters and Schemas in OpenAPI. You can use the simple types on their own, or you can combine multiple of them together to form complex objects. - -### Simple Types - -There are 5 simple property types: Integers, Numbers, Strings, Booleans, and Schemas. Each of which can be created using the following functions: - -* [`New-PodeOAIntProperty`](../../../Functions/OAProperties/New-PodeOAIntProperty) -* [`New-PodeOANumberProperty`](../../../Functions/OAProperties/New-PodeOANumberProperty) -* [`New-PodeOAStringProperty`](../../../Functions/OAProperties/New-PodeOAStringProperty) -* [`New-PodeOABoolProperty`](../../../Functions/OAProperties/New-PodeOABoolProperty) -* [`New-PodeOASchemaProperty`](../../../Functions//New-PodeOASchemaProperty) -* [`New-PodeOAMultiTypeProperty`](../../../Functions/OAProperties/New-PodeOAMultiTypeProperty) (Note: OpenAPI 3.1 only) - -These properties can be created with a Name, and other flags such as Required and/or a Description: - -```powershell -# simple integer -New-PodeOAIntProperty -Name 'userId' - -# a float number with a max value of 100 -New-PodeOANumberProperty -Name 'ratio' -Format Float -Maximum 100 - -# a string with a default value, and enum of options -New-PodeOAStringProperty -Name 'type' -Default 'admin' -Enum @('admin', 'user') - -# a boolean that's required -New-PodeOABoolProperty -Name 'enabled' -Required - -# a schema property that references another component schema -New-PodeOASchemaProperty -Name 'Config' -Reference 'ConfigSchema' - -# a string or an integer or a null value (only available with OpenAPI 3.1) -New-PodeOAMultiTypeProperty -Name 'multi' -Type integer,string -Nullable -``` - -On their own, like above, the simple properties don't really do much. However, you can combine that together to make complex objects/arrays as defined below. - -### Arrays - -There isn't a dedicated function to create an array property, instead there is an `-Array` switch on each of the property functions - both Object and the above simple properties. - -If you supply the `-Array` switch to any of the above simple properties, this will define an array of that type - the `-Name` parameter can also be omitted if only a simple array if required. - -For example, the below will define an integer array: - -```powershell -New-PodeOAIntProperty -Array -``` - -When used in a Response, this could return the following JSON example: - -```json -[ - 0, - 1, - 2 -] -``` - -### Objects - -An object property is a combination of multiple other properties - both simple, array of more objects. - -There are two ways to define objects: - -1. Similar to arrays, you can use the `-Object` switch on the simple properties. -2. You can use the [`New-PodeOAObjectProperty`](../../../Functions/OAProperties/New-PodeOAObjectProperty) function to combine multiple properties. - -#### Simple - -If you use the `-Object` switch on the simple property function, this will automatically wrap the property as an object. The Name for this is required. - -For example, the below will define a simple `userId` integer object: - -```powershell -New-PodeOAIntProperty -Name 'userId' -Object -``` - -In a response as JSON, this could look as follows: - -```json -{ - "userId": 0 -} -``` - -Furthermore, you can also supply both `-Array` and `-Object` switches: - -```powershell -New-PodeOAIntProperty -Name 'userId' -Object -Array -``` - -This wil result in something like the following JSON: - -```json -{ - "userId": [ 0, 1, 2 ] -} -``` - -#### Complex - -Unlike the `-Object` switch that simply converts a single property into an object, the [`New-PodeOAObjectProperty`](../../../Functions/OAProperties/New-PodeOAObjectProperty) function can combine and convert multiple properties. - -For example, the following will create an object using an Integer, String, and a Boolean: - -Legacy Definition - -```powershell -New-PodeOAObjectProperty -Properties ( - (New-PodeOAIntProperty -Name 'userId'), - (New-PodeOAStringProperty -Name 'name'), - (New-PodeOABoolProperty -Name 'enabled') -) -``` - -Using piping (new in Pode 2.10) - -```powershell -New-PodeOAIntProperty -Name 'userId'| New-PodeOAStringProperty -Name 'name'| - New-PodeOABoolProperty -Name 'enabled' |New-PodeOAObjectProperty -``` - -As JSON, this could look as follows: - -```json -{ - "userId": 0, - "name": "Gary Goodspeed", - "enabled": true -} -``` - -You can also supply the `-Array` switch to the [`New-PodeOAObjectProperty`](../../../Functions/OAProperties/New-PodeOAObjectProperty) function. This will result in an array of objects. For example, if we took the above: - -```powershell -New-PodeOAIntProperty -Name 'userId'| New-PodeOAStringProperty -Name 'name'| - New-PodeOABoolProperty -Name 'enabled' |New-PodeOAObjectProperty -Array -``` - -As JSON, this could look as follows: - -```json -[ - { - "userId": 0, - "name": "Gary Goodspeed", - "enabled": true - }, - { - "userId": 1, - "name": "Kevin", - "enabled": false - } -] -``` - -You can also combine objects into other objects: - -```powershell -$usersArray = New-PodeOAIntProperty -Name 'userId'| New-PodeOAStringProperty -Name 'name'| - New-PodeOABoolProperty -Name 'enabled' |New-PodeOAObjectProperty -Array - -New-PodeOAObjectProperty -Properties @( - (New-PodeOAIntProperty -Name 'found'), - $usersArray -) -``` - -As JSON, this could look as follows: - -```json -{ - "found": 2, - "users": [ - { - "userId": 0, - "name": "Gary Goodspeed", - "enabled": true - }, - { - "userId": 1, - "name": "Kevin", - "enabled": false - } - ] -} -``` - -### oneOf, anyOf and allOf Keywords - -OpenAPI 3.x provides several keywords which you can use to combine schemas. You can use these keywords to create a complex schema or validate a value against multiple criteria. - -* oneOf - validates the value against exactly one of the sub-schemas -* allOf - validates the value against all the sub-schemas -* anyOf - validates the value against any (one or more) of the sub-schemas - -You can use the [`Merge-PodeOAProperty`](../../../Functions/OAProperties/Merge-PodeOAProperty) will instead define a relationship between the properties. - -Unlike [`New-PodeOAObjectProperty`](../../../Functions/OAProperties/New-PodeOAObjectProperty) which combines and converts multiple properties into an Object, [`Merge-PodeOAProperty`](../../../Functions/OAProperties/Merge-PodeOAProperty) will instead define a relationship between the properties. - -For example, the following will create an something like an C Union object using an Integer, String, and a Boolean: - -```powershell -Merge-PodeOAProperty -Type OneOf -ObjectDefinitions @( - (New-PodeOAIntProperty -Name 'userId' -Object), - (New-PodeOAStringProperty -Name 'name' -Object), - (New-PodeOABoolProperty -Name 'enabled' -Object) - ) -``` - -Or - -```powershell -New-PodeOAIntProperty -Name 'userId' -Object | - New-PodeOAStringProperty -Name 'name' -Object | - New-PodeOABoolProperty -Name 'enabled' -Object | - Merge-PodeOAProperty -Type OneOf -``` - -As JSON, this could look as follows: - -```json -{ - "oneOf": [ - { - "type": "object", - "properties": { - "userId": { - "type": "integer" - } - } - }, - { - "type": "object", - "properties": { - "name": { - "type": "string" - } - } - }, - { - "type": "object", - "properties": { - "enabled": { - "type": "boolean", - "default": false - } - } - } - ] -} -``` - -You can also supply a Component Schema created using [`Add-PodeOAComponentSchema`](../../../Functions/OAComponents/Add-PodeOAComponentSchema). For example, if we took the above: - -```powershell - New-PodeOAIntProperty -Name 'id'-Format Int64 -Example 1 -ReadOnly | - New-PodeOAStringProperty -Name 'username' -Example 'theUser' -Required | - New-PodeOAStringProperty -Name 'firstName' -Example 'John' | - New-PodeOAStringProperty -Name 'lastName' -Example 'James' | - New-PodeOAStringProperty -Name 'email' -Format email -Example 'john@email.com' | - New-PodeOAStringProperty -Name 'lastName' -Example 'James' | - New-PodeOAStringProperty -Name 'password' -Format Password -Example '12345' -Required | - New-PodeOAStringProperty -Name 'phone' -Example '12345' | - New-PodeOAIntProperty -Name 'userStatus'-Format int32 -Description 'User Status' -Example 1| - New-PodeOAObjectProperty -Name 'User' -XmlName 'user' | - Add-PodeOAComponentSchema - - New-PodeOAStringProperty -Name 'street' -Example '437 Lytton' -Required | - New-PodeOAStringProperty -Name 'city' -Example 'Palo Alto' -Required | - New-PodeOAStringProperty -Name 'state' -Example 'CA' -Required | - New-PodeOAStringProperty -Name 'zip' -Example '94031' -Required | - New-PodeOAObjectProperty -Name 'Address' -XmlName 'address' -Description 'Shipping Address' | - Add-PodeOAComponentSchema - - Merge-PodeOAProperty -Type AllOf -ObjectDefinitions 'Address','User' - -``` - -As JSON, this could look as follows: - -```json -{ - "allOf": [ - { - "$ref": "#/components/schemas/Address" - }, - { - "$ref": "#/components/schemas/User" - } - ] -} -``` -## Implementing Parameter Validation - -Is possible to validate any parameter submitted by clients against an OpenAPI schema, ensuring adherence to defined standards. - - -First, schema validation has to be enabled using : - -```powershell -Enable-PodeOpenApi -EnableSchemaValidation #any other parameters needed -``` - -This command activates the OpenAPI feature with schema validation enabled, ensuring strict adherence to specified schemas. - -Next, is possible to validate any route using `PodeOAJsonSchemaCompliance`. -In this example, we'll create a route for updating a pet: - -```powershell -Add-PodeRoute -PassThru -Method Post -Path '/user' -ScriptBlock { - $contentType = Get-PodeHeader -Name 'Content-Type' - $responseMediaType = Get-PodeHeader -Name 'Accept' - switch ($contentType) { - 'application/xml' { - $user = ConvertFrom-PodeXml -node $WebEvent.data | ConvertTo-Json - } - 'application/json' { $user = ConvertTo-Json $WebEvent.data } - 'application/x-www-form-urlencoded' { $user = ConvertTo-Json $WebEvent.data } - default { - Write-PodeHtmlResponse -StatusCode 415 - return - } - } - $Validate = Test-PodeOAJsonSchemaCompliance -Json $user -SchemaReference 'User' - if ($Validate.result) { - $newUser = Add-user -User (convertfrom-json -InputObject $user -AsHashtable) - Save-PodeState -Path $using:PetDataJson - switch ($responseMediaType) { - 'application/xml' { Write-PodeXmlResponse -Value $newUser -StatusCode 200 } - 'application/json' { Write-PodeJsonResponse -Value $newUser -StatusCode 200 } - default { Write-PodeHtmlResponse -StatusCode 415 } - } - } - else { - Write-PodeHtmlResponse -StatusCode 405 -Value ($Validate.message -join ', ') - } -} | Set-PodeOARouteInfo -Summary 'Create user.' -Description 'This can only be done by the logged in user.' -Tags 'user' -OperationId 'createUser' -PassThru | - Set-PodeOARequest -RequestBody (New-PodeOARequestBody -Content (New-PodeOAContentMediaType -MediaType 'application/json', 'application/xml', 'application/x-www-form-urlencoded' -Content 'User' )) -PassThru | - Add-PodeOAResponse -StatusCode 405 -Description 'Invalid Input' -PassThru | - Add-PodeOAResponse -Default -Content (New-PodeOAContentMediaType -MediaType 'application/json', 'application/xml' -Content 'User' ) -``` -#### Explanation -- The route handles different content types (JSON/XML) and converts them to JSON for validation. -- It validates the received pet object against the 'User' schema using the 'Test-PodeOAJsonSchemaCompliance' function. -- Depending on the validation result, appropriate HTTP responses are returned. -- OpenAPI metadata such as summary, description, request body, and responses are also defined for documentation purposes. - - - -## OpenApi Documentation pages - -If you're not using a custom OpenAPI viewer, then you can use one or more of the inbuilt which Pode supports: ones with Pode: - -* Swagger -* ReDoc -* RapiDoc -* StopLight -* Explorer -* RapiPdf - -For each you can customise the Route path to access the page on, but by default Swagger is at `/swagger`, ReDoc is at `/redoc`, etc. If you've written your own custom OpenAPI definition then you can also set a custom Route path to fetch the definition on. - -To enable a viewer you can use the [`Enable-PodeOAViewer`](../../../Functions/OpenApi/Enable-PodeOAViewer) function: - -```powershell -# for swagger at "/docs/swagger" -Enable-PodeOpenApiViewer -Type Swagger -Path '/docs/swagger' -DarkMode - -# and ReDoc at the default "/redoc" -Enable-PodeOpenApiViewer -Type ReDoc - -# and RapiDoc at "/docs/rapidoc" -Enable-PodeOAViewer -Type RapiDoc -Path '/docs/rapidoc' -DarkMode - -# and StopLight at "/docs/stoplight" -Enable-PodeOAViewer -Type StopLight -Path '/docs/stoplight' - -# and Explorer at "/docs/explorer" -Enable-PodeOAViewer -Type Explorer -Path '/docs/explorer' - -# and RapiPdf at "/docs/rapipdf" -Enable-PodeOAViewer -Type RapiPdf -Path '/docs/rapipdf' - -# plus a bookmark page with the link to all documentation -Enable-PodeOAViewer -Bookmarks -Path '/docs' - -# there is also an OpenAPI editor (only for v3.0.x) -Enable-PodeOAViewer -Editor -Path '/docs/swagger-editor' -``` - -## Multiple OpenAPI definition - -It's possible to create multiple OpenAPI definitions inside the same Server instance. This feature could be useful in situations such as: - -* Multiple versions of the OpenAPI specification for different use cases -* The same OpenAPI definition, but one using OpenAPI v3.0.3 and another using v3.1.0 -* Different APIs based on the IP or URL - - -### How to use it -Any Pode function that interacts with OpenAPI has a `-DefinitionTag [string[]]` parameter available. This allows you to specify within which OpenAPI definition(s) the API's definition should be available. - -!!! note - These functions accept a simple string, and not an array - - * Get-PodeOADefinition - * Enable-PodeOpenApi - * Enable-PodeOAViewer - * Add-PodeOAInfo - * Test-PodeOAJsonSchemaCompliance - -A new OpenAPI definition has to be created using the `Enable-PodeOpenApi` function - -```powershell -Enable-PodeOpenApi -Path '/docs/openapi/v3.0' -OpenApiVersion '3.0.3' -DefinitionTag 'v3' -Enable-PodeOpenApi -Path '/docs/openapi/v3.1' -OpenApiVersion '3.1.0' -DefinitionTag 'v3.1' -Enable-PodeOpenApi -Path '/docs/openapi/admin' -OpenApiVersion '3.1.0' -DefinitionTag 'admin' -``` - -There is also [`Select-PodeOADefinition`](../../../Functions/OpenApi/Select-PodeOADefinition), which simplifies the selection of which OpenAPI definition to use as a wrapper around multiple OpenAPI functions, or Route functions. Meaning you don't have to specify `-DefinitionTag` on embedded OpenAPI/Route calls: - -```powershell -Select-PodeOADefinition -Tag 'v3', 'v3.1' -Scriptblock { - Add-PodeRouteGroup -Path '/api/v5' -Routes { - Add-PodeRoute -Method Get -Path '/petbyRef/:petId' -ScriptBlock { - Write-PodeJsonResponse -Value 'done' -StatusCode 2005 - } - } -} - -Select-PodeOADefinition -Tag 'admin' -ScriptBlock { - # your admin definition -} -``` - -The default `Definition Tag` is named "default". This can be changed using the `Server.psd1` file and the `Web.OpenApi.DefaultDefinitionTag` property - -```powershell -@{ - Web=@{ - OpenApi=@{ - DefaultDefinitionTag= 'NewDefault' - } - } -} -``` - -### Renaming a Definition Tag - -A `Definition Tag` can be renamed at any time using the `Rename-PodeOADefinitionTagName` function. This allows you to update the tag name for an existing OpenAPI definition, ensuring your tags remain organized and meaningful. - -```powershell -Rename-PodeOADefinitionTagName -Tag 'v.3' -NewTag 'v.3.0.3' -``` - -In this example, the tag `'v.3'` is renamed to `'v.3.0.3'`. - -### Renaming the Default Definition Tag - -You can also rename the default `Definition Tag` without specifying the `Tag` parameter. This updates the default tag to the new name provided. - -```powershell -Rename-PodeOADefinitionTagName -NewTag 'NewDefault' -``` - -In this example, the default definition tag is renamed to `'NewDefault'`. - -!!! note -The `Rename-PodeOADefinitionTagName` function cannot be used inside a `Select-PodeOADefinition` `[Scriptblock]`. Attempting to do so will result in an error. - - -### OpenAPI example - -A simple OpenAPI definition - -```powershell -Add-PodeOAInfo -Title 'Swagger Petstore - OpenAPI 3.0' -Version 1.0.17 -Description $InfoDescription -TermsOfService 'http://swagger.io/terms/' -LicenseName 'Apache 2.0' ` - -LicenseUrl 'http://www.apache.org/licenses/LICENSE-2.0.html' -ContactName 'API Support' -ContactEmail 'apiteam@swagger.io' -DefinitionTag 'v3' - -Add-PodeOAInfo -Title 'Swagger Petstore - OpenAPI 3.1' -Version 1.0.17 -Description $InfoDescription -TermsOfService 'http://swagger.io/terms/' -LicenseName 'Apache 2.0' ` - -LicenseUrl 'http://www.apache.org/licenses/LICENSE-2.0.html' -ContactName 'API Support' -ContactEmail 'apiteam@swagger.io' -DefinitionTag 'v3.1' - -Add-PodeOAServerEndpoint -url '/api/v3' -Description 'default endpoint' -DefinitionTag 'v3', 'v3.1' - -#OpenAPI 3.0 -Enable-PodeOAViewer -Type Swagger -Path '/docs/swagger' -DefinitionTag 'v3' -Enable-PodeOAViewer -Type Bookmarks -Path '/docs' -DefinitionTag 'v3' - -#OpenAPI 3.1 -Enable-PodeOAViewer -Type Swagger -Path '/docs/v3.1/swagger' -DefinitionTag 'v3.1' -Enable-PodeOAViewer -Type ReDoc -Path '/docs/v3.1/redoc' -DarkMode -DefinitionTag 'v3.1' -Enable-PodeOAViewer -Type Bookmarks -Path '/docs/v3.1' -DefinitionTag 'v3.1' - -Select-PodeOADefinition -Tag 'v3', 'v3.1' -ScriptBlock { - New-PodeOAIntProperty -Name 'id'-Format Int64 -Example 10 -Required | - New-PodeOAStringProperty -Name 'name' -Example 'doggie' -Required | - New-PodeOASchemaProperty -Name 'category' -Reference 'Category' | - New-PodeOAStringProperty -Name 'photoUrls' -Array -XmlWrapped -XmlItemName 'photoUrl' -Required | - New-PodeOASchemaProperty -Name 'tags' -Reference 'Tag' -Array -XmlWrapped | - New-PodeOAStringProperty -Name 'status' -Description 'pet status in the store' -Enum @('available', 'pending', 'sold') | - New-PodeOAObjectProperty -XmlName 'pet' | - Add-PodeOAComponentSchema -Name 'Pet' - - - Add-PodeRouteGroup -Path '/api/v3' -Routes { - Add-PodeRoute -PassThru -Method Put -Path '/pet' -Authentication 'merged_auth_nokey' -Scope 'write:pets', 'read:pets' -ScriptBlock { - #code - } | Set-PodeOARouteInfo -Summary 'Update an existing pet' -Description 'Update an existing pet by Id' -Tags 'pet' -OperationId 'updatePet' -PassThru | - Set-PodeOARequest -RequestBody ( - New-PodeOARequestBody -Description 'Update an existent pet in the store' -Required -Content ( - New-PodeOAContentMediaType -ContentMediaType 'application/json', 'application/xml' -Content 'Pet' ) - ) -PassThru | - Add-PodeOAResponse -StatusCode 200 -Description 'Successful operation' -Content (New-PodeOAContentMediaType -ContentMediaType 'application/json', 'application/xml' -Content 'Pet' ) -PassThru | - Add-PodeOAResponse -StatusCode 400 -Description 'Invalid ID supplied' -PassThru | - Add-PodeOAResponse -StatusCode 404 -Description 'Pet not found' -PassThru | - Add-PodeOAResponse -StatusCode 405 -Description 'Validation exception' - } -} -``` From e824cb1b2e6a7729b3219baa712e3265ab3353b9 Mon Sep 17 00:00:00 2001 From: mdaneri Date: Sat, 13 Jul 2024 22:39:56 -0700 Subject: [PATCH 10/10] Renamed Rename-PodeOADefinitionTagName to Rename-PodeOADefinitionTag --- src/Locales/ar/Pode.psd1 | 2 +- src/Locales/de/Pode.psd1 | 2 +- src/Locales/en-us/Pode.psd1 | 2 +- src/Locales/en/Pode.psd1 | 2 +- src/Locales/es/Pode.psd1 | 2 +- src/Locales/fr/Pode.psd1 | 2 +- src/Locales/it/Pode.psd1 | 2 +- src/Locales/ja/Pode.psd1 | 2 +- src/Locales/ko/Pode.psd1 | 2 +- src/Locales/pl/Pode.psd1 | 2 +- src/Locales/pt/Pode.psd1 | 2 +- src/Locales/zh/Pode.psd1 | 2 +- src/Pode.psd1 | 2 +- src/Public/OpenApi.ps1 | 8 ++++---- tests/unit/OpenApi.Tests.ps1 | 10 +++++----- 15 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/Locales/ar/Pode.psd1 b/src/Locales/ar/Pode.psd1 index 252dca504..995db9c2a 100644 --- a/src/Locales/ar/Pode.psd1 +++ b/src/Locales/ar/Pode.psd1 @@ -284,5 +284,5 @@ requestLoggingAlreadyEnabledExceptionMessage = 'تم تمكين تسجيل الطلبات بالفعل.' invalidAccessControlMaxAgeDurationExceptionMessage = 'مدة Access-Control-Max-Age غير صالحة المقدمة: {0}. يجب أن تكون أكبر من 0.' openApiDefinitionAlreadyExistsExceptionMessage = 'تعريف OpenAPI باسم {0} موجود بالفعل.' - renamePodeOADefinitionTagNameExceptionMessage = "لا يمكن استخدام Rename-PodeOADefinitionTagName داخل Select-PodeOADefinition 'ScriptBlock'." + renamePodeOADefinitionTagExceptionMessage = "لا يمكن استخدام Rename-PodeOADefinitionTag داخل Select-PodeOADefinition 'ScriptBlock'." } diff --git a/src/Locales/de/Pode.psd1 b/src/Locales/de/Pode.psd1 index 2a11af441..1a0dc69c1 100644 --- a/src/Locales/de/Pode.psd1 +++ b/src/Locales/de/Pode.psd1 @@ -284,5 +284,5 @@ requestLoggingAlreadyEnabledExceptionMessage = 'Die Anforderungsprotokollierung wurde bereits aktiviert.' invalidAccessControlMaxAgeDurationExceptionMessage = 'Ungültige Access-Control-Max-Age-Dauer angegeben: {0}. Sollte größer als 0 sein.' openApiDefinitionAlreadyExistsExceptionMessage = 'Die OpenAPI-Definition mit dem Namen {0} existiert bereits.' - renamePodeOADefinitionTagNameExceptionMessage = "Rename-PodeOADefinitionTagName kann nicht innerhalb eines 'ScriptBlock' von Select-PodeOADefinition verwendet werden." + renamePodeOADefinitionTagExceptionMessage = "Rename-PodeOADefinitionTag kann nicht innerhalb eines 'ScriptBlock' von Select-PodeOADefinition verwendet werden." } \ No newline at end of file diff --git a/src/Locales/en-us/Pode.psd1 b/src/Locales/en-us/Pode.psd1 index e8a1d57ae..11e13dd1b 100644 --- a/src/Locales/en-us/Pode.psd1 +++ b/src/Locales/en-us/Pode.psd1 @@ -284,5 +284,5 @@ requestLoggingAlreadyEnabledExceptionMessage = 'Request Logging has already been enabled.' invalidAccessControlMaxAgeDurationExceptionMessage = 'Invalid Access-Control-Max-Age duration supplied: {0}. Should be greater than 0.' openApiDefinitionAlreadyExistsExceptionMessage = 'OpenAPI definition named {0} already exists.' - renamePodeOADefinitionTagNameExceptionMessage = "Rename-PodeOADefinitionTagName cannot be used inside a Select-PodeOADefinition 'ScriptBlock'." + renamePodeOADefinitionTagExceptionMessage = "Rename-PodeOADefinitionTag cannot be used inside a Select-PodeOADefinition 'ScriptBlock'." } \ No newline at end of file diff --git a/src/Locales/en/Pode.psd1 b/src/Locales/en/Pode.psd1 index 079d5f852..8fb179a1b 100644 --- a/src/Locales/en/Pode.psd1 +++ b/src/Locales/en/Pode.psd1 @@ -284,6 +284,6 @@ requestLoggingAlreadyEnabledExceptionMessage = 'Request Logging has already been enabled.' invalidAccessControlMaxAgeDurationExceptionMessage = 'Invalid Access-Control-Max-Age duration supplied: {0}. Should be greater than 0.' openApiDefinitionAlreadyExistsExceptionMessage = 'OpenAPI definition named {0} already exists.' - renamePodeOADefinitionTagNameExceptionMessage = "Rename-PodeOADefinitionTagName cannot be used inside a Select-PodeOADefinition 'ScriptBlock'." + renamePodeOADefinitionTagExceptionMessage = "Rename-PodeOADefinitionTag cannot be used inside a Select-PodeOADefinition 'ScriptBlock'." } diff --git a/src/Locales/es/Pode.psd1 b/src/Locales/es/Pode.psd1 index 0ad047839..bb40ae833 100644 --- a/src/Locales/es/Pode.psd1 +++ b/src/Locales/es/Pode.psd1 @@ -284,6 +284,6 @@ requestLoggingAlreadyEnabledExceptionMessage = 'El registro de solicitudes ya está habilitado.' invalidAccessControlMaxAgeDurationExceptionMessage = 'Duración inválida para Access-Control-Max-Age proporcionada: {0}. Debe ser mayor que 0.' openApiDefinitionAlreadyExistsExceptionMessage = 'La definición de OpenAPI con el nombre {0} ya existe.' - renamePodeOADefinitionTagNameExceptionMessage = "Rename-PodeOADefinitionTagName no se puede usar dentro de un 'ScriptBlock' de Select-PodeOADefinition." + renamePodeOADefinitionTagExceptionMessage = "Rename-PodeOADefinitionTag no se puede usar dentro de un 'ScriptBlock' de Select-PodeOADefinition." } diff --git a/src/Locales/fr/Pode.psd1 b/src/Locales/fr/Pode.psd1 index 92dd448b7..5f34d865f 100644 --- a/src/Locales/fr/Pode.psd1 +++ b/src/Locales/fr/Pode.psd1 @@ -284,6 +284,6 @@ requestLoggingAlreadyEnabledExceptionMessage = 'La journalisation des requêtes est déjà activée.' invalidAccessControlMaxAgeDurationExceptionMessage = 'Durée Access-Control-Max-Age invalide fournie : {0}. Doit être supérieure à 0.' openApiDefinitionAlreadyExistsExceptionMessage = 'La définition OpenAPI nommée {0} existe déjà.' - renamePodeOADefinitionTagNameExceptionMessage = "Rename-PodeOADefinitionTagName ne peut pas être utilisé à l'intérieur d'un 'ScriptBlock' de Select-PodeOADefinition." + renamePodeOADefinitionTagExceptionMessage = "Rename-PodeOADefinitionTag ne peut pas être utilisé à l'intérieur d'un 'ScriptBlock' de Select-PodeOADefinition." } diff --git a/src/Locales/it/Pode.psd1 b/src/Locales/it/Pode.psd1 index 7a865dce9..6008eba78 100644 --- a/src/Locales/it/Pode.psd1 +++ b/src/Locales/it/Pode.psd1 @@ -284,5 +284,5 @@ requestLoggingAlreadyEnabledExceptionMessage = 'La registrazione delle richieste è già abilitata.' invalidAccessControlMaxAgeDurationExceptionMessage = 'Durata non valida fornita per Access-Control-Max-Age: {0}. Deve essere maggiore di 0.' openApiDefinitionAlreadyExistsExceptionMessage = 'La definizione OpenAPI denominata {0} esiste già.' - renamePodeOADefinitionTagNameExceptionMessage = "Rename-PodeOADefinitionTagName non può essere utilizzato all'interno di un 'ScriptBlock' di Select-PodeOADefinition." + renamePodeOADefinitionTagExceptionMessage = "Rename-PodeOADefinitionTag non può essere utilizzato all'interno di un 'ScriptBlock' di Select-PodeOADefinition." } \ No newline at end of file diff --git a/src/Locales/ja/Pode.psd1 b/src/Locales/ja/Pode.psd1 index f20c56401..9e94e26b0 100644 --- a/src/Locales/ja/Pode.psd1 +++ b/src/Locales/ja/Pode.psd1 @@ -284,5 +284,5 @@ requestLoggingAlreadyEnabledExceptionMessage = 'リクエストロギングは既に有効になっています。' invalidAccessControlMaxAgeDurationExceptionMessage = '無効な Access-Control-Max-Age 期間が提供されました:{0}。0 より大きくする必要があります。' openApiDefinitionAlreadyExistsExceptionMessage = '名前が {0} の OpenAPI 定義は既に存在します。' - renamePodeOADefinitionTagNameExceptionMessage = "Rename-PodeOADefinitionTagName は Select-PodeOADefinition 'ScriptBlock' 内で使用できません。" + renamePodeOADefinitionTagExceptionMessage = "Rename-PodeOADefinitionTag は Select-PodeOADefinition 'ScriptBlock' 内で使用できません。" } diff --git a/src/Locales/ko/Pode.psd1 b/src/Locales/ko/Pode.psd1 index c718999f0..6b959cc05 100644 --- a/src/Locales/ko/Pode.psd1 +++ b/src/Locales/ko/Pode.psd1 @@ -284,5 +284,5 @@ requestLoggingAlreadyEnabledExceptionMessage = '요청 로깅이 이미 활성화되었습니다.' invalidAccessControlMaxAgeDurationExceptionMessage = '잘못된 Access-Control-Max-Age 기간이 제공되었습니다: {0}. 0보다 커야 합니다.' openApiDefinitionAlreadyExistsExceptionMessage = '이름이 {0}인 OpenAPI 정의가 이미 존재합니다.' - renamePodeOADefinitionTagNameExceptionMessage = "Rename-PodeOADefinitionTagName은 Select-PodeOADefinition 'ScriptBlock' 내에서 사용할 수 없습니다." + renamePodeOADefinitionTagExceptionMessage = "Rename-PodeOADefinitionTag은 Select-PodeOADefinition 'ScriptBlock' 내에서 사용할 수 없습니다." } diff --git a/src/Locales/pl/Pode.psd1 b/src/Locales/pl/Pode.psd1 index 5f11f96f1..3926ef69b 100644 --- a/src/Locales/pl/Pode.psd1 +++ b/src/Locales/pl/Pode.psd1 @@ -284,5 +284,5 @@ requestLoggingAlreadyEnabledExceptionMessage = 'Rejestrowanie żądań jest już włączone.' invalidAccessControlMaxAgeDurationExceptionMessage = 'Podano nieprawidłowy czas trwania Access-Control-Max-Age: {0}. Powinien być większy niż 0.' openApiDefinitionAlreadyExistsExceptionMessage = 'Definicja OpenAPI o nazwie {0} już istnieje.' - renamePodeOADefinitionTagNameExceptionMessage = "Rename-PodeOADefinitionTagName nie może być używany wewnątrz 'ScriptBlock' Select-PodeOADefinition." + renamePodeOADefinitionTagExceptionMessage = "Rename-PodeOADefinitionTag nie może być używany wewnątrz 'ScriptBlock' Select-PodeOADefinition." } diff --git a/src/Locales/pt/Pode.psd1 b/src/Locales/pt/Pode.psd1 index e8c9feb0e..71dc5c425 100644 --- a/src/Locales/pt/Pode.psd1 +++ b/src/Locales/pt/Pode.psd1 @@ -284,5 +284,5 @@ requestLoggingAlreadyEnabledExceptionMessage = 'O registro de solicitações já está habilitado.' invalidAccessControlMaxAgeDurationExceptionMessage = 'Duração inválida fornecida para Access-Control-Max-Age: {0}. Deve ser maior que 0.' openApiDefinitionAlreadyExistsExceptionMessage = 'A definição OpenAPI com o nome {0} já existe.' - renamePodeOADefinitionTagNameExceptionMessage = "Rename-PodeOADefinitionTagName não pode ser usado dentro de um 'ScriptBlock' Select-PodeOADefinition." + renamePodeOADefinitionTagExceptionMessage = "Rename-PodeOADefinitionTag não pode ser usado dentro de um 'ScriptBlock' Select-PodeOADefinition." } \ No newline at end of file diff --git a/src/Locales/zh/Pode.psd1 b/src/Locales/zh/Pode.psd1 index 0b8c012d6..027f95c9d 100644 --- a/src/Locales/zh/Pode.psd1 +++ b/src/Locales/zh/Pode.psd1 @@ -284,6 +284,6 @@ requestLoggingAlreadyEnabledExceptionMessage = '请求日志记录已启用。' invalidAccessControlMaxAgeDurationExceptionMessage = '提供的 Access-Control-Max-Age 时长无效:{0}。应大于 0。' openApiDefinitionAlreadyExistsExceptionMessage = '名为 {0} 的 OpenAPI 定义已存在。' - renamePodeOADefinitionTagNameExceptionMessage = "Rename-PodeOADefinitionTagName 不能在 Select-PodeOADefinition 'ScriptBlock' 内使用。" + renamePodeOADefinitionTagExceptionMessage = "Rename-PodeOADefinitionTag 不能在 Select-PodeOADefinition 'ScriptBlock' 内使用。" } diff --git a/src/Pode.psd1 b/src/Pode.psd1 index d0295957c..eae7d8c44 100644 --- a/src/Pode.psd1 +++ b/src/Pode.psd1 @@ -313,7 +313,7 @@ 'New-PodeOARequestBody', 'Test-PodeOADefinitionTag', 'Test-PodeOADefinition', - 'Rename-PodeOADefinitionTagName', + 'Rename-PodeOADefinitionTag', # properties 'New-PodeOAIntProperty', diff --git a/src/Public/OpenApi.ps1 b/src/Public/OpenApi.ps1 index b71c20032..206f5c1d4 100644 --- a/src/Public/OpenApi.ps1 +++ b/src/Public/OpenApi.ps1 @@ -3441,12 +3441,12 @@ The current tag name of the OpenAPI definition. If not specified, the default de The new tag name for the OpenAPI definition. This parameter is mandatory. .EXAMPLE -Rename-PodeOADefinitionTagName -Tag 'oldTag' -NewTag 'newTag' +Rename-PodeOADefinitionTag -Tag 'oldTag' -NewTag 'newTag' Rename a specific OpenAPI definition tag .EXAMPLE -Rename-PodeOADefinitionTagName -NewTag 'newDefaultTag' +Rename-PodeOADefinitionTag -NewTag 'newDefaultTag' Rename the default OpenAPI definition tag @@ -3456,7 +3456,7 @@ This function will throw an error if: - The new tag name already exists. - The current tag name does not exist. #> -function Rename-PodeOADefinitionTagName { +function Rename-PodeOADefinitionTag { param ( [Parameter(Mandatory = $false)] [string]$Tag, @@ -3466,7 +3466,7 @@ function Rename-PodeOADefinitionTagName { # Check if the function is being used inside a Select-PodeOADefinition ScriptBlock if ($PodeContext.Server.OpenApi.DefinitionTagSelectionStack.Count -gt 0) { - throw ($PodeLocale.renamePodeOADefinitionTagNameExceptionMessage) + throw ($PodeLocale.renamePodeOADefinitionTagExceptionMessage) } # Check if the new tag name already exists in the OpenAPI definitions diff --git a/tests/unit/OpenApi.Tests.ps1 b/tests/unit/OpenApi.Tests.ps1 index 2c06adef8..18a082756 100644 --- a/tests/unit/OpenApi.Tests.ps1 +++ b/tests/unit/OpenApi.Tests.ps1 @@ -3035,7 +3035,7 @@ Describe 'OpenApi' { } } - Describe 'Rename-PodeOADefinitionTagName' { + Describe 'Rename-PodeOADefinitionTag' { # Mocking the PodeContext to simulate the environment BeforeEach { $PodeContext = @{ @@ -3061,7 +3061,7 @@ Describe 'OpenApi' { # Test case: Renaming a specific tag It 'Renames a specific OpenAPI definition tag' { - Rename-PodeOADefinitionTagName -Tag 'oldTag' -NewTag 'newTag' + Rename-PodeOADefinitionTag -Tag 'oldTag' -NewTag 'newTag' # Check if the new tag exists $PodeContext.Server.OpenAPI.Definitions.ContainsKey('newTag') | Should -BeTrue @@ -3073,7 +3073,7 @@ Describe 'OpenApi' { # Test case: Renaming the default tag It 'Renames the default OpenAPI definition tag when Tag parameter is not specified' { - Rename-PodeOADefinitionTagName -NewTag 'newDefaultTag' + Rename-PodeOADefinitionTag -NewTag 'newDefaultTag' # Check if the new default tag is set $PodeContext.Server.Web.OpenApi.DefaultDefinitionTag | Should -Be 'newDefaultTag' @@ -3090,14 +3090,14 @@ Describe 'OpenApi' { Description = 'Existing tag description' } - { Rename-PodeOADefinitionTagName -Tag 'oldTag' -NewTag 'existingTag' } | Should -Throw -ExpectedMessage ($PodeLocale.openApiDefinitionAlreadyExistsExceptionMessage -f 'existingTag') + { Rename-PodeOADefinitionTag -Tag 'oldTag' -NewTag 'existingTag' } | Should -Throw -ExpectedMessage ($PodeLocale.openApiDefinitionAlreadyExistsExceptionMessage -f 'existingTag') } # Test case: Error when used inside Select-PodeOADefinition ScriptBlock It 'Throws an error when used inside a Select-PodeOADefinition ScriptBlock' { $PodeContext.Server.OpenApi.DefinitionTagSelectionStack.Push('dummy') - { Rename-PodeOADefinitionTagName -Tag 'oldTag' -NewTag 'newTag' } | Should -Throw -ExpectedMessage ($PodeLocale.renamePodeOADefinitionTagNameExceptionMessage) + { Rename-PodeOADefinitionTag -Tag 'oldTag' -NewTag 'newTag' } | Should -Throw -ExpectedMessage ($PodeLocale.renamePodeOADefinitionTagExceptionMessage) # Clear the stack after test $PodeContext.Server.OpenApi.DefinitionTagSelectionStack.Clear()