diff --git a/openapi3/callback.go b/openapi3/callback.go index 39a5955cd..bf5dc83dc 100644 --- a/openapi3/callback.go +++ b/openapi3/callback.go @@ -2,29 +2,9 @@ package openapi3 import ( "context" - "fmt" "sort" - - "github.com/go-openapi/jsonpointer" ) -type Callbacks map[string]*CallbackRef - -var _ jsonpointer.JSONPointable = (*Callbacks)(nil) - -// JSONLookup implements https://pkg.go.dev/github.com/go-openapi/jsonpointer#JSONPointable -func (c Callbacks) JSONLookup(token string) (interface{}, error) { - ref, ok := c[token] - if ref == nil || !ok { - return nil, fmt.Errorf("object has no field %q", token) - } - - if ref.Ref != "" { - return &Ref{Ref: ref.Ref}, nil - } - return ref.Value, nil -} - // Callback is specified by OpenAPI/Swagger standard version 3. // See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#callback-object type Callback map[string]*PathItem diff --git a/openapi3/components.go b/openapi3/components.go index 5119e867e..656ea1936 100644 --- a/openapi3/components.go +++ b/openapi3/components.go @@ -5,6 +5,20 @@ import ( "encoding/json" "fmt" "sort" + + "github.com/go-openapi/jsonpointer" +) + +type ( + Callbacks map[string]*CallbackRef + Examples map[string]*ExampleRef + Headers map[string]*HeaderRef + Links map[string]*LinkRef + ParametersMap map[string]*ParameterRef + RequestBodies map[string]*RequestBodyRef + ResponseBodies map[string]*ResponseRef + Schemas map[string]*SchemaRef + SecuritySchemes map[string]*SecuritySchemeRef ) // Components is specified by OpenAPI/Swagger standard version 3. @@ -228,3 +242,120 @@ func (components *Components) Validate(ctx context.Context, opts ...ValidationOp return validateExtensions(ctx, components.Extensions) } + +var _ jsonpointer.JSONPointable = (*Schemas)(nil) + +// JSONLookup implements https://pkg.go.dev/github.com/go-openapi/jsonpointer#JSONPointable +func (m Schemas) JSONLookup(token string) (interface{}, error) { + if v, ok := m[token]; !ok || v == nil { + return nil, fmt.Errorf("no schema %q", token) + } else if ref := v.Ref; ref != "" { + return &Ref{Ref: ref}, nil + } else { + return v.Value, nil + } +} + +var _ jsonpointer.JSONPointable = (*ParametersMap)(nil) + +// JSONLookup implements https://pkg.go.dev/github.com/go-openapi/jsonpointer#JSONPointable +func (m ParametersMap) JSONLookup(token string) (interface{}, error) { + if v, ok := m[token]; !ok || v == nil { + return nil, fmt.Errorf("no parameter %q", token) + } else if ref := v.Ref; ref != "" { + return &Ref{Ref: ref}, nil + } else { + return v.Value, nil + } +} + +var _ jsonpointer.JSONPointable = (*Headers)(nil) + +// JSONLookup implements https://pkg.go.dev/github.com/go-openapi/jsonpointer#JSONPointable +func (m Headers) JSONLookup(token string) (interface{}, error) { + if v, ok := m[token]; !ok || v == nil { + return nil, fmt.Errorf("no header %q", token) + } else if ref := v.Ref; ref != "" { + return &Ref{Ref: ref}, nil + } else { + return v.Value, nil + } +} + +var _ jsonpointer.JSONPointable = (*RequestBodyRef)(nil) + +// JSONLookup implements https://pkg.go.dev/github.com/go-openapi/jsonpointer#JSONPointable +func (m RequestBodies) JSONLookup(token string) (interface{}, error) { + if v, ok := m[token]; !ok || v == nil { + return nil, fmt.Errorf("no request body %q", token) + } else if ref := v.Ref; ref != "" { + return &Ref{Ref: ref}, nil + } else { + return v.Value, nil + } +} + +var _ jsonpointer.JSONPointable = (*ResponseRef)(nil) + +// JSONLookup implements https://pkg.go.dev/github.com/go-openapi/jsonpointer#JSONPointable +func (m ResponseBodies) JSONLookup(token string) (interface{}, error) { + if v, ok := m[token]; !ok || v == nil { + return nil, fmt.Errorf("no response body %q", token) + } else if ref := v.Ref; ref != "" { + return &Ref{Ref: ref}, nil + } else { + return v.Value, nil + } +} + +var _ jsonpointer.JSONPointable = (*SecuritySchemes)(nil) + +// JSONLookup implements https://pkg.go.dev/github.com/go-openapi/jsonpointer#JSONPointable +func (m SecuritySchemes) JSONLookup(token string) (interface{}, error) { + if v, ok := m[token]; !ok || v == nil { + return nil, fmt.Errorf("no security scheme body %q", token) + } else if ref := v.Ref; ref != "" { + return &Ref{Ref: ref}, nil + } else { + return v.Value, nil + } +} + +var _ jsonpointer.JSONPointable = (*Examples)(nil) + +// JSONLookup implements https://pkg.go.dev/github.com/go-openapi/jsonpointer#JSONPointable +func (m Examples) JSONLookup(token string) (interface{}, error) { + if v, ok := m[token]; !ok || v == nil { + return nil, fmt.Errorf("no example body %q", token) + } else if ref := v.Ref; ref != "" { + return &Ref{Ref: ref}, nil + } else { + return v.Value, nil + } +} + +var _ jsonpointer.JSONPointable = (*Links)(nil) + +// JSONLookup implements https://pkg.go.dev/github.com/go-openapi/jsonpointer#JSONPointable +func (m Links) JSONLookup(token string) (interface{}, error) { + if v, ok := m[token]; !ok || v == nil { + return nil, fmt.Errorf("no link body %q", token) + } else if ref := v.Ref; ref != "" { + return &Ref{Ref: ref}, nil + } else { + return v.Value, nil + } +} + +var _ jsonpointer.JSONPointable = (*Callbacks)(nil) + +// JSONLookup implements https://pkg.go.dev/github.com/go-openapi/jsonpointer#JSONPointable +func (m Callbacks) JSONLookup(token string) (interface{}, error) { + if v, ok := m[token]; !ok || v == nil { + return nil, fmt.Errorf("no callback body %q", token) + } else if ref := v.Ref; ref != "" { + return &Ref{Ref: ref}, nil + } else { + return v.Value, nil + } +} diff --git a/openapi3/example.go b/openapi3/example.go index 67039a6c3..44e71d827 100644 --- a/openapi3/example.go +++ b/openapi3/example.go @@ -4,28 +4,8 @@ import ( "context" "encoding/json" "errors" - "fmt" - - "github.com/go-openapi/jsonpointer" ) -type Examples map[string]*ExampleRef - -var _ jsonpointer.JSONPointable = (*Examples)(nil) - -// JSONLookup implements https://pkg.go.dev/github.com/go-openapi/jsonpointer#JSONPointable -func (e Examples) JSONLookup(token string) (interface{}, error) { - ref, ok := e[token] - if ref == nil || !ok { - return nil, fmt.Errorf("object has no field %q", token) - } - - if ref.Ref != "" { - return &Ref{Ref: ref.Ref}, nil - } - return ref.Value, nil -} - // Example is specified by OpenAPI/Swagger 3.0 standard. // See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#example-object type Example struct { diff --git a/openapi3/header.go b/openapi3/header.go index aea3bf80a..e5eee6ccb 100644 --- a/openapi3/header.go +++ b/openapi3/header.go @@ -8,23 +8,6 @@ import ( "github.com/go-openapi/jsonpointer" ) -type Headers map[string]*HeaderRef - -var _ jsonpointer.JSONPointable = (*Headers)(nil) - -// JSONLookup implements https://pkg.go.dev/github.com/go-openapi/jsonpointer#JSONPointable -func (h Headers) JSONLookup(token string) (interface{}, error) { - ref, ok := h[token] - if ref == nil || !ok { - return nil, fmt.Errorf("object has no field %q", token) - } - - if ref.Ref != "" { - return &Ref{Ref: ref.Ref}, nil - } - return ref.Value, nil -} - // Header is specified by OpenAPI/Swagger 3.0 standard. // See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#header-object type Header struct { diff --git a/openapi3/link.go b/openapi3/link.go index 394afa8a9..23a8df41b 100644 --- a/openapi3/link.go +++ b/openapi3/link.go @@ -5,27 +5,8 @@ import ( "encoding/json" "errors" "fmt" - - "github.com/go-openapi/jsonpointer" ) -type Links map[string]*LinkRef - -// JSONLookup implements https://pkg.go.dev/github.com/go-openapi/jsonpointer#JSONPointable -func (links Links) JSONLookup(token string) (interface{}, error) { - ref, ok := links[token] - if !ok { - return nil, fmt.Errorf("object has no field %q", token) - } - - if ref != nil && ref.Ref != "" { - return &Ref{Ref: ref.Ref}, nil - } - return ref.Value, nil -} - -var _ jsonpointer.JSONPointable = (*Links)(nil) - // Link is specified by OpenAPI/Swagger standard version 3. // See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#link-object type Link struct { diff --git a/openapi3/openapi3.go b/openapi3/openapi3.go index 52125b1b3..865837e0e 100644 --- a/openapi3/openapi3.go +++ b/openapi3/openapi3.go @@ -5,6 +5,8 @@ import ( "encoding/json" "errors" "fmt" + + "github.com/go-openapi/jsonpointer" ) // T is the root of an OpenAPI v3 document @@ -24,6 +26,33 @@ type T struct { visited visitedComponent } +var _ jsonpointer.JSONPointable = (*T)(nil) + +// JSONLookup implements https://pkg.go.dev/github.com/go-openapi/jsonpointer#JSONPointable +func (doc *T) JSONLookup(token string) (interface{}, error) { + switch token { + case "openapi": + return doc.OpenAPI, nil + case "components": + return doc.Components, nil + case "info": + return doc.Info, nil + case "paths": + return doc.Paths, nil + case "security": + return doc.Security, nil + case "servers": + return doc.Servers, nil + case "tags": + return doc.Tags, nil + case "externalDocs": + return doc.ExternalDocs, nil + } + + v, _, err := jsonpointer.GetForToken(doc.Extensions, token) + return v, err +} + // MarshalJSON returns the JSON encoding of T. func (doc T) MarshalJSON() ([]byte, error) { m := make(map[string]interface{}, 4+len(doc.Extensions)) diff --git a/openapi3/parameter.go b/openapi3/parameter.go index 8a7546989..f5a157de2 100644 --- a/openapi3/parameter.go +++ b/openapi3/parameter.go @@ -11,23 +11,6 @@ import ( "github.com/go-openapi/jsonpointer" ) -type ParametersMap map[string]*ParameterRef - -var _ jsonpointer.JSONPointable = (*ParametersMap)(nil) - -// JSONLookup implements https://pkg.go.dev/github.com/go-openapi/jsonpointer#JSONPointable -func (p ParametersMap) JSONLookup(token string) (interface{}, error) { - ref, ok := p[token] - if ref == nil || !ok { - return nil, fmt.Errorf("object has no field %q", token) - } - - if ref.Ref != "" { - return &Ref{Ref: ref.Ref}, nil - } - return ref.Value, nil -} - // Parameters is specified by OpenAPI/Swagger 3.0 standard. type Parameters []*ParameterRef @@ -39,13 +22,11 @@ func (p Parameters) JSONLookup(token string) (interface{}, error) { if err != nil { return nil, err } - if index < 0 || index >= len(p) { return nil, fmt.Errorf("index %d out of bounds of array of length %d", index, len(p)) } ref := p[index] - if ref != nil && ref.Ref != "" { return &Ref{Ref: ref.Ref}, nil } diff --git a/openapi3/refs_test.go b/openapi3/refs_test.go index 545c610b8..3f044303a 100644 --- a/openapi3/refs_test.go +++ b/openapi3/refs_test.go @@ -216,12 +216,15 @@ components: - type: integer format: int32 `[1:]) + loader := NewLoader() doc, err := loader.LoadFromData(spec) require.NoError(t, err) require.NotNil(t, doc) + err = doc.Validate(loader.Context) require.NoError(t, err) + var ptr jsonpointer.Pointer var v interface{} var kind reflect.Kind diff --git a/openapi3/request_body.go b/openapi3/request_body.go index 8f5c0d6f8..acd2d0e8c 100644 --- a/openapi3/request_body.go +++ b/openapi3/request_body.go @@ -4,28 +4,8 @@ import ( "context" "encoding/json" "errors" - "fmt" - - "github.com/go-openapi/jsonpointer" ) -type RequestBodies map[string]*RequestBodyRef - -var _ jsonpointer.JSONPointable = (*RequestBodyRef)(nil) - -// JSONLookup implements https://pkg.go.dev/github.com/go-openapi/jsonpointer#JSONPointable -func (r RequestBodies) JSONLookup(token string) (interface{}, error) { - ref, ok := r[token] - if !ok { - return nil, fmt.Errorf("object has no field %q", token) - } - - if ref != nil && ref.Ref != "" { - return &Ref{Ref: ref.Ref}, nil - } - return ref.Value, nil -} - // RequestBody is specified by OpenAPI/Swagger 3.0 standard. // See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#request-body-object type RequestBody struct { diff --git a/openapi3/response.go b/openapi3/response.go index 37f531a65..24b3a5566 100644 --- a/openapi3/response.go +++ b/openapi3/response.go @@ -11,21 +11,6 @@ import ( "github.com/go-openapi/jsonpointer" ) -type ResponseBodies map[string]*ResponseRef - -var _ jsonpointer.JSONPointable = (*ResponseRef)(nil) - -// JSONLookup implements https://pkg.go.dev/github.com/go-openapi/jsonpointer#JSONPointable -func (m ResponseBodies) JSONLookup(token string) (interface{}, error) { - if v, ok := m[token]; !ok || v == nil { - return nil, fmt.Errorf("no response body %q", token) - } else if ref := v.Ref; ref != "" { - return &Ref{Ref: ref}, nil - } else { - return v.Value, nil - } -} - // Responses is specified by OpenAPI/Swagger 3.0 standard. // See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#responses-object type Responses map[string]*ResponseRef diff --git a/openapi3/schema.go b/openapi3/schema.go index 07f569616..443e628e2 100644 --- a/openapi3/schema.go +++ b/openapi3/schema.go @@ -60,23 +60,6 @@ func NewSchemaRef(ref string, value *Schema) *SchemaRef { } } -type Schemas map[string]*SchemaRef - -var _ jsonpointer.JSONPointable = (*Schemas)(nil) - -// JSONLookup implements https://pkg.go.dev/github.com/go-openapi/jsonpointer#JSONPointable -func (s Schemas) JSONLookup(token string) (interface{}, error) { - ref, ok := s[token] - if ref == nil || !ok { - return nil, fmt.Errorf("object has no field %q", token) - } - - if ref.Ref != "" { - return &Ref{Ref: ref.Ref}, nil - } - return ref.Value, nil -} - type SchemaRefs []*SchemaRef var _ jsonpointer.JSONPointable = (*SchemaRefs)(nil) diff --git a/openapi3/security_scheme.go b/openapi3/security_scheme.go index 42df94d5b..c07bfb619 100644 --- a/openapi3/security_scheme.go +++ b/openapi3/security_scheme.go @@ -6,27 +6,8 @@ import ( "errors" "fmt" "net/url" - - "github.com/go-openapi/jsonpointer" ) -type SecuritySchemes map[string]*SecuritySchemeRef - -// JSONLookup implements https://pkg.go.dev/github.com/go-openapi/jsonpointer#JSONPointable -func (s SecuritySchemes) JSONLookup(token string) (interface{}, error) { - ref, ok := s[token] - if ref == nil || !ok { - return nil, fmt.Errorf("object has no field %q", token) - } - - if ref.Ref != "" { - return &Ref{Ref: ref.Ref}, nil - } - return ref.Value, nil -} - -var _ jsonpointer.JSONPointable = (*SecuritySchemes)(nil) - // SecurityScheme is specified by OpenAPI/Swagger standard version 3. // See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#security-scheme-object type SecurityScheme struct {