Skip to content

Commit d179b28

Browse files
committed
feat: flag to allow converting from yaml to json pre validation
1 parent bde0446 commit d179b28

File tree

4 files changed

+67
-8
lines changed

4 files changed

+67
-8
lines changed

README.md

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,12 @@ go get github.com/pb33f/libopenapi-validator
3131
## Validate OpenAPI Document
3232

3333
```bash
34-
go run github.com/pb33f/libopenapi-validator/cmd/validate@latest [--regexengine] <file>
34+
go run github.com/pb33f/libopenapi-validator/cmd/validate@latest [--regexengine] [--yaml2json] <file>
3535
```
36+
37+
### Options
38+
39+
#### --regexengine
3640
🔍 Example: Use a custom regex engine/flag (e.g., ecmascript)
3741
```bash
3842
go run github.com/pb33f/libopenapi-validator/cmd/validate@latest --regexengine=ecmascript <file>
@@ -51,6 +55,26 @@ go run github.com/pb33f/libopenapi-validator/cmd/validate@latest --regexengine=e
5155
- re2
5256
- unicode
5357

58+
#### --yaml2json
59+
🔍 Convert YAML files to JSON before validation (ℹ️ Default: false)
60+
61+
[libopenapi](https://github.com/pb33f/libopenapi/blob/main/datamodel/spec_info.go#L115) passes `map[interface{}]interface{}` structures for deeply nested objects or complex mappings in the OpenAPI specification, which are not allowed in JSON.
62+
These structures cannot be properly converted to JSON by libopenapi and cannot be validated by jsonschema, resulting in ambiguous errors.
63+
64+
This flag allows pre-converting from YAML to JSON to bypass this limitation of the libopenapi.
65+
66+
**When does this happen?**
67+
- OpenAPI specs with deeply nested schema definitions
68+
- Complex `allOf`, `oneOf`, or `anyOf` structures with multiple levels
69+
- Specifications with intricate object mappings in examples or schema properties
70+
71+
Enabling this flag pre-converts the YAML document from YAML to JSON, ensuring a clean JSON structure before validation.
72+
73+
Example:
74+
```bash
75+
go run github.com/pb33f/libopenapi-validator/cmd/validate@latest --yaml2json <file>
76+
```
77+
5478
## Documentation
5579

5680
- [The structure of the validator](https://pb33f.io/libopenapi/validation/#the-structure-of-the-validator)

cmd/validate/main.go

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"os"
99

1010
"github.com/dlclark/regexp2"
11+
"github.com/goccy/go-yaml"
1112
"github.com/pb33f/libopenapi"
1213
"github.com/santhosh-tekuri/jsonschema/v6"
1314

@@ -64,13 +65,19 @@ var (
6465
If not specified, the default libopenapi option is "re2".
6566
6667
If not specified, the default libopenapi regex engine is "re2"".`)
68+
convertYAMLToJSON = flag.Bool("yaml2json", false, `Convert YAML files to JSON before validation.
69+
libopenapi passes map[interface{}]interface{} structures for deeply nested objects
70+
or complex mappings, which are not allowed in JSON and cannot be validated by jsonschema.
71+
This flag allows pre-converting from YAML to JSON to bypass this limitation of the libopenapi.
72+
Default is false.`)
6773
)
6874

