Build-LMFilterValidationConfig.ps1
|
<# .SYNOPSIS Development tool to generate filter field validation configuration from Swagger. .DESCRIPTION This script fetches the LogicMonitor public Swagger JSON endpoint and extracts API endpoints and their response schemas. It then maps each endpoint to the properties available in the response model, creating a validation configuration file that can be used at runtime to validate filter fields before sending API requests. .EXAMPLE .\Build-LMFilterValidationConfig.ps1 This will generate Private/LMFilterValidationConfig.psd1 with all endpoint-to-fields mappings. .NOTES This is a development-time tool and should be run whenever endpoint filter fields need to be refreshed from the latest public Swagger spec. #> [CmdletBinding()] param( [Parameter()] [String]$SwaggerUrl = 'https://www.logicmonitor.com/swagger-ui-master/api-v3/dist/swagger.json', [Parameter()] [String]$OutputPath = (Join-Path $PSScriptRoot 'Private/LMFilterValidationConfig.psd1') ) Write-Host "Fetching Swagger file: $SwaggerUrl" -ForegroundColor Cyan try { $Swagger = Invoke-RestMethod -Uri $SwaggerUrl -Method Get -ErrorAction Stop } catch { Write-Error "Failed to fetch Swagger from '$SwaggerUrl'. $($_.Exception.Message)" return } if (-not $Swagger.definitions -or -not $Swagger.paths) { Write-Error "Unexpected Swagger format. Expected Swagger 2.0 with 'definitions' and 'paths'." return } $Definitions = @{} foreach ($definitionProperty in $Swagger.definitions.PSObject.Properties) { $Definitions[$definitionProperty.Name] = $definitionProperty.Value } Write-Host "Extracting API endpoints and schemas..." -ForegroundColor Cyan # Build endpoint to schema mapping $EndpointToSchema = @{} $SchemaProperties = @{} function Get-SwaggerRefName { param( [Parameter(Mandatory)] [String]$RefPath ) if ($RefPath -match '^#/definitions/(?<name>.+)$') { return $Matches.name } return $null } function Get-SchemaPropertyNames { param( [Parameter(Mandatory)] [Object]$Schema, [Parameter(Mandatory)] [hashtable]$AllDefinitions, [Parameter()] [hashtable]$Visited = @{} ) $properties = @() if ($null -eq $Schema) { return $properties } if ($Schema.properties) { $properties += @($Schema.properties.PSObject.Properties.Name) } if ($Schema.allOf) { foreach ($allOfItem in $Schema.allOf) { if ($allOfItem.properties) { $properties += @($allOfItem.properties.PSObject.Properties.Name) } if ($allOfItem.'$ref') { $refSchemaName = Get-SwaggerRefName -RefPath $allOfItem.'$ref' if ($refSchemaName -and -not $Visited.ContainsKey($refSchemaName) -and $AllDefinitions.ContainsKey($refSchemaName)) { $Visited[$refSchemaName] = $true $properties += Get-SchemaPropertyNames -Schema $AllDefinitions[$refSchemaName] -AllDefinitions $AllDefinitions -Visited $Visited } } } } if ($Schema.'$ref') { $refSchemaName = Get-SwaggerRefName -RefPath $Schema.'$ref' if ($refSchemaName -and -not $Visited.ContainsKey($refSchemaName) -and $AllDefinitions.ContainsKey($refSchemaName)) { $Visited[$refSchemaName] = $true $properties += Get-SchemaPropertyNames -Schema $AllDefinitions[$refSchemaName] -AllDefinitions $AllDefinitions -Visited $Visited } } return @($properties | Sort-Object -Unique) } # First, extract all schema properties foreach ($schemaName in $Swagger.definitions.PSObject.Properties.Name) { $schema = $Definitions[$schemaName] $properties = Get-SchemaPropertyNames -Schema $schema -AllDefinitions $Definitions if ($properties.Count -gt 0) { $SchemaProperties[$schemaName] = $properties } } Write-Host "Found $($SchemaProperties.Count) schemas with properties" -ForegroundColor Green # Now map endpoints to their response schemas foreach ($path in $Swagger.paths.PSObject.Properties.Name) { $pathItem = $Swagger.paths.$path # We're primarily interested in GET endpoints for filtering if ($pathItem.get) { $getOp = $pathItem.get # Check if it has a filter parameter $hasFilter = $false $parameters = @($pathItem.parameters) + @($getOp.parameters) if ($parameters) { foreach ($param in $parameters) { if ($param.name -eq 'filter') { $hasFilter = $true break } } } if ($hasFilter) { # Extract the Swagger 2.0 response schema $responseSchema = $null if ($getOp.responses -and $getOp.responses.'200' -and $getOp.responses.'200'.schema) { $responseSchema = $getOp.responses.'200'.schema } if ($responseSchema -and $responseSchema.'$ref') { $responseSchemaName = Get-SwaggerRefName -RefPath $responseSchema.'$ref' if (-not $responseSchemaName) { continue } # For pagination responses, we need to get the items schema if ($responseSchemaName -match 'PaginationResponse$') { $paginationSchema = $Definitions[$responseSchemaName] if ($paginationSchema.properties.items.items.'$ref') { $itemsSchemaRef = $paginationSchema.properties.items.items.'$ref' $itemsSchemaName = Get-SwaggerRefName -RefPath $itemsSchemaRef if ($SchemaProperties[$itemsSchemaName]) { $EndpointToSchema[$path] = @{ Schema = $itemsSchemaName Properties = $SchemaProperties[$itemsSchemaName] } } } } # For non-pagination responses, use the schema directly elseif ($SchemaProperties[$responseSchemaName]) { $EndpointToSchema[$path] = @{ Schema = $responseSchemaName Properties = $SchemaProperties[$responseSchemaName] } } } } } } Write-Host "Mapped $($EndpointToSchema.Count) endpoints to schemas" -ForegroundColor Green # Build the final configuration hashtable $Config = @{} foreach ($endpoint in $EndpointToSchema.Keys | Sort-Object) { $properties = $EndpointToSchema[$endpoint].Properties $schema = $EndpointToSchema[$endpoint].Schema # Only include properties that actually exist in the schema # Don't add special properties if they're not defined in the API $Config[$endpoint] = $properties | Sort-Object -Unique Write-Verbose "Endpoint: $endpoint -> Schema: $schema -> Properties: $($properties.Count)" } # Generate the PSD1 file Write-Host "Generating configuration file: $OutputPath" -ForegroundColor Cyan $PSD1Content = @" <# .SYNOPSIS Filter field validation configuration generated from public Swagger JSON .DESCRIPTION This file contains a mapping of API endpoints to their valid filterable fields. It is automatically generated by Build-LMFilterValidationConfig.ps1 and should not be manually edited. Generated: $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') Swagger endpoints processed: $($EndpointToSchema.Count) Swagger URL: $SwaggerUrl .NOTES To regenerate this file, run: .\Build-LMFilterValidationConfig.ps1 #> @{ "@ foreach ($endpoint in $Config.Keys | Sort-Object) { $properties = $Config[$endpoint] $propertiesString = ($properties | ForEach-Object { "'$_'" }) -join ', ' $PSD1Content += "`n '$endpoint' = @($propertiesString)" } $PSD1Content += "`n}`n" # Write the file Set-Content -Path $OutputPath -Value $PSD1Content -Encoding UTF8 Write-Host "Successfully generated configuration file!" -ForegroundColor Green Write-Host " Endpoints: $($Config.Keys.Count)" -ForegroundColor Green Write-Host " Output: $OutputPath" -ForegroundColor Green # Display some sample mappings Write-Host "`nSample mappings:" -ForegroundColor Cyan $sampleEndpoints = @('/device/devices', '/device/groups', '/alert/alerts') | Where-Object { $Config[$_] } foreach ($endpoint in $sampleEndpoints) { Write-Host " $endpoint" -ForegroundColor Yellow Write-Host " Fields: $($Config[$endpoint] -join ', ')" -ForegroundColor Gray } |