44package schema_validation
55
66import (
7+ "bytes"
78 "encoding/json"
89 "errors"
910 "fmt"
@@ -29,14 +30,22 @@ func normalizeJSON(data any) any {
2930// ValidateOpenAPIDocument will validate an OpenAPI document against the OpenAPI 2, 3.0 and 3.1 schemas (depending on version)
3031// It will return true if the document is valid, false if it is not and a slice of ValidationError pointers.
3132func ValidateOpenAPIDocument (doc libopenapi.Document , opts ... config.Option ) (bool , []* liberrors.ValidationError ) {
33+ return ValidateOpenAPIDocumentWithPrecompiled (doc , nil , opts ... )
34+ }
35+
36+ // ValidateOpenAPIDocumentWithPrecompiled validates an OpenAPI document against the OAS JSON Schema.
37+ // When compiledSchema is non-nil it is used directly, skipping schema compilation.
38+ // When SpecJSONBytes is available on the document's SpecInfo, the normalizeJSON round-trip is
39+ // bypassed in favour of a single jsonschema.UnmarshalJSON call.
40+ func ValidateOpenAPIDocumentWithPrecompiled (doc libopenapi.Document , compiledSchema * jsonschema.Schema , opts ... config.Option ) (bool , []* liberrors.ValidationError ) {
3241 options := config .NewValidationOptions (opts ... )
3342
3443 info := doc .GetSpecInfo ()
3544 loadedSchema := info .APISchema
3645 var validationErrors []* liberrors.ValidationError
3746
38- // Check if SpecJSON is nil before dereferencing
39- if info .SpecJSON == nil {
47+ // Check if both JSON representations are nil before proceeding
48+ if info .SpecJSON == nil && info . SpecJSONBytes == nil {
4049 validationErrors = append (validationErrors , & liberrors.ValidationError {
4150 ValidationType : helpers .Schema ,
4251 ValidationSubType : "document" ,
@@ -50,27 +59,44 @@ func ValidateOpenAPIDocument(doc libopenapi.Document, opts ...config.Option) (bo
5059 return false , validationErrors
5160 }
5261
53- decodedDocument := * info .SpecJSON
62+ // Use the precompiled schema if provided, otherwise compile it
63+ jsch := compiledSchema
64+ if jsch == nil {
65+ var err error
66+ jsch , err = helpers .NewCompiledSchema ("schema" , []byte (loadedSchema ), options )
67+ if err != nil {
68+ validationErrors = append (validationErrors , & liberrors.ValidationError {
69+ ValidationType : helpers .Schema ,
70+ ValidationSubType : "compilation" ,
71+ Message : "OpenAPI document schema compilation failed" ,
72+ Reason : fmt .Sprintf ("The OpenAPI schema failed to compile: %s" , err .Error ()),
73+ SpecLine : 1 ,
74+ SpecCol : 0 ,
75+ HowToFix : "check the OpenAPI schema for invalid JSON Schema syntax, complex regex patterns, or unsupported schema constructs" ,
76+ Context : loadedSchema ,
77+ })
78+ return false , validationErrors
79+ }
80+ }
5481
55- // Compile the JSON Schema
56- jsch , err := helpers .NewCompiledSchema ("schema" , []byte (loadedSchema ), options )
57- if err != nil {
58- // schema compilation failed, return validation error instead of panicking
59- validationErrors = append (validationErrors , & liberrors.ValidationError {
60- ValidationType : helpers .Schema ,
61- ValidationSubType : "compilation" ,
62- Message : "OpenAPI document schema compilation failed" ,
63- Reason : fmt .Sprintf ("The OpenAPI schema failed to compile: %s" , err .Error ()),
64- SpecLine : 1 ,
65- SpecCol : 0 ,
66- HowToFix : "check the OpenAPI schema for invalid JSON Schema syntax, complex regex patterns, or unsupported schema constructs" ,
67- Context : loadedSchema ,
68- })
69- return false , validationErrors
82+ // Build the normalized document value for validation.
83+ // Prefer SpecJSONBytes (single unmarshal) over SpecJSON (marshal+unmarshal round-trip).
84+ var normalized any
85+ if info .SpecJSONBytes != nil && len (* info .SpecJSONBytes ) > 0 {
86+ var err error
87+ normalized , err = jsonschema .UnmarshalJSON (bytes .NewReader (* info .SpecJSONBytes ))
88+ if err != nil {
89+ // Fall back to normalizeJSON if UnmarshalJSON fails
90+ if info .SpecJSON != nil {
91+ normalized = normalizeJSON (* info .SpecJSON )
92+ }
93+ }
94+ } else if info .SpecJSON != nil {
95+ normalized = normalizeJSON (* info .SpecJSON )
7096 }
7197
7298 // Validate the document
73- scErrs := jsch .Validate (normalizeJSON ( decodedDocument ) )
99+ scErrs := jsch .Validate (normalized )
74100
75101 var schemaValidationErrors []* liberrors.SchemaValidationFailure
76102
0 commit comments