6975
// main is the entry point for validating an OpenAPI Specification (OAS) document.
7076
// It uses the libopenapi-validator library to check if the provided OAS document
7177
// conforms to the OpenAPI specification.
7278
//
73-
// This tool accepts a single input file (YAML or JSON) and provides an optional
79+
// This tool accepts a single input file (YAML or JSON) and provides optional flags:
80+
//
7481
// `--regexengine` flag to customize the regex engine used during validation.
7582
// This is useful for cases where the spec uses regex patterns that require engines
7683
// like ECMAScript or RE2.
@@ -80,9 +87,16 @@ If not specified, the default libopenapi regex engine is "re2"".`)
8087
// - Flags: ignorecase, multiline, explicitcapture, compiled, singleline,
8188
// ignorepatternwhitespace, righttoleft, debug, unicode
8289
//
90+
// `--yaml2json` flag to convert YAML files to JSON before validation.
91+
// libopenapi passes map[interface{}]interface{} structures for deeply nested
92+
// objects or complex mappings, which are not allowed in JSON and cannot be
93+
// validated by jsonschema. This flag allows pre-converting from YAML to JSON
94+
// to bypass this limitation of the libopenapi. Default is false.
95+
//
8396
// Example usage:
8497
//
8598
// go run main.go --regexengine=ecmascript ./my-api-spec.yaml
99+
// go run main.go --yaml2json ./my-api-spec.yaml
86100
//
87101
// If validation passes, the tool logs a success message.
88102
// If the document is invalid or there is a processing error, it logs details and exits non-zero.
@@ -94,13 +108,21 @@ Validates an OpenAPI document using libopenapi-validator.
94108
95109
Options:
96110
--regexengine string Specify the regex parsing option to use.
97-
Supported values are:
111+
Supported values are:
98112
Engines: re2 (default), ecmascript
99-
Flags: ignorecase, multiline, explicitcapture, compiled,
100-
singleline, ignorepatternwhitespace, righttoleft,
113+
Flags: ignorecase, multiline, explicitcapture, compiled,
114+
singleline, ignorepatternwhitespace, righttoleft,
101115
debug, unicode
102116
If not specified, the default libopenapi option is "re2".
103117
118+
--yaml2json Convert YAML files to JSON before validation.
119+
libopenapi passes map[interface{}]interface{}
120+
structures for deeply nested objects or complex mappings, which
121+
are not allowed in JSON and cannot be validated by jsonschema.
122+
This flag allows pre-converting from YAML to JSON to bypass this
123+
limitation of the libopenapi.
124+
(default: false)
125+
104126
-h, --help Show this help message and exit.
105127
`)
106128
}
@@ -156,6 +178,17 @@ Options:
156178
os.Exit(1)
157179
}
158180

181+
if *convertYAMLToJSON {
182+
var v interface{}
183+
if err := yaml.Unmarshal(data, &v); err == nil {
184+
data, err = yaml.YAMLToJSON(data)
185+
if err != nil {
186+
logger.Error("invalid api spec: error converting yaml to json", slog.Any("error", err))
187+
os.Exit(1)
188+
}
189+
}
190+
}
191+
159192
doc, err := libopenapi.NewDocument(data)
160193
if err != nil {
161194
logger.Error("error creating new libopenapi document", slog.Any("error", err))

go.mod

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ module github.com/pb33f/libopenapi-validator
33
go 1.24.7
44

55
require (
6+
github.com/basgys/goxml2json v1.1.1-0.20231018121955-e66ee54ceaad
67
github.com/dlclark/regexp2 v1.11.5
8+
github.com/goccy/go-yaml v1.18.0
79
github.com/pb33f/jsonpath v0.1.2
810
github.com/pb33f/libopenapi v0.28.1
911
github.com/santhosh-tekuri/jsonschema/v6 v6.0.2
@@ -14,7 +16,6 @@ require (
1416

1517
require (
1618
github.com/bahlo/generic-list-go v0.2.0 // indirect
17-
github.com/basgys/goxml2json v1.1.1-0.20231018121955-e66ee54ceaad // indirect
1819
github.com/buger/jsonparser v1.1.1 // indirect
1920
github.com/davecgh/go-spew v1.1.1 // indirect
2021
github.com/pb33f/ordered-map/v2 v2.3.0 // indirect

go.sum

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk=
22
github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg=
3-
github.com/basgys/goxml2json v1.1.0 h1:4ln5i4rseYfXNd86lGEB+Vi652IsIXIvggKM/BhUKVw=
4-
github.com/basgys/goxml2json v1.1.0/go.mod h1:wH7a5Np/Q4QoECFIU8zTQlZwZkrilY0itPfecMw41Dw=
53
github.com/basgys/goxml2json v1.1.1-0.20231018121955-e66ee54ceaad h1:3swAvbzgfaI6nKuDDU7BiKfZRdF+h2ZwKgMHd8Ha4t8=
64
github.com/basgys/goxml2json v1.1.1-0.20231018121955-e66ee54ceaad/go.mod h1:9+nBLYNWkvPcq9ep0owWUsPTLgL9ZXTsZWcCSVGGLJ0=
5+
github.com/bitly/go-simplejson v0.5.1 h1:xgwPbetQScXt1gh9BmoJ6j9JMr3TElvuIyjR8pgdoow=
76
github.com/bitly/go-simplejson v0.5.1/go.mod h1:YOPVLzCfwK14b4Sff3oP1AmGhI9T9Vsg84etUnlyp+Q=
87
github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs=
98
github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
@@ -12,6 +11,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
1211
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
1312
github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZQ=
1413
github.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
14+
github.com/goccy/go-yaml v1.18.0 h1:8W7wMFS12Pcas7KU+VVkaiCng+kG8QiFeFwzFb+rwuw=
15+
github.com/goccy/go-yaml v1.18.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
1516
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
1617
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
1718
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=

0 commit comments

Comments
 (0)