Public/Import-OpenApiDocument.ps1
|
<# .SYNOPSIS Reads an OpenAPI 3.0/3.1 or Swagger 2.0 document and returns the normalised document model. .DESCRIPTION Import-OpenApiDocument loads a document from a file, a URL or a string, detects its version and returns one OpenAPI 3-shaped model (PSTypeName Tcs.OpenApi.Document) whatever the input version: Title, Version, Description, Servers, SecuritySchemes, Security, Schemas, Operations and Findings. - JSON is always supported. YAML needs ConvertFrom-Yaml from the powershell-yaml module; without it the command stops with an error that says so. - Swagger 2.0 documents are converted: host/basePath/schemes become Servers, definitions become Schemas, body and formData parameters become a RequestBody, collectionFormat becomes style/explode and securityDefinitions become SecuritySchemes. - Local $refs are resolved (circular schemas are marked Recursive); external $refs are reported and the operations that use them are flagged Unsupported. - Problems met while normalising are returned in the model's Findings (see Test-OpenApiDocument). The model is plain data (PSCustomObject, ordered dictionaries and arrays), so it can be saved with ConvertTo-Json -Depth 100. .PARAMETER Path Path of a .json, .yaml or .yml document. .PARAMETER Uri Absolute URL of the document. It is downloaded with Invoke-WebRequest; relative server URLs in the document are resolved against it. .PARAMETER InputObject The document text (JSON or YAML). .EXAMPLE $doc = Import-OpenApiDocument -Path ./petstore.json $doc.Operations | Select-Object OperationId, Method, Path Loads a local document and lists its operations. .EXAMPLE Import-OpenApiDocument -Uri 'https://petstore3.swagger.io/api/v3/openapi.json' | Select-Object -ExpandProperty Findings Downloads a document and shows the problems found while normalising it. .EXAMPLE Get-ChildItem -Path ./specs -Filter *.json | Import-OpenApiDocument Imports every JSON document in a folder; Swagger 2.0 documents come back OpenAPI 3-shaped. .INPUTS System.IO.FileInfo Files (or any object with a FullName or Path property) through the pipeline. .OUTPUTS Tcs.OpenApi.Document The normalised document model. .NOTES Author: Nigel Tatschner Company: TheCodeSaiyan Stops with an error for input that cannot be read or parsed and for documents whose version is not 3.0.x, 3.1.x or Swagger 2.0 (finding OA001). All other problems are returned as findings. .LINK Test-OpenApiDocument .LINK New-OpenApiModule #> function Import-OpenApiDocument { [CmdletBinding(DefaultParameterSetName = 'Path')] [OutputType('Tcs.OpenApi.Document')] param( [Parameter(Mandatory, ParameterSetName = 'Path', ValueFromPipelineByPropertyName, HelpMessage = 'Path of a .json, .yaml or .yml document.')] [Alias('FullName')] [ValidateNotNullOrEmpty()] [string]$Path, [Parameter(Mandatory, ParameterSetName = 'Uri', HelpMessage = 'Absolute URL of the document.')] [ValidateNotNull()] [uri]$Uri, [Parameter(Mandatory, ParameterSetName = 'InputObject', HelpMessage = 'The document text (JSON or YAML).')] [AllowEmptyString()] [string]$InputObject ) begin { $telemetry = Start-TcsTelemetry $lastError = $null } process { $parameterSet = $PSCmdlet.ParameterSetName $completed = $false try { $readArguments = @{} $readArguments[$parameterSet] = Get-Variable -Name $parameterSet -ValueOnly $source = Get-OpenApiDocumentText @readArguments Write-Verbose "Reading OpenAPI document from '$($source.Source)'." $root = ConvertFrom-OpenApiText -Text $source.Text -Format $source.Format $model = ConvertTo-OpenApiDocumentModel -Root $root -BaseUri $source.BaseUri $versionFinding = @($model.Findings | Where-Object { $_.Code -eq 'OA001' }) | Select-Object -First 1 if ($null -ne $versionFinding) { $exception = New-Object -TypeName System.NotSupportedException -ArgumentList "$($source.Source): $($versionFinding.Message)" $record = New-Object -TypeName System.Management.Automation.ErrorRecord -ArgumentList $exception, 'OpenApi.UnsupportedVersion', ([System.Management.Automation.ErrorCategory]::InvalidData), $source.Source # ThrowTerminatingError skips the catch block below; only finally runs $lastError = $record $PSCmdlet.ThrowTerminatingError($record) } foreach ($finding in $model.Findings) { Write-Verbose "$($finding.Severity) $($finding.Code) $($finding.Pointer): $($finding.Message)" } $model $completed = $true } catch { $lastError = $_ throw } finally { # end does not run when a later command stops the pipeline (Select-Object -First) if (-not $completed) { Complete-TcsTelemetry -Token $telemetry -ErrorRecord $lastError } } } end { Complete-TcsTelemetry -Token $telemetry -ErrorRecord $lastError } } |