Merged in jb/openapi (pull request #22)
add openapi infra * add openapi infra Includes generated stubs and all deps * generatetolocation * basesetupoffunctionsandclient * round1controllertests * passintegrationtests * cleanupfromfullsuite * storedjson * fixjsonyaml * fixtests Approved-by: Michael McGuinness
This commit is contained in:
committed by
Michael McGuinness
parent
5ca36b0502
commit
174644b63c
+205
@@ -0,0 +1,205 @@
|
||||
package openapi3
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
|
||||
"github.com/go-openapi/jsonpointer"
|
||||
)
|
||||
|
||||
// T is the root of an OpenAPI v3 document
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#openapi-object
|
||||
type T struct {
|
||||
Extensions map[string]any `json:"-" yaml:"-"`
|
||||
|
||||
OpenAPI string `json:"openapi" yaml:"openapi"` // Required
|
||||
Components *Components `json:"components,omitempty" yaml:"components,omitempty"`
|
||||
Info *Info `json:"info" yaml:"info"` // Required
|
||||
Paths *Paths `json:"paths" yaml:"paths"` // Required
|
||||
Security SecurityRequirements `json:"security,omitempty" yaml:"security,omitempty"`
|
||||
Servers Servers `json:"servers,omitempty" yaml:"servers,omitempty"`
|
||||
Tags Tags `json:"tags,omitempty" yaml:"tags,omitempty"`
|
||||
ExternalDocs *ExternalDocs `json:"externalDocs,omitempty" yaml:"externalDocs,omitempty"`
|
||||
|
||||
visited visitedComponent
|
||||
url *url.URL
|
||||
}
|
||||
|
||||
var _ jsonpointer.JSONPointable = (*T)(nil)
|
||||
|
||||
// JSONLookup implements https://pkg.go.dev/github.com/go-openapi/jsonpointer#JSONPointable
|
||||
func (doc *T) JSONLookup(token string) (any, 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) {
|
||||
x, err := doc.MarshalYAML()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return json.Marshal(x)
|
||||
}
|
||||
|
||||
// MarshalYAML returns the YAML encoding of T.
|
||||
func (doc *T) MarshalYAML() (any, error) {
|
||||
if doc == nil {
|
||||
return nil, nil
|
||||
}
|
||||
m := make(map[string]any, 4+len(doc.Extensions))
|
||||
for k, v := range doc.Extensions {
|
||||
m[k] = v
|
||||
}
|
||||
m["openapi"] = doc.OpenAPI
|
||||
if x := doc.Components; x != nil {
|
||||
m["components"] = x
|
||||
}
|
||||
m["info"] = doc.Info
|
||||
m["paths"] = doc.Paths
|
||||
if x := doc.Security; len(x) != 0 {
|
||||
m["security"] = x
|
||||
}
|
||||
if x := doc.Servers; len(x) != 0 {
|
||||
m["servers"] = x
|
||||
}
|
||||
if x := doc.Tags; len(x) != 0 {
|
||||
m["tags"] = x
|
||||
}
|
||||
if x := doc.ExternalDocs; x != nil {
|
||||
m["externalDocs"] = x
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON sets T to a copy of data.
|
||||
func (doc *T) UnmarshalJSON(data []byte) error {
|
||||
type TBis T
|
||||
var x TBis
|
||||
if err := json.Unmarshal(data, &x); err != nil {
|
||||
return unmarshalError(err)
|
||||
}
|
||||
_ = json.Unmarshal(data, &x.Extensions)
|
||||
delete(x.Extensions, "openapi")
|
||||
delete(x.Extensions, "components")
|
||||
delete(x.Extensions, "info")
|
||||
delete(x.Extensions, "paths")
|
||||
delete(x.Extensions, "security")
|
||||
delete(x.Extensions, "servers")
|
||||
delete(x.Extensions, "tags")
|
||||
delete(x.Extensions, "externalDocs")
|
||||
if len(x.Extensions) == 0 {
|
||||
x.Extensions = nil
|
||||
}
|
||||
*doc = T(x)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (doc *T) AddOperation(path string, method string, operation *Operation) {
|
||||
if doc.Paths == nil {
|
||||
doc.Paths = NewPaths()
|
||||
}
|
||||
pathItem := doc.Paths.Value(path)
|
||||
if pathItem == nil {
|
||||
pathItem = &PathItem{}
|
||||
doc.Paths.Set(path, pathItem)
|
||||
}
|
||||
pathItem.SetOperation(method, operation)
|
||||
}
|
||||
|
||||
func (doc *T) AddServer(server *Server) {
|
||||
doc.Servers = append(doc.Servers, server)
|
||||
}
|
||||
|
||||
func (doc *T) AddServers(servers ...*Server) {
|
||||
doc.Servers = append(doc.Servers, servers...)
|
||||
}
|
||||
|
||||
// Validate returns an error if T does not comply with the OpenAPI spec.
|
||||
// Validations Options can be provided to modify the validation behavior.
|
||||
func (doc *T) Validate(ctx context.Context, opts ...ValidationOption) error {
|
||||
ctx = WithValidationOptions(ctx, opts...)
|
||||
|
||||
if doc.OpenAPI == "" {
|
||||
return errors.New("value of openapi must be a non-empty string")
|
||||
}
|
||||
|
||||
var wrap func(error) error
|
||||
|
||||
wrap = func(e error) error { return fmt.Errorf("invalid components: %w", e) }
|
||||
if v := doc.Components; v != nil {
|
||||
if err := v.Validate(ctx); err != nil {
|
||||
return wrap(err)
|
||||
}
|
||||
}
|
||||
|
||||
wrap = func(e error) error { return fmt.Errorf("invalid info: %w", e) }
|
||||
if v := doc.Info; v != nil {
|
||||
if err := v.Validate(ctx); err != nil {
|
||||
return wrap(err)
|
||||
}
|
||||
} else {
|
||||
return wrap(errors.New("must be an object"))
|
||||
}
|
||||
|
||||
wrap = func(e error) error { return fmt.Errorf("invalid paths: %w", e) }
|
||||
if v := doc.Paths; v != nil {
|
||||
if err := v.Validate(ctx); err != nil {
|
||||
return wrap(err)
|
||||
}
|
||||
} else {
|
||||
return wrap(errors.New("must be an object"))
|
||||
}
|
||||
|
||||
wrap = func(e error) error { return fmt.Errorf("invalid security: %w", e) }
|
||||
if v := doc.Security; v != nil {
|
||||
if err := v.Validate(ctx); err != nil {
|
||||
return wrap(err)
|
||||
}
|
||||
}
|
||||
|
||||
wrap = func(e error) error { return fmt.Errorf("invalid servers: %w", e) }
|
||||
if v := doc.Servers; v != nil {
|
||||
if err := v.Validate(ctx); err != nil {
|
||||
return wrap(err)
|
||||
}
|
||||
}
|
||||
|
||||
wrap = func(e error) error { return fmt.Errorf("invalid tags: %w", e) }
|
||||
if v := doc.Tags; v != nil {
|
||||
if err := v.Validate(ctx); err != nil {
|
||||
return wrap(err)
|
||||
}
|
||||
}
|
||||
|
||||
wrap = func(e error) error { return fmt.Errorf("invalid external docs: %w", e) }
|
||||
if v := doc.ExternalDocs; v != nil {
|
||||
if err := v.Validate(ctx); err != nil {
|
||||
return wrap(err)
|
||||
}
|
||||
}
|
||||
|
||||
return validateExtensions(ctx, doc.Extensions)
|
||||
}
|
||||
Reference in New Issue
Block a user