go.mod: bump github.com/getkin/kin-openapi to v0.131.0
As deepmap/oapi-codegen didn't work with this newer version, upgrade to oapi-codegen/oapi-codegen v2. Mitigating CVE-2025-30153
This commit is contained in:
parent
c5cb0d0618
commit
b2700903ae
403 changed files with 44758 additions and 16347 deletions
2
vendor/github.com/getkin/kin-openapi/jsoninfo/doc.go
generated
vendored
2
vendor/github.com/getkin/kin-openapi/jsoninfo/doc.go
generated
vendored
|
|
@ -1,2 +0,0 @@
|
|||
// Package jsoninfo provides information and functions for marshalling/unmarshalling JSON.
|
||||
package jsoninfo
|
||||
121
vendor/github.com/getkin/kin-openapi/jsoninfo/field_info.go
generated
vendored
121
vendor/github.com/getkin/kin-openapi/jsoninfo/field_info.go
generated
vendored
|
|
@ -1,121 +0,0 @@
|
|||
package jsoninfo
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
// FieldInfo contains information about JSON serialization of a field.
|
||||
type FieldInfo struct {
|
||||
MultipleFields bool // Whether multiple Go fields share this JSON name
|
||||
HasJSONTag bool
|
||||
TypeIsMarshaller bool
|
||||
TypeIsUnmarshaller bool
|
||||
JSONOmitEmpty bool
|
||||
JSONString bool
|
||||
Index []int
|
||||
Type reflect.Type
|
||||
JSONName string
|
||||
}
|
||||
|
||||
func AppendFields(fields []FieldInfo, parentIndex []int, t reflect.Type) []FieldInfo {
|
||||
if t.Kind() == reflect.Ptr {
|
||||
t = t.Elem()
|
||||
}
|
||||
// For each field
|
||||
numField := t.NumField()
|
||||
iteration:
|
||||
for i := 0; i < numField; i++ {
|
||||
f := t.Field(i)
|
||||
index := make([]int, 0, len(parentIndex)+1)
|
||||
index = append(index, parentIndex...)
|
||||
index = append(index, i)
|
||||
|
||||
// See whether this is an embedded field
|
||||
if f.Anonymous {
|
||||
if f.Tag.Get("json") == "-" {
|
||||
continue
|
||||
}
|
||||
fields = AppendFields(fields, index, f.Type)
|
||||
continue iteration
|
||||
}
|
||||
|
||||
// Ignore certain types
|
||||
switch f.Type.Kind() {
|
||||
case reflect.Func, reflect.Chan:
|
||||
continue iteration
|
||||
}
|
||||
|
||||
// Is it a private (lowercase) field?
|
||||
firstRune, _ := utf8.DecodeRuneInString(f.Name)
|
||||
if unicode.IsLower(firstRune) {
|
||||
continue iteration
|
||||
}
|
||||
|
||||
// Declare a field
|
||||
field := FieldInfo{
|
||||
Index: index,
|
||||
Type: f.Type,
|
||||
JSONName: f.Name,
|
||||
}
|
||||
|
||||
// Read "json" tag
|
||||
jsonTag := f.Tag.Get("json")
|
||||
|
||||
// Read our custom "multijson" tag that
|
||||
// allows multiple fields with the same name.
|
||||
if v := f.Tag.Get("multijson"); v != "" {
|
||||
field.MultipleFields = true
|
||||
jsonTag = v
|
||||
}
|
||||
|
||||
// Handle "-"
|
||||
if jsonTag == "-" {
|
||||
continue
|
||||
}
|
||||
|
||||
// Parse the tag
|
||||
if jsonTag != "" {
|
||||
field.HasJSONTag = true
|
||||
for i, part := range strings.Split(jsonTag, ",") {
|
||||
if i == 0 {
|
||||
if part != "" {
|
||||
field.JSONName = part
|
||||
}
|
||||
} else {
|
||||
switch part {
|
||||
case "omitempty":
|
||||
field.JSONOmitEmpty = true
|
||||
case "string":
|
||||
field.JSONString = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_, field.TypeIsMarshaller = field.Type.MethodByName("MarshalJSON")
|
||||
_, field.TypeIsUnmarshaller = field.Type.MethodByName("UnmarshalJSON")
|
||||
|
||||
// Field is done
|
||||
fields = append(fields, field)
|
||||
}
|
||||
|
||||
return fields
|
||||
}
|
||||
|
||||
type sortableFieldInfos []FieldInfo
|
||||
|
||||
func (list sortableFieldInfos) Len() int {
|
||||
return len(list)
|
||||
}
|
||||
|
||||
func (list sortableFieldInfos) Less(i, j int) bool {
|
||||
return list[i].JSONName < list[j].JSONName
|
||||
}
|
||||
|
||||
func (list sortableFieldInfos) Swap(i, j int) {
|
||||
a, b := list[i], list[j]
|
||||
list[i], list[j] = b, a
|
||||
}
|
||||
162
vendor/github.com/getkin/kin-openapi/jsoninfo/marshal.go
generated
vendored
162
vendor/github.com/getkin/kin-openapi/jsoninfo/marshal.go
generated
vendored
|
|
@ -1,162 +0,0 @@
|
|||
package jsoninfo
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// MarshalStrictStruct function:
|
||||
// * Marshals struct fields, ignoring MarshalJSON() and fields without 'json' tag.
|
||||
// * Correctly handles StrictStruct semantics.
|
||||
func MarshalStrictStruct(value StrictStruct) ([]byte, error) {
|
||||
encoder := NewObjectEncoder()
|
||||
if err := value.EncodeWith(encoder, value); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return encoder.Bytes()
|
||||
}
|
||||
|
||||
type ObjectEncoder struct {
|
||||
result map[string]json.RawMessage
|
||||
}
|
||||
|
||||
func NewObjectEncoder() *ObjectEncoder {
|
||||
return &ObjectEncoder{
|
||||
result: make(map[string]json.RawMessage, 8),
|
||||
}
|
||||
}
|
||||
|
||||
// Bytes returns the result of encoding.
|
||||
func (encoder *ObjectEncoder) Bytes() ([]byte, error) {
|
||||
return json.Marshal(encoder.result)
|
||||
}
|
||||
|
||||
// EncodeExtension adds a key/value to the current JSON object.
|
||||
func (encoder *ObjectEncoder) EncodeExtension(key string, value interface{}) error {
|
||||
data, err := json.Marshal(value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
encoder.result[key] = data
|
||||
return nil
|
||||
}
|
||||
|
||||
// EncodeExtensionMap adds all properties to the result.
|
||||
func (encoder *ObjectEncoder) EncodeExtensionMap(value map[string]json.RawMessage) error {
|
||||
if value != nil {
|
||||
result := encoder.result
|
||||
for k, v := range value {
|
||||
result[k] = v
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (encoder *ObjectEncoder) EncodeStructFieldsAndExtensions(value interface{}) error {
|
||||
reflection := reflect.ValueOf(value)
|
||||
|
||||
// Follow "encoding/json" semantics
|
||||
if reflection.Kind() != reflect.Ptr {
|
||||
// Panic because this is a clear programming error
|
||||
panic(fmt.Errorf("value %s is not a pointer", reflection.Type().String()))
|
||||
}
|
||||
if reflection.IsNil() {
|
||||
// Panic because this is a clear programming error
|
||||
panic(fmt.Errorf("value %s is nil", reflection.Type().String()))
|
||||
}
|
||||
|
||||
// Take the element
|
||||
reflection = reflection.Elem()
|
||||
|
||||
// Obtain typeInfo
|
||||
typeInfo := GetTypeInfo(reflection.Type())
|
||||
|
||||
// Declare result
|
||||
result := encoder.result
|
||||
|
||||
// Supported fields
|
||||
iteration:
|
||||
for _, field := range typeInfo.Fields {
|
||||
// Fields without JSON tag are ignored
|
||||
if !field.HasJSONTag {
|
||||
continue
|
||||
}
|
||||
|
||||
// Marshal
|
||||
fieldValue := reflection.FieldByIndex(field.Index)
|
||||
if v, ok := fieldValue.Interface().(json.Marshaler); ok {
|
||||
if fieldValue.Kind() == reflect.Ptr && fieldValue.IsNil() {
|
||||
if field.JSONOmitEmpty {
|
||||
continue iteration
|
||||
}
|
||||
result[field.JSONName] = []byte("null")
|
||||
continue
|
||||
}
|
||||
fieldData, err := v.MarshalJSON()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
result[field.JSONName] = fieldData
|
||||
continue
|
||||
}
|
||||
switch fieldValue.Kind() {
|
||||
case reflect.Ptr, reflect.Interface:
|
||||
if fieldValue.IsNil() {
|
||||
if field.JSONOmitEmpty {
|
||||
continue iteration
|
||||
}
|
||||
result[field.JSONName] = []byte("null")
|
||||
continue
|
||||
}
|
||||
case reflect.Struct:
|
||||
case reflect.Map:
|
||||
if field.JSONOmitEmpty && (fieldValue.IsNil() || fieldValue.Len() == 0) {
|
||||
continue iteration
|
||||
}
|
||||
case reflect.Slice:
|
||||
if field.JSONOmitEmpty && fieldValue.Len() == 0 {
|
||||
continue iteration
|
||||
}
|
||||
case reflect.Bool:
|
||||
x := fieldValue.Bool()
|
||||
if field.JSONOmitEmpty && !x {
|
||||
continue iteration
|
||||
}
|
||||
s := "false"
|
||||
if x {
|
||||
s = "true"
|
||||
}
|
||||
result[field.JSONName] = []byte(s)
|
||||
continue iteration
|
||||
case reflect.Int64, reflect.Int, reflect.Int32:
|
||||
if field.JSONOmitEmpty && fieldValue.Int() == 0 {
|
||||
continue iteration
|
||||
}
|
||||
case reflect.Uint64, reflect.Uint, reflect.Uint32:
|
||||
if field.JSONOmitEmpty && fieldValue.Uint() == 0 {
|
||||
continue iteration
|
||||
}
|
||||
case reflect.Float64:
|
||||
if field.JSONOmitEmpty && fieldValue.Float() == 0.0 {
|
||||
continue iteration
|
||||
}
|
||||
case reflect.String:
|
||||
if field.JSONOmitEmpty && len(fieldValue.String()) == 0 {
|
||||
continue iteration
|
||||
}
|
||||
default:
|
||||
panic(fmt.Errorf("field %q has unsupported type %s", field.JSONName, field.Type.String()))
|
||||
}
|
||||
|
||||
// No special treament is needed
|
||||
// Use plain old "encoding/json".Marshal
|
||||
fieldData, err := json.Marshal(fieldValue.Addr().Interface())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
result[field.JSONName] = fieldData
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
30
vendor/github.com/getkin/kin-openapi/jsoninfo/marshal_ref.go
generated
vendored
30
vendor/github.com/getkin/kin-openapi/jsoninfo/marshal_ref.go
generated
vendored
|
|
@ -1,30 +0,0 @@
|
|||
package jsoninfo
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
func MarshalRef(value string, otherwise interface{}) ([]byte, error) {
|
||||
if value != "" {
|
||||
return json.Marshal(&refProps{
|
||||
Ref: value,
|
||||
})
|
||||
}
|
||||
return json.Marshal(otherwise)
|
||||
}
|
||||
|
||||
func UnmarshalRef(data []byte, destRef *string, destOtherwise interface{}) error {
|
||||
refProps := &refProps{}
|
||||
if err := json.Unmarshal(data, refProps); err == nil {
|
||||
ref := refProps.Ref
|
||||
if ref != "" {
|
||||
*destRef = ref
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return json.Unmarshal(data, destOtherwise)
|
||||
}
|
||||
|
||||
type refProps struct {
|
||||
Ref string `json:"$ref,omitempty" yaml:"$ref,omitempty"`
|
||||
}
|
||||
6
vendor/github.com/getkin/kin-openapi/jsoninfo/strict_struct.go
generated
vendored
6
vendor/github.com/getkin/kin-openapi/jsoninfo/strict_struct.go
generated
vendored
|
|
@ -1,6 +0,0 @@
|
|||
package jsoninfo
|
||||
|
||||
type StrictStruct interface {
|
||||
EncodeWith(encoder *ObjectEncoder, value interface{}) error
|
||||
DecodeWith(decoder *ObjectDecoder, value interface{}) error
|
||||
}
|
||||
68
vendor/github.com/getkin/kin-openapi/jsoninfo/type_info.go
generated
vendored
68
vendor/github.com/getkin/kin-openapi/jsoninfo/type_info.go
generated
vendored
|
|
@ -1,68 +0,0 @@
|
|||
package jsoninfo
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"sort"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var (
|
||||
typeInfos = map[reflect.Type]*TypeInfo{}
|
||||
typeInfosMutex sync.RWMutex
|
||||
)
|
||||
|
||||
// TypeInfo contains information about JSON serialization of a type
|
||||
type TypeInfo struct {
|
||||
Type reflect.Type
|
||||
Fields []FieldInfo
|
||||
}
|
||||
|
||||
func GetTypeInfoForValue(value interface{}) *TypeInfo {
|
||||
return GetTypeInfo(reflect.TypeOf(value))
|
||||
}
|
||||
|
||||
// GetTypeInfo returns TypeInfo for the given type.
|
||||
func GetTypeInfo(t reflect.Type) *TypeInfo {
|
||||
for t.Kind() == reflect.Ptr {
|
||||
t = t.Elem()
|
||||
}
|
||||
typeInfosMutex.RLock()
|
||||
typeInfo, exists := typeInfos[t]
|
||||
typeInfosMutex.RUnlock()
|
||||
if exists {
|
||||
return typeInfo
|
||||
}
|
||||
if t.Kind() != reflect.Struct {
|
||||
typeInfo = &TypeInfo{
|
||||
Type: t,
|
||||
}
|
||||
} else {
|
||||
// Allocate
|
||||
typeInfo = &TypeInfo{
|
||||
Type: t,
|
||||
Fields: make([]FieldInfo, 0, 16),
|
||||
}
|
||||
|
||||
// Add fields
|
||||
typeInfo.Fields = AppendFields(nil, nil, t)
|
||||
|
||||
// Sort fields
|
||||
sort.Sort(sortableFieldInfos(typeInfo.Fields))
|
||||
}
|
||||
|
||||
// Publish
|
||||
typeInfosMutex.Lock()
|
||||
typeInfos[t] = typeInfo
|
||||
typeInfosMutex.Unlock()
|
||||
return typeInfo
|
||||
}
|
||||
|
||||
// FieldNames returns all field names
|
||||
func (typeInfo *TypeInfo) FieldNames() []string {
|
||||
fields := typeInfo.Fields
|
||||
names := make([]string, 0, len(fields))
|
||||
for _, field := range fields {
|
||||
names = append(names, field.JSONName)
|
||||
}
|
||||
return names
|
||||
}
|
||||
121
vendor/github.com/getkin/kin-openapi/jsoninfo/unmarshal.go
generated
vendored
121
vendor/github.com/getkin/kin-openapi/jsoninfo/unmarshal.go
generated
vendored
|
|
@ -1,121 +0,0 @@
|
|||
package jsoninfo
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// UnmarshalStrictStruct function:
|
||||
// * Unmarshals struct fields, ignoring UnmarshalJSON(...) and fields without 'json' tag.
|
||||
// * Correctly handles StrictStruct
|
||||
func UnmarshalStrictStruct(data []byte, value StrictStruct) error {
|
||||
decoder, err := NewObjectDecoder(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return value.DecodeWith(decoder, value)
|
||||
}
|
||||
|
||||
type ObjectDecoder struct {
|
||||
Data []byte
|
||||
remainingFields map[string]json.RawMessage
|
||||
}
|
||||
|
||||
func NewObjectDecoder(data []byte) (*ObjectDecoder, error) {
|
||||
var remainingFields map[string]json.RawMessage
|
||||
if err := json.Unmarshal(data, &remainingFields); err != nil {
|
||||
return nil, fmt.Errorf("failed to unmarshal extension properties: %v (%s)", err, data)
|
||||
}
|
||||
return &ObjectDecoder{
|
||||
Data: data,
|
||||
remainingFields: remainingFields,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// DecodeExtensionMap returns all properties that were not decoded previously.
|
||||
func (decoder *ObjectDecoder) DecodeExtensionMap() map[string]json.RawMessage {
|
||||
return decoder.remainingFields
|
||||
}
|
||||
|
||||
func (decoder *ObjectDecoder) DecodeStructFieldsAndExtensions(value interface{}) error {
|
||||
reflection := reflect.ValueOf(value)
|
||||
if reflection.Kind() != reflect.Ptr {
|
||||
panic(fmt.Errorf("value %T is not a pointer", value))
|
||||
}
|
||||
if reflection.IsNil() {
|
||||
panic(fmt.Errorf("value %T is nil", value))
|
||||
}
|
||||
reflection = reflection.Elem()
|
||||
for (reflection.Kind() == reflect.Interface || reflection.Kind() == reflect.Ptr) && !reflection.IsNil() {
|
||||
reflection = reflection.Elem()
|
||||
}
|
||||
reflectionType := reflection.Type()
|
||||
if reflectionType.Kind() != reflect.Struct {
|
||||
panic(fmt.Errorf("value %T is not a struct", value))
|
||||
}
|
||||
typeInfo := GetTypeInfo(reflectionType)
|
||||
|
||||
// Supported fields
|
||||
fields := typeInfo.Fields
|
||||
remainingFields := decoder.remainingFields
|
||||
for fieldIndex, field := range fields {
|
||||
// Fields without JSON tag are ignored
|
||||
if !field.HasJSONTag {
|
||||
continue
|
||||
}
|
||||
|
||||
// Get data
|
||||
fieldData, exists := remainingFields[field.JSONName]
|
||||
if !exists {
|
||||
continue
|
||||
}
|
||||
|
||||
// Unmarshal
|
||||
if field.TypeIsUnmarshaller {
|
||||
fieldType := field.Type
|
||||
isPtr := false
|
||||
if fieldType.Kind() == reflect.Ptr {
|
||||
fieldType = fieldType.Elem()
|
||||
isPtr = true
|
||||
}
|
||||
fieldValue := reflect.New(fieldType)
|
||||
if err := fieldValue.Interface().(json.Unmarshaler).UnmarshalJSON(fieldData); err != nil {
|
||||
if field.MultipleFields {
|
||||
i := fieldIndex + 1
|
||||
if i < len(fields) && fields[i].JSONName == field.JSONName {
|
||||
continue
|
||||
}
|
||||
}
|
||||
return fmt.Errorf("failed to unmarshal property %q (%s): %v",
|
||||
field.JSONName, fieldValue.Type().String(), err)
|
||||
}
|
||||
if !isPtr {
|
||||
fieldValue = fieldValue.Elem()
|
||||
}
|
||||
reflection.FieldByIndex(field.Index).Set(fieldValue)
|
||||
|
||||
// Remove the field from remaining fields
|
||||
delete(remainingFields, field.JSONName)
|
||||
} else {
|
||||
fieldPtr := reflection.FieldByIndex(field.Index)
|
||||
if fieldPtr.Kind() != reflect.Ptr || fieldPtr.IsNil() {
|
||||
fieldPtr = fieldPtr.Addr()
|
||||
}
|
||||
if err := json.Unmarshal(fieldData, fieldPtr.Interface()); err != nil {
|
||||
if field.MultipleFields {
|
||||
i := fieldIndex + 1
|
||||
if i < len(fields) && fields[i].JSONName == field.JSONName {
|
||||
continue
|
||||
}
|
||||
}
|
||||
return fmt.Errorf("failed to unmarshal property %q (%s): %v",
|
||||
field.JSONName, fieldPtr.Type().String(), err)
|
||||
}
|
||||
|
||||
// Remove the field from remaining fields
|
||||
delete(remainingFields, field.JSONName)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
42
vendor/github.com/getkin/kin-openapi/jsoninfo/unsupported_properties_error.go
generated
vendored
42
vendor/github.com/getkin/kin-openapi/jsoninfo/unsupported_properties_error.go
generated
vendored
|
|
@ -1,42 +0,0 @@
|
|||
package jsoninfo
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"sort"
|
||||
)
|
||||
|
||||
// UnsupportedPropertiesError is a helper for extensions that want to refuse
|
||||
// unsupported JSON object properties.
|
||||
//
|
||||
// It produces a helpful error message.
|
||||
type UnsupportedPropertiesError struct {
|
||||
Value interface{}
|
||||
UnsupportedProperties map[string]json.RawMessage
|
||||
}
|
||||
|
||||
func NewUnsupportedPropertiesError(v interface{}, m map[string]json.RawMessage) error {
|
||||
return &UnsupportedPropertiesError{
|
||||
Value: v,
|
||||
UnsupportedProperties: m,
|
||||
}
|
||||
}
|
||||
|
||||
func (err *UnsupportedPropertiesError) Error() string {
|
||||
m := err.UnsupportedProperties
|
||||
typeInfo := GetTypeInfoForValue(err.Value)
|
||||
if m == nil || typeInfo == nil {
|
||||
return fmt.Sprintf("invalid %T", *err)
|
||||
}
|
||||
keys := make([]string, 0, len(m))
|
||||
for k := range m {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
supported := typeInfo.FieldNames()
|
||||
if len(supported) == 0 {
|
||||
return fmt.Sprintf("type \"%T\" doesn't take any properties. Unsupported properties: %+v",
|
||||
err.Value, keys)
|
||||
}
|
||||
return fmt.Sprintf("unsupported properties: %+v (supported properties are: %+v)", keys, supported)
|
||||
}
|
||||
68
vendor/github.com/getkin/kin-openapi/openapi3/callback.go
generated
vendored
68
vendor/github.com/getkin/kin-openapi/openapi3/callback.go
generated
vendored
|
|
@ -2,36 +2,60 @@ package openapi3
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/go-openapi/jsonpointer"
|
||||
"sort"
|
||||
)
|
||||
|
||||
type Callbacks map[string]*CallbackRef
|
||||
// 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 struct {
|
||||
Extensions map[string]any `json:"-" yaml:"-"`
|
||||
Origin *Origin `json:"__origin__,omitempty" yaml:"__origin__,omitempty"`
|
||||
|
||||
var _ jsonpointer.JSONPointable = (*Callbacks)(nil)
|
||||
|
||||
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
|
||||
m map[string]*PathItem
|
||||
}
|
||||
|
||||
// Callback is specified by OpenAPI/Swagger standard version 3.
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#callbackObject
|
||||
type Callback map[string]*PathItem
|
||||
// NewCallback builds a Callback object with path items in insertion order.
|
||||
func NewCallback(opts ...NewCallbackOption) *Callback {
|
||||
Callback := NewCallbackWithCapacity(len(opts))
|
||||
for _, opt := range opts {
|
||||
opt(Callback)
|
||||
}
|
||||
return Callback
|
||||
}
|
||||
|
||||
func (value Callback) Validate(ctx context.Context) error {
|
||||
for _, v := range value {
|
||||
// NewCallbackOption describes options to NewCallback func
|
||||
type NewCallbackOption func(*Callback)
|
||||
|
||||
// WithCallback adds Callback as an option to NewCallback
|
||||
func WithCallback(cb string, pathItem *PathItem) NewCallbackOption {
|
||||
return func(callback *Callback) {
|
||||
if p := pathItem; p != nil && cb != "" {
|
||||
callback.Set(cb, p)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Validate returns an error if Callback does not comply with the OpenAPI spec.
|
||||
func (callback *Callback) Validate(ctx context.Context, opts ...ValidationOption) error {
|
||||
ctx = WithValidationOptions(ctx, opts...)
|
||||
|
||||
keys := make([]string, 0, callback.Len())
|
||||
for key := range callback.Map() {
|
||||
keys = append(keys, key)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
for _, key := range keys {
|
||||
v := callback.Value(key)
|
||||
if err := v.Validate(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
||||
return validateExtensions(ctx, callback.Extensions)
|
||||
}
|
||||
|
||||
// UnmarshalJSON sets Callbacks to a copy of data.
|
||||
func (callbacks *Callbacks) UnmarshalJSON(data []byte) (err error) {
|
||||
*callbacks, _, err = unmarshalStringMapP[CallbackRef](data)
|
||||
return
|
||||
}
|
||||
|
|
|
|||
339
vendor/github.com/getkin/kin-openapi/openapi3/components.go
generated
vendored
339
vendor/github.com/getkin/kin-openapi/openapi3/components.go
generated
vendored
|
|
@ -2,22 +2,36 @@ package openapi3
|
|||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"sort"
|
||||
|
||||
"github.com/getkin/kin-openapi/jsoninfo"
|
||||
"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.
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#componentsObject
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#components-object
|
||||
type Components struct {
|
||||
ExtensionProps
|
||||
Extensions map[string]any `json:"-" yaml:"-"`
|
||||
Origin *Origin `json:"__origin__,omitempty" yaml:"__origin__,omitempty"`
|
||||
|
||||
Schemas Schemas `json:"schemas,omitempty" yaml:"schemas,omitempty"`
|
||||
Parameters ParametersMap `json:"parameters,omitempty" yaml:"parameters,omitempty"`
|
||||
Headers Headers `json:"headers,omitempty" yaml:"headers,omitempty"`
|
||||
RequestBodies RequestBodies `json:"requestBodies,omitempty" yaml:"requestBodies,omitempty"`
|
||||
Responses Responses `json:"responses,omitempty" yaml:"responses,omitempty"`
|
||||
Responses ResponseBodies `json:"responses,omitempty" yaml:"responses,omitempty"`
|
||||
SecuritySchemes SecuritySchemes `json:"securitySchemes,omitempty" yaml:"securitySchemes,omitempty"`
|
||||
Examples Examples `json:"examples,omitempty" yaml:"examples,omitempty"`
|
||||
Links Links `json:"links,omitempty" yaml:"links,omitempty"`
|
||||
|
|
@ -28,82 +42,331 @@ func NewComponents() Components {
|
|||
return Components{}
|
||||
}
|
||||
|
||||
func (components *Components) MarshalJSON() ([]byte, error) {
|
||||
return jsoninfo.MarshalStrictStruct(components)
|
||||
// MarshalJSON returns the JSON encoding of Components.
|
||||
func (components Components) MarshalJSON() ([]byte, error) {
|
||||
x, err := components.MarshalYAML()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return json.Marshal(x)
|
||||
}
|
||||
|
||||
// MarshalYAML returns the YAML encoding of Components.
|
||||
func (components Components) MarshalYAML() (any, error) {
|
||||
m := make(map[string]any, 9+len(components.Extensions))
|
||||
for k, v := range components.Extensions {
|
||||
m[k] = v
|
||||
}
|
||||
if x := components.Schemas; len(x) != 0 {
|
||||
m["schemas"] = x
|
||||
}
|
||||
if x := components.Parameters; len(x) != 0 {
|
||||
m["parameters"] = x
|
||||
}
|
||||
if x := components.Headers; len(x) != 0 {
|
||||
m["headers"] = x
|
||||
}
|
||||
if x := components.RequestBodies; len(x) != 0 {
|
||||
m["requestBodies"] = x
|
||||
}
|
||||
if x := components.Responses; len(x) != 0 {
|
||||
m["responses"] = x
|
||||
}
|
||||
if x := components.SecuritySchemes; len(x) != 0 {
|
||||
m["securitySchemes"] = x
|
||||
}
|
||||
if x := components.Examples; len(x) != 0 {
|
||||
m["examples"] = x
|
||||
}
|
||||
if x := components.Links; len(x) != 0 {
|
||||
m["links"] = x
|
||||
}
|
||||
if x := components.Callbacks; len(x) != 0 {
|
||||
m["callbacks"] = x
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON sets Components to a copy of data.
|
||||
func (components *Components) UnmarshalJSON(data []byte) error {
|
||||
return jsoninfo.UnmarshalStrictStruct(data, components)
|
||||
type ComponentsBis Components
|
||||
var x ComponentsBis
|
||||
if err := json.Unmarshal(data, &x); err != nil {
|
||||
return unmarshalError(err)
|
||||
}
|
||||
_ = json.Unmarshal(data, &x.Extensions)
|
||||
delete(x.Extensions, originKey)
|
||||
delete(x.Extensions, "schemas")
|
||||
delete(x.Extensions, "parameters")
|
||||
delete(x.Extensions, "headers")
|
||||
delete(x.Extensions, "requestBodies")
|
||||
delete(x.Extensions, "responses")
|
||||
delete(x.Extensions, "securitySchemes")
|
||||
delete(x.Extensions, "examples")
|
||||
delete(x.Extensions, "links")
|
||||
delete(x.Extensions, "callbacks")
|
||||
if len(x.Extensions) == 0 {
|
||||
x.Extensions = nil
|
||||
}
|
||||
*components = Components(x)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (components *Components) Validate(ctx context.Context) (err error) {
|
||||
for k, v := range components.Schemas {
|
||||
// Validate returns an error if Components does not comply with the OpenAPI spec.
|
||||
func (components *Components) Validate(ctx context.Context, opts ...ValidationOption) (err error) {
|
||||
ctx = WithValidationOptions(ctx, opts...)
|
||||
|
||||
schemas := make([]string, 0, len(components.Schemas))
|
||||
for name := range components.Schemas {
|
||||
schemas = append(schemas, name)
|
||||
}
|
||||
sort.Strings(schemas)
|
||||
for _, k := range schemas {
|
||||
v := components.Schemas[k]
|
||||
if err = ValidateIdentifier(k); err != nil {
|
||||
return
|
||||
return fmt.Errorf("schema %q: %w", k, err)
|
||||
}
|
||||
if err = v.Validate(ctx); err != nil {
|
||||
return
|
||||
return fmt.Errorf("schema %q: %w", k, err)
|
||||
}
|
||||
}
|
||||
|
||||
for k, v := range components.Parameters {
|
||||
parameters := make([]string, 0, len(components.Parameters))
|
||||
for name := range components.Parameters {
|
||||
parameters = append(parameters, name)
|
||||
}
|
||||
sort.Strings(parameters)
|
||||
for _, k := range parameters {
|
||||
v := components.Parameters[k]
|
||||
if err = ValidateIdentifier(k); err != nil {
|
||||
return
|
||||
return fmt.Errorf("parameter %q: %w", k, err)
|
||||
}
|
||||
if err = v.Validate(ctx); err != nil {
|
||||
return
|
||||
return fmt.Errorf("parameter %q: %w", k, err)
|
||||
}
|
||||
}
|
||||
|
||||
for k, v := range components.RequestBodies {
|
||||
requestBodies := make([]string, 0, len(components.RequestBodies))
|
||||
for name := range components.RequestBodies {
|
||||
requestBodies = append(requestBodies, name)
|
||||
}
|
||||
sort.Strings(requestBodies)
|
||||
for _, k := range requestBodies {
|
||||
v := components.RequestBodies[k]
|
||||
if err = ValidateIdentifier(k); err != nil {
|
||||
return
|
||||
return fmt.Errorf("request body %q: %w", k, err)
|
||||
}
|
||||
if err = v.Validate(ctx); err != nil {
|
||||
return
|
||||
return fmt.Errorf("request body %q: %w", k, err)
|
||||
}
|
||||
}
|
||||
|
||||
for k, v := range components.Responses {
|
||||
responses := make([]string, 0, len(components.Responses))
|
||||
for name := range components.Responses {
|
||||
responses = append(responses, name)
|
||||
}
|
||||
sort.Strings(responses)
|
||||
for _, k := range responses {
|
||||
if err = ValidateIdentifier(k); err != nil {
|
||||
return
|
||||
return fmt.Errorf("response %q: %w", k, err)
|
||||
}
|
||||
v := components.Responses[k]
|
||||
if err = v.Validate(ctx); err != nil {
|
||||
return
|
||||
return fmt.Errorf("response %q: %w", k, err)
|
||||
}
|
||||
}
|
||||
|
||||
for k, v := range components.Headers {
|
||||
headers := make([]string, 0, len(components.Headers))
|
||||
for name := range components.Headers {
|
||||
headers = append(headers, name)
|
||||
}
|
||||
sort.Strings(headers)
|
||||
for _, k := range headers {
|
||||
v := components.Headers[k]
|
||||
if err = ValidateIdentifier(k); err != nil {
|
||||
return
|
||||
return fmt.Errorf("header %q: %w", k, err)
|
||||
}
|
||||
if err = v.Validate(ctx); err != nil {
|
||||
return
|
||||
return fmt.Errorf("header %q: %w", k, err)
|
||||
}
|
||||
}
|
||||
|
||||
for k, v := range components.SecuritySchemes {
|
||||
securitySchemes := make([]string, 0, len(components.SecuritySchemes))
|
||||
for name := range components.SecuritySchemes {
|
||||
securitySchemes = append(securitySchemes, name)
|
||||
}
|
||||
sort.Strings(securitySchemes)
|
||||
for _, k := range securitySchemes {
|
||||
v := components.SecuritySchemes[k]
|
||||
if err = ValidateIdentifier(k); err != nil {
|
||||
return
|
||||
return fmt.Errorf("security scheme %q: %w", k, err)
|
||||
}
|
||||
if err = v.Validate(ctx); err != nil {
|
||||
return
|
||||
return fmt.Errorf("security scheme %q: %w", k, err)
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
examples := make([]string, 0, len(components.Examples))
|
||||
for name := range components.Examples {
|
||||
examples = append(examples, name)
|
||||
}
|
||||
sort.Strings(examples)
|
||||
for _, k := range examples {
|
||||
v := components.Examples[k]
|
||||
if err = ValidateIdentifier(k); err != nil {
|
||||
return fmt.Errorf("example %q: %w", k, err)
|
||||
}
|
||||
if err = v.Validate(ctx); err != nil {
|
||||
return fmt.Errorf("example %q: %w", k, err)
|
||||
}
|
||||
}
|
||||
|
||||
links := make([]string, 0, len(components.Links))
|
||||
for name := range components.Links {
|
||||
links = append(links, name)
|
||||
}
|
||||
sort.Strings(links)
|
||||
for _, k := range links {
|
||||
v := components.Links[k]
|
||||
if err = ValidateIdentifier(k); err != nil {
|
||||
return fmt.Errorf("link %q: %w", k, err)
|
||||
}
|
||||
if err = v.Validate(ctx); err != nil {
|
||||
return fmt.Errorf("link %q: %w", k, err)
|
||||
}
|
||||
}
|
||||
|
||||
callbacks := make([]string, 0, len(components.Callbacks))
|
||||
for name := range components.Callbacks {
|
||||
callbacks = append(callbacks, name)
|
||||
}
|
||||
sort.Strings(callbacks)
|
||||
for _, k := range callbacks {
|
||||
v := components.Callbacks[k]
|
||||
if err = ValidateIdentifier(k); err != nil {
|
||||
return fmt.Errorf("callback %q: %w", k, err)
|
||||
}
|
||||
if err = v.Validate(ctx); err != nil {
|
||||
return fmt.Errorf("callback %q: %w", k, err)
|
||||
}
|
||||
}
|
||||
|
||||
return validateExtensions(ctx, components.Extensions)
|
||||
}
|
||||
|
||||
const identifierPattern = `^[a-zA-Z0-9._-]+$`
|
||||
var _ jsonpointer.JSONPointable = (*Schemas)(nil)
|
||||
|
||||
// IdentifierRegExp verifies whether Component object key matches 'identifierPattern' pattern, according to OapiAPI v3.x.0.
|
||||
// Hovever, to be able supporting legacy OpenAPI v2.x, there is a need to customize above pattern in orde not to fail
|
||||
// converted v2-v3 validation
|
||||
var IdentifierRegExp = regexp.MustCompile(identifierPattern)
|
||||
|
||||
func ValidateIdentifier(value string) error {
|
||||
if IdentifierRegExp.MatchString(value) {
|
||||
return nil
|
||||
// JSONLookup implements https://pkg.go.dev/github.com/go-openapi/jsonpointer#JSONPointable
|
||||
func (m Schemas) JSONLookup(token string) (any, 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) (any, 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) (any, 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) (any, 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) (any, 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) (any, 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) (any, 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) (any, 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) (any, 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
|
||||
}
|
||||
return fmt.Errorf("identifier %q is not supported by OpenAPIv3 standard (regexp: %q)", value, identifierPattern)
|
||||
}
|
||||
|
|
|
|||
71
vendor/github.com/getkin/kin-openapi/openapi3/contact.go
generated
vendored
Normal file
71
vendor/github.com/getkin/kin-openapi/openapi3/contact.go
generated
vendored
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
package openapi3
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
// Contact is specified by OpenAPI/Swagger standard version 3.
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#contact-object
|
||||
type Contact struct {
|
||||
Extensions map[string]any `json:"-" yaml:"-"`
|
||||
Origin *Origin `json:"__origin__,omitempty" yaml:"__origin__,omitempty"`
|
||||
|
||||
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
||||
URL string `json:"url,omitempty" yaml:"url,omitempty"`
|
||||
Email string `json:"email,omitempty" yaml:"email,omitempty"`
|
||||
}
|
||||
|
||||
// MarshalJSON returns the JSON encoding of Contact.
|
||||
func (contact Contact) MarshalJSON() ([]byte, error) {
|
||||
x, err := contact.MarshalYAML()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return json.Marshal(x)
|
||||
}
|
||||
|
||||
// MarshalYAML returns the YAML encoding of Contact.
|
||||
func (contact Contact) MarshalYAML() (any, error) {
|
||||
m := make(map[string]any, 3+len(contact.Extensions))
|
||||
for k, v := range contact.Extensions {
|
||||
m[k] = v
|
||||
}
|
||||
if x := contact.Name; x != "" {
|
||||
m["name"] = x
|
||||
}
|
||||
if x := contact.URL; x != "" {
|
||||
m["url"] = x
|
||||
}
|
||||
if x := contact.Email; x != "" {
|
||||
m["email"] = x
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON sets Contact to a copy of data.
|
||||
func (contact *Contact) UnmarshalJSON(data []byte) error {
|
||||
type ContactBis Contact
|
||||
var x ContactBis
|
||||
if err := json.Unmarshal(data, &x); err != nil {
|
||||
return unmarshalError(err)
|
||||
}
|
||||
_ = json.Unmarshal(data, &x.Extensions)
|
||||
|
||||
delete(x.Extensions, originKey)
|
||||
delete(x.Extensions, "name")
|
||||
delete(x.Extensions, "url")
|
||||
delete(x.Extensions, "email")
|
||||
if len(x.Extensions) == 0 {
|
||||
x.Extensions = nil
|
||||
}
|
||||
*contact = Contact(x)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Validate returns an error if Contact does not comply with the OpenAPI spec.
|
||||
func (contact *Contact) Validate(ctx context.Context, opts ...ValidationOption) error {
|
||||
ctx = WithValidationOptions(ctx, opts...)
|
||||
|
||||
return validateExtensions(ctx, contact.Extensions)
|
||||
}
|
||||
23
vendor/github.com/getkin/kin-openapi/openapi3/content.go
generated
vendored
23
vendor/github.com/getkin/kin-openapi/openapi3/content.go
generated
vendored
|
|
@ -2,6 +2,7 @@ package openapi3
|
|||
|
||||
import (
|
||||
"context"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
|
|
@ -9,7 +10,7 @@ import (
|
|||
type Content map[string]*MediaType
|
||||
|
||||
func NewContent() Content {
|
||||
return make(map[string]*MediaType, 4)
|
||||
return make(map[string]*MediaType)
|
||||
}
|
||||
|
||||
func NewContentWithSchema(schema *Schema, consumes []string) Content {
|
||||
|
|
@ -104,12 +105,26 @@ func (content Content) Get(mime string) *MediaType {
|
|||
return content["*/*"]
|
||||
}
|
||||
|
||||
func (value Content) Validate(ctx context.Context) error {
|
||||
for _, v := range value {
|
||||
// Validate MediaType
|
||||
// Validate returns an error if Content does not comply with the OpenAPI spec.
|
||||
func (content Content) Validate(ctx context.Context, opts ...ValidationOption) error {
|
||||
ctx = WithValidationOptions(ctx, opts...)
|
||||
|
||||
keys := make([]string, 0, len(content))
|
||||
for key := range content {
|
||||
keys = append(keys, key)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
for _, k := range keys {
|
||||
v := content[k]
|
||||
if err := v.Validate(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON sets Content to a copy of data.
|
||||
func (content *Content) UnmarshalJSON(data []byte) (err error) {
|
||||
*content, _, err = unmarshalStringMapP[MediaType](data)
|
||||
return
|
||||
}
|
||||
|
|
|
|||
58
vendor/github.com/getkin/kin-openapi/openapi3/discriminator.go
generated
vendored
58
vendor/github.com/getkin/kin-openapi/openapi3/discriminator.go
generated
vendored
|
|
@ -2,27 +2,63 @@ package openapi3
|
|||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/getkin/kin-openapi/jsoninfo"
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
// Discriminator is specified by OpenAPI/Swagger standard version 3.
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#discriminatorObject
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#discriminator-object
|
||||
type Discriminator struct {
|
||||
ExtensionProps
|
||||
Extensions map[string]any `json:"-" yaml:"-"`
|
||||
Origin *Origin `json:"__origin__,omitempty" yaml:"__origin__,omitempty"`
|
||||
|
||||
PropertyName string `json:"propertyName" yaml:"propertyName"`
|
||||
Mapping map[string]string `json:"mapping,omitempty" yaml:"mapping,omitempty"`
|
||||
PropertyName string `json:"propertyName" yaml:"propertyName"` // required
|
||||
Mapping StringMap `json:"mapping,omitempty" yaml:"mapping,omitempty"`
|
||||
}
|
||||
|
||||
func (value *Discriminator) MarshalJSON() ([]byte, error) {
|
||||
return jsoninfo.MarshalStrictStruct(value)
|
||||
// MarshalJSON returns the JSON encoding of Discriminator.
|
||||
func (discriminator Discriminator) MarshalJSON() ([]byte, error) {
|
||||
x, err := discriminator.MarshalYAML()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return json.Marshal(x)
|
||||
}
|
||||
|
||||
func (value *Discriminator) UnmarshalJSON(data []byte) error {
|
||||
return jsoninfo.UnmarshalStrictStruct(data, value)
|
||||
// MarshalYAML returns the YAML encoding of Discriminator.
|
||||
func (discriminator Discriminator) MarshalYAML() (any, error) {
|
||||
m := make(map[string]any, 2+len(discriminator.Extensions))
|
||||
for k, v := range discriminator.Extensions {
|
||||
m[k] = v
|
||||
}
|
||||
m["propertyName"] = discriminator.PropertyName
|
||||
if x := discriminator.Mapping; len(x) != 0 {
|
||||
m["mapping"] = x
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func (value *Discriminator) Validate(ctx context.Context) error {
|
||||
// UnmarshalJSON sets Discriminator to a copy of data.
|
||||
func (discriminator *Discriminator) UnmarshalJSON(data []byte) error {
|
||||
type DiscriminatorBis Discriminator
|
||||
var x DiscriminatorBis
|
||||
if err := json.Unmarshal(data, &x); err != nil {
|
||||
return unmarshalError(err)
|
||||
}
|
||||
_ = json.Unmarshal(data, &x.Extensions)
|
||||
|
||||
delete(x.Extensions, originKey)
|
||||
delete(x.Extensions, "propertyName")
|
||||
delete(x.Extensions, "mapping")
|
||||
if len(x.Extensions) == 0 {
|
||||
x.Extensions = nil
|
||||
}
|
||||
*discriminator = Discriminator(x)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Validate returns an error if Discriminator does not comply with the OpenAPI spec.
|
||||
func (discriminator *Discriminator) Validate(ctx context.Context, opts ...ValidationOption) error {
|
||||
ctx = WithValidationOptions(ctx, opts...)
|
||||
|
||||
return validateExtensions(ctx, discriminator.Extensions)
|
||||
}
|
||||
|
|
|
|||
2
vendor/github.com/getkin/kin-openapi/openapi3/doc.go
generated
vendored
2
vendor/github.com/getkin/kin-openapi/openapi3/doc.go
generated
vendored
|
|
@ -1,4 +1,4 @@
|
|||
// Package openapi3 parses and writes OpenAPI 3 specification documents.
|
||||
//
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.3.md
|
||||
package openapi3
|
||||
|
|
|
|||
83
vendor/github.com/getkin/kin-openapi/openapi3/encoding.go
generated
vendored
83
vendor/github.com/getkin/kin-openapi/openapi3/encoding.go
generated
vendored
|
|
@ -2,15 +2,16 @@ package openapi3
|
|||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/getkin/kin-openapi/jsoninfo"
|
||||
"sort"
|
||||
)
|
||||
|
||||
// Encoding is specified by OpenAPI/Swagger 3.0 standard.
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#encodingObject
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#encoding-object
|
||||
type Encoding struct {
|
||||
ExtensionProps
|
||||
Extensions map[string]any `json:"-" yaml:"-"`
|
||||
Origin *Origin `json:"__origin__,omitempty" yaml:"__origin__,omitempty"`
|
||||
|
||||
ContentType string `json:"contentType,omitempty" yaml:"contentType,omitempty"`
|
||||
Headers Headers `json:"headers,omitempty" yaml:"headers,omitempty"`
|
||||
|
|
@ -39,12 +40,59 @@ func (encoding *Encoding) WithHeaderRef(name string, ref *HeaderRef) *Encoding {
|
|||
return encoding
|
||||
}
|
||||
|
||||
func (encoding *Encoding) MarshalJSON() ([]byte, error) {
|
||||
return jsoninfo.MarshalStrictStruct(encoding)
|
||||
// MarshalJSON returns the JSON encoding of Encoding.
|
||||
func (encoding Encoding) MarshalJSON() ([]byte, error) {
|
||||
x, err := encoding.MarshalYAML()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return json.Marshal(x)
|
||||
}
|
||||
|
||||
// MarshalYAML returns the YAML encoding of Encoding.
|
||||
func (encoding Encoding) MarshalYAML() (any, error) {
|
||||
m := make(map[string]any, 5+len(encoding.Extensions))
|
||||
for k, v := range encoding.Extensions {
|
||||
m[k] = v
|
||||
}
|
||||
if x := encoding.ContentType; x != "" {
|
||||
m["contentType"] = x
|
||||
}
|
||||
if x := encoding.Headers; len(x) != 0 {
|
||||
m["headers"] = x
|
||||
}
|
||||
if x := encoding.Style; x != "" {
|
||||
m["style"] = x
|
||||
}
|
||||
if x := encoding.Explode; x != nil {
|
||||
m["explode"] = x
|
||||
}
|
||||
if x := encoding.AllowReserved; x {
|
||||
m["allowReserved"] = x
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON sets Encoding to a copy of data.
|
||||
func (encoding *Encoding) UnmarshalJSON(data []byte) error {
|
||||
return jsoninfo.UnmarshalStrictStruct(data, encoding)
|
||||
type EncodingBis Encoding
|
||||
var x EncodingBis
|
||||
if err := json.Unmarshal(data, &x); err != nil {
|
||||
return unmarshalError(err)
|
||||
}
|
||||
_ = json.Unmarshal(data, &x.Extensions)
|
||||
|
||||
delete(x.Extensions, originKey)
|
||||
delete(x.Extensions, "contentType")
|
||||
delete(x.Extensions, "headers")
|
||||
delete(x.Extensions, "style")
|
||||
delete(x.Extensions, "explode")
|
||||
delete(x.Extensions, "allowReserved")
|
||||
if len(x.Extensions) == 0 {
|
||||
x.Extensions = nil
|
||||
}
|
||||
*encoding = Encoding(x)
|
||||
return nil
|
||||
}
|
||||
|
||||
// SerializationMethod returns a serialization method of request body.
|
||||
|
|
@ -62,11 +110,21 @@ func (encoding *Encoding) SerializationMethod() *SerializationMethod {
|
|||
return sm
|
||||
}
|
||||
|
||||
func (value *Encoding) Validate(ctx context.Context) error {
|
||||
if value == nil {
|
||||
// Validate returns an error if Encoding does not comply with the OpenAPI spec.
|
||||
func (encoding *Encoding) Validate(ctx context.Context, opts ...ValidationOption) error {
|
||||
ctx = WithValidationOptions(ctx, opts...)
|
||||
|
||||
if encoding == nil {
|
||||
return nil
|
||||
}
|
||||
for k, v := range value.Headers {
|
||||
|
||||
headers := make([]string, 0, len(encoding.Headers))
|
||||
for k := range encoding.Headers {
|
||||
headers = append(headers, k)
|
||||
}
|
||||
sort.Strings(headers)
|
||||
for _, k := range headers {
|
||||
v := encoding.Headers[k]
|
||||
if err := ValidateIdentifier(k); err != nil {
|
||||
return nil
|
||||
}
|
||||
|
|
@ -76,7 +134,7 @@ func (value *Encoding) Validate(ctx context.Context) error {
|
|||
}
|
||||
|
||||
// Validate a media types's serialization method.
|
||||
sm := value.SerializationMethod()
|
||||
sm := encoding.SerializationMethod()
|
||||
switch {
|
||||
case sm.Style == SerializationForm && sm.Explode,
|
||||
sm.Style == SerializationForm && !sm.Explode,
|
||||
|
|
@ -85,10 +143,9 @@ func (value *Encoding) Validate(ctx context.Context) error {
|
|||
sm.Style == SerializationPipeDelimited && sm.Explode,
|
||||
sm.Style == SerializationPipeDelimited && !sm.Explode,
|
||||
sm.Style == SerializationDeepObject && sm.Explode:
|
||||
// it is a valid
|
||||
default:
|
||||
return fmt.Errorf("serialization method with style=%q and explode=%v is not supported by media type", sm.Style, sm.Explode)
|
||||
}
|
||||
|
||||
return nil
|
||||
return validateExtensions(ctx, encoding.Extensions)
|
||||
}
|
||||
|
|
|
|||
28
vendor/github.com/getkin/kin-openapi/openapi3/errors.go
generated
vendored
28
vendor/github.com/getkin/kin-openapi/openapi3/errors.go
generated
vendored
|
|
@ -10,16 +10,22 @@ import (
|
|||
type MultiError []error
|
||||
|
||||
func (me MultiError) Error() string {
|
||||
return spliceErr(" | ", me)
|
||||
}
|
||||
|
||||
func spliceErr(sep string, errs []error) string {
|
||||
buff := &bytes.Buffer{}
|
||||
for _, e := range me {
|
||||
for i, e := range errs {
|
||||
buff.WriteString(e.Error())
|
||||
buff.WriteString(" | ")
|
||||
if i != len(errs)-1 {
|
||||
buff.WriteString(sep)
|
||||
}
|
||||
}
|
||||
return buff.String()
|
||||
}
|
||||
|
||||
//Is allows you to determine if a generic error is in fact a MultiError using `errors.Is()`
|
||||
//It will also return true if any of the contained errors match target
|
||||
// Is allows you to determine if a generic error is in fact a MultiError using `errors.Is()`
|
||||
// It will also return true if any of the contained errors match target
|
||||
func (me MultiError) Is(target error) bool {
|
||||
if _, ok := target.(MultiError); ok {
|
||||
return true
|
||||
|
|
@ -32,8 +38,8 @@ func (me MultiError) Is(target error) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
//As allows you to use `errors.As()` to set target to the first error within the multi error that matches the target type
|
||||
func (me MultiError) As(target interface{}) bool {
|
||||
// As allows you to use `errors.As()` to set target to the first error within the multi error that matches the target type
|
||||
func (me MultiError) As(target any) bool {
|
||||
for _, e := range me {
|
||||
if errors.As(e, target) {
|
||||
return true
|
||||
|
|
@ -41,3 +47,13 @@ func (me MultiError) As(target interface{}) bool {
|
|||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type multiErrorForOneOf MultiError
|
||||
|
||||
func (meo multiErrorForOneOf) Error() string {
|
||||
return spliceErr(" Or ", meo)
|
||||
}
|
||||
|
||||
func (meo multiErrorForOneOf) Unwrap() error {
|
||||
return MultiError(meo)
|
||||
}
|
||||
|
|
|
|||
107
vendor/github.com/getkin/kin-openapi/openapi3/example.go
generated
vendored
107
vendor/github.com/getkin/kin-openapi/openapi3/example.go
generated
vendored
|
|
@ -2,53 +2,92 @@ package openapi3
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/getkin/kin-openapi/jsoninfo"
|
||||
"github.com/go-openapi/jsonpointer"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
)
|
||||
|
||||
type Examples map[string]*ExampleRef
|
||||
|
||||
var _ jsonpointer.JSONPointable = (*Examples)(nil)
|
||||
|
||||
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#exampleObject
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#example-object
|
||||
type Example struct {
|
||||
ExtensionProps
|
||||
Extensions map[string]any `json:"-" yaml:"-"`
|
||||
Origin *Origin `json:"__origin__,omitempty" yaml:"__origin__,omitempty"`
|
||||
|
||||
Summary string `json:"summary,omitempty" yaml:"summary,omitempty"`
|
||||
Description string `json:"description,omitempty" yaml:"description,omitempty"`
|
||||
Value interface{} `json:"value,omitempty" yaml:"value,omitempty"`
|
||||
ExternalValue string `json:"externalValue,omitempty" yaml:"externalValue,omitempty"`
|
||||
Summary string `json:"summary,omitempty" yaml:"summary,omitempty"`
|
||||
Description string `json:"description,omitempty" yaml:"description,omitempty"`
|
||||
Value any `json:"value,omitempty" yaml:"value,omitempty"`
|
||||
ExternalValue string `json:"externalValue,omitempty" yaml:"externalValue,omitempty"`
|
||||
}
|
||||
|
||||
func NewExample(value interface{}) *Example {
|
||||
return &Example{
|
||||
Value: value,
|
||||
func NewExample(value any) *Example {
|
||||
return &Example{Value: value}
|
||||
}
|
||||
|
||||
// MarshalJSON returns the JSON encoding of Example.
|
||||
func (example Example) MarshalJSON() ([]byte, error) {
|
||||
x, err := example.MarshalYAML()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return json.Marshal(x)
|
||||
}
|
||||
|
||||
func (example *Example) MarshalJSON() ([]byte, error) {
|
||||
return jsoninfo.MarshalStrictStruct(example)
|
||||
// MarshalYAML returns the YAML encoding of Example.
|
||||
func (example Example) MarshalYAML() (any, error) {
|
||||
m := make(map[string]any, 4+len(example.Extensions))
|
||||
for k, v := range example.Extensions {
|
||||
m[k] = v
|
||||
}
|
||||
if x := example.Summary; x != "" {
|
||||
m["summary"] = x
|
||||
}
|
||||
if x := example.Description; x != "" {
|
||||
m["description"] = x
|
||||
}
|
||||
if x := example.Value; x != nil {
|
||||
m["value"] = x
|
||||
}
|
||||
if x := example.ExternalValue; x != "" {
|
||||
m["externalValue"] = x
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON sets Example to a copy of data.
|
||||
func (example *Example) UnmarshalJSON(data []byte) error {
|
||||
return jsoninfo.UnmarshalStrictStruct(data, example)
|
||||
type ExampleBis Example
|
||||
var x ExampleBis
|
||||
if err := json.Unmarshal(data, &x); err != nil {
|
||||
return unmarshalError(err)
|
||||
}
|
||||
_ = json.Unmarshal(data, &x.Extensions)
|
||||
delete(x.Extensions, originKey)
|
||||
delete(x.Extensions, "summary")
|
||||
delete(x.Extensions, "description")
|
||||
delete(x.Extensions, "value")
|
||||
delete(x.Extensions, "externalValue")
|
||||
if len(x.Extensions) == 0 {
|
||||
x.Extensions = nil
|
||||
}
|
||||
*example = Example(x)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (value *Example) Validate(ctx context.Context) error {
|
||||
return nil // TODO
|
||||
// Validate returns an error if Example does not comply with the OpenAPI spec.
|
||||
func (example *Example) Validate(ctx context.Context, opts ...ValidationOption) error {
|
||||
ctx = WithValidationOptions(ctx, opts...)
|
||||
|
||||
if example.Value != nil && example.ExternalValue != "" {
|
||||
return errors.New("value and externalValue are mutually exclusive")
|
||||
}
|
||||
if example.Value == nil && example.ExternalValue == "" {
|
||||
return errors.New("no value or externalValue field")
|
||||
}
|
||||
|
||||
return validateExtensions(ctx, example.Extensions)
|
||||
}
|
||||
|
||||
// UnmarshalJSON sets Examples to a copy of data.
|
||||
func (examples *Examples) UnmarshalJSON(data []byte) (err error) {
|
||||
*examples, _, err = unmarshalStringMapP[ExampleRef](data)
|
||||
return
|
||||
}
|
||||
|
|
|
|||
16
vendor/github.com/getkin/kin-openapi/openapi3/example_validation.go
generated
vendored
Normal file
16
vendor/github.com/getkin/kin-openapi/openapi3/example_validation.go
generated
vendored
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
package openapi3
|
||||
|
||||
import "context"
|
||||
|
||||
func validateExampleValue(ctx context.Context, input any, schema *Schema) error {
|
||||
opts := make([]SchemaValidationOption, 0, 2)
|
||||
|
||||
if vo := getValidationOptions(ctx); vo.examplesValidationAsReq {
|
||||
opts = append(opts, VisitAsRequest())
|
||||
} else if vo.examplesValidationAsRes {
|
||||
opts = append(opts, VisitAsResponse())
|
||||
}
|
||||
opts = append(opts, MultiErrors())
|
||||
|
||||
return schema.VisitJSON(input, opts...)
|
||||
}
|
||||
46
vendor/github.com/getkin/kin-openapi/openapi3/extension.go
generated
vendored
46
vendor/github.com/getkin/kin-openapi/openapi3/extension.go
generated
vendored
|
|
@ -1,38 +1,32 @@
|
|||
package openapi3
|
||||
|
||||
import (
|
||||
"github.com/getkin/kin-openapi/jsoninfo"
|
||||
"context"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ExtensionProps provides support for OpenAPI extensions.
|
||||
// It reads/writes all properties that begin with "x-".
|
||||
type ExtensionProps struct {
|
||||
Extensions map[string]interface{} `json:"-" yaml:"-"`
|
||||
}
|
||||
func validateExtensions(ctx context.Context, extensions map[string]any) error { // FIXME: newtype + Validate(...)
|
||||
allowed := getValidationOptions(ctx).extraSiblingFieldsAllowed
|
||||
|
||||
// Assert that the type implements the interface
|
||||
var _ jsoninfo.StrictStruct = &ExtensionProps{}
|
||||
|
||||
// EncodeWith will be invoked by package "jsoninfo"
|
||||
func (props *ExtensionProps) EncodeWith(encoder *jsoninfo.ObjectEncoder, value interface{}) error {
|
||||
for k, v := range props.Extensions {
|
||||
if err := encoder.EncodeExtension(k, v); err != nil {
|
||||
return err
|
||||
var unknowns []string
|
||||
for k := range extensions {
|
||||
if strings.HasPrefix(k, "x-") {
|
||||
continue
|
||||
}
|
||||
if allowed != nil {
|
||||
if _, ok := allowed[k]; ok {
|
||||
continue
|
||||
}
|
||||
}
|
||||
unknowns = append(unknowns, k)
|
||||
}
|
||||
return encoder.EncodeStructFieldsAndExtensions(value)
|
||||
}
|
||||
|
||||
// DecodeWith will be invoked by package "jsoninfo"
|
||||
func (props *ExtensionProps) DecodeWith(decoder *jsoninfo.ObjectDecoder, value interface{}) error {
|
||||
if err := decoder.DecodeStructFieldsAndExtensions(value); err != nil {
|
||||
return err
|
||||
if len(unknowns) != 0 {
|
||||
sort.Strings(unknowns)
|
||||
return fmt.Errorf("extra sibling fields: %+v", unknowns)
|
||||
}
|
||||
source := decoder.DecodeExtensionMap()
|
||||
result := make(map[string]interface{}, len(source))
|
||||
for k, v := range source {
|
||||
result[k] = v
|
||||
}
|
||||
props.Extensions = result
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
54
vendor/github.com/getkin/kin-openapi/openapi3/external_docs.go
generated
vendored
54
vendor/github.com/getkin/kin-openapi/openapi3/external_docs.go
generated
vendored
|
|
@ -2,36 +2,74 @@ package openapi3
|
|||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
|
||||
"github.com/getkin/kin-openapi/jsoninfo"
|
||||
)
|
||||
|
||||
// ExternalDocs is specified by OpenAPI/Swagger standard version 3.
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#external-documentation-object
|
||||
type ExternalDocs struct {
|
||||
ExtensionProps
|
||||
Extensions map[string]any `json:"-" yaml:"-"`
|
||||
Origin *Origin `json:"__origin__,omitempty" yaml:"__origin__,omitempty"`
|
||||
|
||||
Description string `json:"description,omitempty" yaml:"description,omitempty"`
|
||||
URL string `json:"url,omitempty" yaml:"url,omitempty"`
|
||||
}
|
||||
|
||||
func (e *ExternalDocs) MarshalJSON() ([]byte, error) {
|
||||
return jsoninfo.MarshalStrictStruct(e)
|
||||
// MarshalJSON returns the JSON encoding of ExternalDocs.
|
||||
func (e ExternalDocs) MarshalJSON() ([]byte, error) {
|
||||
x, err := e.MarshalYAML()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return json.Marshal(x)
|
||||
}
|
||||
|
||||
// MarshalYAML returns the YAML encoding of ExternalDocs.
|
||||
func (e ExternalDocs) MarshalYAML() (any, error) {
|
||||
m := make(map[string]any, 2+len(e.Extensions))
|
||||
for k, v := range e.Extensions {
|
||||
m[k] = v
|
||||
}
|
||||
if x := e.Description; x != "" {
|
||||
m["description"] = x
|
||||
}
|
||||
if x := e.URL; x != "" {
|
||||
m["url"] = x
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON sets ExternalDocs to a copy of data.
|
||||
func (e *ExternalDocs) UnmarshalJSON(data []byte) error {
|
||||
return jsoninfo.UnmarshalStrictStruct(data, e)
|
||||
type ExternalDocsBis ExternalDocs
|
||||
var x ExternalDocsBis
|
||||
if err := json.Unmarshal(data, &x); err != nil {
|
||||
return unmarshalError(err)
|
||||
}
|
||||
_ = json.Unmarshal(data, &x.Extensions)
|
||||
delete(x.Extensions, originKey)
|
||||
delete(x.Extensions, "description")
|
||||
delete(x.Extensions, "url")
|
||||
if len(x.Extensions) == 0 {
|
||||
x.Extensions = nil
|
||||
}
|
||||
*e = ExternalDocs(x)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *ExternalDocs) Validate(ctx context.Context) error {
|
||||
// Validate returns an error if ExternalDocs does not comply with the OpenAPI spec.
|
||||
func (e *ExternalDocs) Validate(ctx context.Context, opts ...ValidationOption) error {
|
||||
ctx = WithValidationOptions(ctx, opts...)
|
||||
|
||||
if e.URL == "" {
|
||||
return errors.New("url is required")
|
||||
}
|
||||
if _, err := url.Parse(e.URL); err != nil {
|
||||
return fmt.Errorf("url is incorrect: %w", err)
|
||||
}
|
||||
return nil
|
||||
|
||||
return validateExtensions(ctx, e.Extensions)
|
||||
}
|
||||
|
|
|
|||
120
vendor/github.com/getkin/kin-openapi/openapi3/header.go
generated
vendored
120
vendor/github.com/getkin/kin-openapi/openapi3/header.go
generated
vendored
|
|
@ -5,61 +5,63 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/getkin/kin-openapi/jsoninfo"
|
||||
"github.com/go-openapi/jsonpointer"
|
||||
)
|
||||
|
||||
type Headers map[string]*HeaderRef
|
||||
|
||||
var _ jsonpointer.JSONPointable = (*Headers)(nil)
|
||||
|
||||
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#headerObject
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#header-object
|
||||
type Header struct {
|
||||
Parameter
|
||||
}
|
||||
|
||||
var _ jsonpointer.JSONPointable = (*Header)(nil)
|
||||
|
||||
func (value *Header) UnmarshalJSON(data []byte) error {
|
||||
return jsoninfo.UnmarshalStrictStruct(data, value)
|
||||
// JSONLookup implements https://pkg.go.dev/github.com/go-openapi/jsonpointer#JSONPointable
|
||||
func (header Header) JSONLookup(token string) (any, error) {
|
||||
return header.Parameter.JSONLookup(token)
|
||||
}
|
||||
|
||||
// MarshalJSON returns the JSON encoding of Header.
|
||||
func (header Header) MarshalJSON() ([]byte, error) {
|
||||
return header.Parameter.MarshalJSON()
|
||||
}
|
||||
|
||||
// UnmarshalJSON sets Header to a copy of data.
|
||||
func (header *Header) UnmarshalJSON(data []byte) error {
|
||||
return header.Parameter.UnmarshalJSON(data)
|
||||
}
|
||||
|
||||
// MarshalYAML returns the JSON encoding of Header.
|
||||
func (header Header) MarshalYAML() (any, error) {
|
||||
return header.Parameter, nil
|
||||
}
|
||||
|
||||
// SerializationMethod returns a header's serialization method.
|
||||
func (value *Header) SerializationMethod() (*SerializationMethod, error) {
|
||||
style := value.Style
|
||||
func (header *Header) SerializationMethod() (*SerializationMethod, error) {
|
||||
style := header.Style
|
||||
if style == "" {
|
||||
style = SerializationSimple
|
||||
}
|
||||
explode := false
|
||||
if value.Explode != nil {
|
||||
explode = *value.Explode
|
||||
if header.Explode != nil {
|
||||
explode = *header.Explode
|
||||
}
|
||||
return &SerializationMethod{Style: style, Explode: explode}, nil
|
||||
}
|
||||
|
||||
func (value *Header) Validate(ctx context.Context) error {
|
||||
if value.Name != "" {
|
||||
// Validate returns an error if Header does not comply with the OpenAPI spec.
|
||||
func (header *Header) Validate(ctx context.Context, opts ...ValidationOption) error {
|
||||
ctx = WithValidationOptions(ctx, opts...)
|
||||
|
||||
if header.Name != "" {
|
||||
return errors.New("header 'name' MUST NOT be specified, it is given in the corresponding headers map")
|
||||
}
|
||||
if value.In != "" {
|
||||
if header.In != "" {
|
||||
return errors.New("header 'in' MUST NOT be specified, it is implicitly in header")
|
||||
}
|
||||
|
||||
// Validate a parameter's serialization method.
|
||||
sm, err := value.SerializationMethod()
|
||||
sm, err := header.SerializationMethod()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -67,62 +69,34 @@ func (value *Header) Validate(ctx context.Context) error {
|
|||
sm.Style == SerializationSimple && !sm.Explode ||
|
||||
sm.Style == SerializationSimple && sm.Explode; !smSupported {
|
||||
e := fmt.Errorf("serialization method with style=%q and explode=%v is not supported by a header parameter", sm.Style, sm.Explode)
|
||||
return fmt.Errorf("header schema is invalid: %v", e)
|
||||
return fmt.Errorf("header schema is invalid: %w", e)
|
||||
}
|
||||
|
||||
if (value.Schema == nil) == (value.Content == nil) {
|
||||
e := fmt.Errorf("parameter must contain exactly one of content and schema: %v", value)
|
||||
return fmt.Errorf("header schema is invalid: %v", e)
|
||||
if (header.Schema == nil) == (len(header.Content) == 0) {
|
||||
e := fmt.Errorf("parameter must contain exactly one of content and schema: %v", header)
|
||||
return fmt.Errorf("header schema is invalid: %w", e)
|
||||
}
|
||||
if schema := value.Schema; schema != nil {
|
||||
if schema := header.Schema; schema != nil {
|
||||
if err := schema.Validate(ctx); err != nil {
|
||||
return fmt.Errorf("header schema is invalid: %v", err)
|
||||
return fmt.Errorf("header schema is invalid: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
if content := value.Content; content != nil {
|
||||
if content := header.Content; content != nil {
|
||||
e := errors.New("parameter content must only contain one entry")
|
||||
if len(content) > 1 {
|
||||
return fmt.Errorf("header content is invalid: %w", e)
|
||||
}
|
||||
|
||||
if err := content.Validate(ctx); err != nil {
|
||||
return fmt.Errorf("header content is invalid: %v", err)
|
||||
return fmt.Errorf("header content is invalid: %w", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (value Header) JSONLookup(token string) (interface{}, error) {
|
||||
switch token {
|
||||
case "schema":
|
||||
if value.Schema != nil {
|
||||
if value.Schema.Ref != "" {
|
||||
return &Ref{Ref: value.Schema.Ref}, nil
|
||||
}
|
||||
return value.Schema.Value, nil
|
||||
}
|
||||
case "name":
|
||||
return value.Name, nil
|
||||
case "in":
|
||||
return value.In, nil
|
||||
case "description":
|
||||
return value.Description, nil
|
||||
case "style":
|
||||
return value.Style, nil
|
||||
case "explode":
|
||||
return value.Explode, nil
|
||||
case "allowEmptyValue":
|
||||
return value.AllowEmptyValue, nil
|
||||
case "allowReserved":
|
||||
return value.AllowReserved, nil
|
||||
case "deprecated":
|
||||
return value.Deprecated, nil
|
||||
case "required":
|
||||
return value.Required, nil
|
||||
case "example":
|
||||
return value.Example, nil
|
||||
case "examples":
|
||||
return value.Examples, nil
|
||||
case "content":
|
||||
return value.Content, nil
|
||||
}
|
||||
|
||||
v, _, err := jsonpointer.GetForToken(value.ExtensionProps, token)
|
||||
return v, err
|
||||
// UnmarshalJSON sets Headers to a copy of data.
|
||||
func (headers *Headers) UnmarshalJSON(data []byte) (err error) {
|
||||
*headers, _, err = unmarshalStringMapP[HeaderRef](data)
|
||||
return
|
||||
}
|
||||
|
|
|
|||
261
vendor/github.com/getkin/kin-openapi/openapi3/helpers.go
generated
vendored
Normal file
261
vendor/github.com/getkin/kin-openapi/openapi3/helpers.go
generated
vendored
Normal file
|
|
@ -0,0 +1,261 @@
|
|||
package openapi3
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"path"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/go-openapi/jsonpointer"
|
||||
)
|
||||
|
||||
const identifierChars = `a-zA-Z0-9._-`
|
||||
|
||||
// IdentifierRegExp verifies whether Component object key matches contains just 'identifierChars', according to OpenAPI v3.x.
|
||||
// InvalidIdentifierCharRegExp matches all characters not contained in 'identifierChars'.
|
||||
// However, to be able supporting legacy OpenAPI v2.x, there is a need to customize above pattern in order not to fail
|
||||
// converted v2-v3 validation
|
||||
var (
|
||||
IdentifierRegExp = regexp.MustCompile(`^[` + identifierChars + `]+$`)
|
||||
InvalidIdentifierCharRegExp = regexp.MustCompile(`[^` + identifierChars + `]`)
|
||||
)
|
||||
|
||||
// ValidateIdentifier returns an error if the given component name does not match [IdentifierRegExp].
|
||||
func ValidateIdentifier(value string) error {
|
||||
if IdentifierRegExp.MatchString(value) {
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("identifier %q is not supported by OpenAPIv3 standard (charset: [%q])", value, identifierChars)
|
||||
}
|
||||
|
||||
// Float64Ptr is a helper for defining OpenAPI schemas.
|
||||
func Float64Ptr(value float64) *float64 {
|
||||
return &value
|
||||
}
|
||||
|
||||
// BoolPtr is a helper for defining OpenAPI schemas.
|
||||
func BoolPtr(value bool) *bool {
|
||||
return &value
|
||||
}
|
||||
|
||||
// Int64Ptr is a helper for defining OpenAPI schemas.
|
||||
func Int64Ptr(value int64) *int64 {
|
||||
return &value
|
||||
}
|
||||
|
||||
// Uint64Ptr is a helper for defining OpenAPI schemas.
|
||||
func Uint64Ptr(value uint64) *uint64 {
|
||||
return &value
|
||||
}
|
||||
|
||||
// componentNames returns the map keys in a sorted slice.
|
||||
func componentNames[E any](s map[string]E) []string {
|
||||
out := make([]string, 0, len(s))
|
||||
for i := range s {
|
||||
out = append(out, i)
|
||||
}
|
||||
sort.Strings(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// copyURI makes a copy of the pointer.
|
||||
func copyURI(u *url.URL) *url.URL {
|
||||
if u == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
c := *u // shallow-copy
|
||||
return &c
|
||||
}
|
||||
|
||||
type ComponentRef interface {
|
||||
RefString() string
|
||||
RefPath() *url.URL
|
||||
CollectionName() string
|
||||
}
|
||||
|
||||
// refersToSameDocument returns if the $ref refers to the same document.
|
||||
//
|
||||
// Documents in different directories will have distinct $ref values that resolve to
|
||||
// the same document.
|
||||
// For example, consider the 3 files:
|
||||
//
|
||||
// /records.yaml
|
||||
// /root.yaml $ref: records.yaml
|
||||
// /schema/other.yaml $ref: ../records.yaml
|
||||
//
|
||||
// The records.yaml reference in the 2 latter refers to the same document.
|
||||
func refersToSameDocument(o1 ComponentRef, o2 ComponentRef) bool {
|
||||
if o1 == nil || o2 == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
r1 := o1.RefPath()
|
||||
r2 := o2.RefPath()
|
||||
|
||||
if r1 == nil || r2 == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
// refURL is relative to the working directory & base spec file.
|
||||
return referenceURIMatch(r1, r2)
|
||||
}
|
||||
|
||||
// referencesRootDocument returns if the $ref points to the root document of the OpenAPI spec.
|
||||
//
|
||||
// If the document has no location, perhaps loaded from data in memory, it always returns false.
|
||||
func referencesRootDocument(doc *T, ref ComponentRef) bool {
|
||||
if doc.url == nil || ref == nil || ref.RefPath() == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
refURL := *ref.RefPath()
|
||||
refURL.Fragment = ""
|
||||
|
||||
// Check referenced element was in the root document.
|
||||
return referenceURIMatch(doc.url, &refURL)
|
||||
}
|
||||
|
||||
func referenceURIMatch(u1 *url.URL, u2 *url.URL) bool {
|
||||
s1, s2 := *u1, *u2
|
||||
if s1.Scheme == "" {
|
||||
s1.Scheme = "file"
|
||||
}
|
||||
if s2.Scheme == "" {
|
||||
s2.Scheme = "file"
|
||||
}
|
||||
|
||||
return s1.String() == s2.String()
|
||||
}
|
||||
|
||||
// ReferencesComponentInRootDocument returns if the given component reference references
|
||||
// the same document or element as another component reference in the root document's
|
||||
// '#/components/<type>'. If it does, it returns the name of it in the form
|
||||
// '#/components/<type>/NameXXX'
|
||||
//
|
||||
// Of course given a component from the root document will always match itself.
|
||||
//
|
||||
// https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#reference-object
|
||||
// https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#relative-references-in-urls
|
||||
//
|
||||
// Example. Take the spec with directory structure:
|
||||
//
|
||||
// openapi.yaml
|
||||
// schemas/
|
||||
// ├─ record.yaml
|
||||
// ├─ records.yaml
|
||||
//
|
||||
// In openapi.yaml we have:
|
||||
//
|
||||
// components:
|
||||
// schemas:
|
||||
// Record:
|
||||
// $ref: schemas/record.yaml
|
||||
//
|
||||
// Case 1: records.yml references a component in the root document
|
||||
//
|
||||
// $ref: ../openapi.yaml#/components/schemas/Record
|
||||
//
|
||||
// This would return...
|
||||
//
|
||||
// #/components/schemas/Record
|
||||
//
|
||||
// Case 2: records.yml indirectly refers to the same schema
|
||||
// as a schema the root document's '#/components/schemas'.
|
||||
//
|
||||
// $ref: ./record.yaml
|
||||
//
|
||||
// This would also return...
|
||||
//
|
||||
// #/components/schemas/Record
|
||||
func ReferencesComponentInRootDocument(doc *T, ref ComponentRef) (string, bool) {
|
||||
if ref == nil || ref.RefString() == "" {
|
||||
return "", false
|
||||
}
|
||||
|
||||
// Case 1:
|
||||
// Something like: ../another-folder/document.json#/myElement
|
||||
if isRemoteReference(ref.RefString()) && isRootComponentReference(ref.RefString(), ref.CollectionName()) {
|
||||
// Determine if it is *this* root doc.
|
||||
if referencesRootDocument(doc, ref) {
|
||||
_, name, _ := strings.Cut(ref.RefString(), path.Join("#/components/", ref.CollectionName()))
|
||||
|
||||
return path.Join("#/components/", ref.CollectionName(), name), true
|
||||
}
|
||||
}
|
||||
|
||||
// If there are no schemas defined in the root document return early.
|
||||
if doc.Components == nil {
|
||||
return "", false
|
||||
}
|
||||
|
||||
collection, _, err := jsonpointer.GetForToken(doc.Components, ref.CollectionName())
|
||||
if err != nil {
|
||||
panic(err) // unreachable
|
||||
}
|
||||
|
||||
var components map[string]ComponentRef
|
||||
|
||||
componentRefType := reflect.TypeOf(new(ComponentRef)).Elem()
|
||||
if t := reflect.TypeOf(collection); t.Kind() == reflect.Map &&
|
||||
t.Key().Kind() == reflect.String &&
|
||||
t.Elem().AssignableTo(componentRefType) {
|
||||
v := reflect.ValueOf(collection)
|
||||
|
||||
components = make(map[string]ComponentRef, v.Len())
|
||||
for _, key := range v.MapKeys() {
|
||||
strct := v.MapIndex(key)
|
||||
// Type assertion safe, already checked via reflection above.
|
||||
components[key.Interface().(string)] = strct.Interface().(ComponentRef)
|
||||
}
|
||||
} else {
|
||||
return "", false
|
||||
}
|
||||
|
||||
// Case 2:
|
||||
// Something like: ../openapi.yaml#/components/schemas/myElement
|
||||
for name, s := range components {
|
||||
// Must be a reference to a YAML file.
|
||||
if !isWholeDocumentReference(s.RefString()) {
|
||||
continue
|
||||
}
|
||||
|
||||
// Is the schema a ref to the same resource.
|
||||
if !refersToSameDocument(s, ref) {
|
||||
continue
|
||||
}
|
||||
|
||||
// Transform the remote ref to the equivalent schema in the root document.
|
||||
return path.Join("#/components/", ref.CollectionName(), name), true
|
||||
}
|
||||
|
||||
return "", false
|
||||
}
|
||||
|
||||
// isElementReference takes a $ref value and checks if it references a specific element.
|
||||
func isElementReference(ref string) bool {
|
||||
return ref != "" && !isWholeDocumentReference(ref)
|
||||
}
|
||||
|
||||
// isSchemaReference takes a $ref value and checks if it references a schema element.
|
||||
func isRootComponentReference(ref string, compType string) bool {
|
||||
return isElementReference(ref) && strings.Contains(ref, path.Join("#/components/", compType))
|
||||
}
|
||||
|
||||
// isWholeDocumentReference takes a $ref value and checks if it is whole document reference.
|
||||
func isWholeDocumentReference(ref string) bool {
|
||||
return ref != "" && !strings.ContainsAny(ref, "#")
|
||||
}
|
||||
|
||||
// isRemoteReference takes a $ref value and checks if it is remote reference.
|
||||
func isRemoteReference(ref string) bool {
|
||||
return ref != "" && !strings.HasPrefix(ref, "#") && !isURLReference(ref)
|
||||
}
|
||||
|
||||
// isURLReference takes a $ref value and checks if it is URL reference.
|
||||
func isURLReference(ref string) bool {
|
||||
return strings.HasPrefix(ref, "http://") || strings.HasPrefix(ref, "https://") || strings.HasPrefix(ref, "//")
|
||||
}
|
||||
126
vendor/github.com/getkin/kin-openapi/openapi3/info.go
generated
vendored
126
vendor/github.com/getkin/kin-openapi/openapi3/info.go
generated
vendored
|
|
@ -2,15 +2,15 @@ package openapi3
|
|||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
|
||||
"github.com/getkin/kin-openapi/jsoninfo"
|
||||
)
|
||||
|
||||
// Info is specified by OpenAPI/Swagger standard version 3.
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#infoObject
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#info-object
|
||||
type Info struct {
|
||||
ExtensionProps
|
||||
Extensions map[string]any `json:"-" yaml:"-"`
|
||||
Origin *Origin `json:"__origin__,omitempty" yaml:"__origin__,omitempty"`
|
||||
|
||||
Title string `json:"title" yaml:"title"` // Required
|
||||
Description string `json:"description,omitempty" yaml:"description,omitempty"`
|
||||
|
|
@ -20,80 +20,86 @@ type Info struct {
|
|||
Version string `json:"version" yaml:"version"` // Required
|
||||
}
|
||||
|
||||
func (value *Info) MarshalJSON() ([]byte, error) {
|
||||
return jsoninfo.MarshalStrictStruct(value)
|
||||
// MarshalJSON returns the JSON encoding of Info.
|
||||
func (info Info) MarshalJSON() ([]byte, error) {
|
||||
x, err := info.MarshalYAML()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return json.Marshal(x)
|
||||
}
|
||||
|
||||
func (value *Info) UnmarshalJSON(data []byte) error {
|
||||
return jsoninfo.UnmarshalStrictStruct(data, value)
|
||||
// MarshalYAML returns the YAML encoding of Info.
|
||||
func (info *Info) MarshalYAML() (any, error) {
|
||||
if info == nil {
|
||||
return nil, nil
|
||||
}
|
||||
m := make(map[string]any, 6+len(info.Extensions))
|
||||
for k, v := range info.Extensions {
|
||||
m[k] = v
|
||||
}
|
||||
m["title"] = info.Title
|
||||
if x := info.Description; x != "" {
|
||||
m["description"] = x
|
||||
}
|
||||
if x := info.TermsOfService; x != "" {
|
||||
m["termsOfService"] = x
|
||||
}
|
||||
if x := info.Contact; x != nil {
|
||||
m["contact"] = x
|
||||
}
|
||||
if x := info.License; x != nil {
|
||||
m["license"] = x
|
||||
}
|
||||
m["version"] = info.Version
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func (value *Info) Validate(ctx context.Context) error {
|
||||
if contact := value.Contact; contact != nil {
|
||||
// UnmarshalJSON sets Info to a copy of data.
|
||||
func (info *Info) UnmarshalJSON(data []byte) error {
|
||||
type InfoBis Info
|
||||
var x InfoBis
|
||||
if err := json.Unmarshal(data, &x); err != nil {
|
||||
return unmarshalError(err)
|
||||
}
|
||||
_ = json.Unmarshal(data, &x.Extensions)
|
||||
delete(x.Extensions, originKey)
|
||||
delete(x.Extensions, "title")
|
||||
delete(x.Extensions, "description")
|
||||
delete(x.Extensions, "termsOfService")
|
||||
delete(x.Extensions, "contact")
|
||||
delete(x.Extensions, "license")
|
||||
delete(x.Extensions, "version")
|
||||
if len(x.Extensions) == 0 {
|
||||
x.Extensions = nil
|
||||
}
|
||||
*info = Info(x)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Validate returns an error if Info does not comply with the OpenAPI spec.
|
||||
func (info *Info) Validate(ctx context.Context, opts ...ValidationOption) error {
|
||||
ctx = WithValidationOptions(ctx, opts...)
|
||||
|
||||
if contact := info.Contact; contact != nil {
|
||||
if err := contact.Validate(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if license := value.License; license != nil {
|
||||
if license := info.License; license != nil {
|
||||
if err := license.Validate(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if value.Version == "" {
|
||||
if info.Version == "" {
|
||||
return errors.New("value of version must be a non-empty string")
|
||||
}
|
||||
|
||||
if value.Title == "" {
|
||||
if info.Title == "" {
|
||||
return errors.New("value of title must be a non-empty string")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Contact is specified by OpenAPI/Swagger standard version 3.
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#contactObject
|
||||
type Contact struct {
|
||||
ExtensionProps
|
||||
|
||||
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
||||
URL string `json:"url,omitempty" yaml:"url,omitempty"`
|
||||
Email string `json:"email,omitempty" yaml:"email,omitempty"`
|
||||
}
|
||||
|
||||
func (value *Contact) MarshalJSON() ([]byte, error) {
|
||||
return jsoninfo.MarshalStrictStruct(value)
|
||||
}
|
||||
|
||||
func (value *Contact) UnmarshalJSON(data []byte) error {
|
||||
return jsoninfo.UnmarshalStrictStruct(data, value)
|
||||
}
|
||||
|
||||
func (value *Contact) Validate(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// License is specified by OpenAPI/Swagger standard version 3.
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#licenseObject
|
||||
type License struct {
|
||||
ExtensionProps
|
||||
|
||||
Name string `json:"name" yaml:"name"` // Required
|
||||
URL string `json:"url,omitempty" yaml:"url,omitempty"`
|
||||
}
|
||||
|
||||
func (value *License) MarshalJSON() ([]byte, error) {
|
||||
return jsoninfo.MarshalStrictStruct(value)
|
||||
}
|
||||
|
||||
func (value *License) UnmarshalJSON(data []byte) error {
|
||||
return jsoninfo.UnmarshalStrictStruct(data, value)
|
||||
}
|
||||
|
||||
func (value *License) Validate(ctx context.Context) error {
|
||||
if value.Name == "" {
|
||||
return errors.New("value of license name must be a non-empty string")
|
||||
}
|
||||
return nil
|
||||
return validateExtensions(ctx, info.Extensions)
|
||||
}
|
||||
|
|
|
|||
545
vendor/github.com/getkin/kin-openapi/openapi3/internalize_refs.go
generated
vendored
545
vendor/github.com/getkin/kin-openapi/openapi3/internalize_refs.go
generated
vendored
|
|
@ -2,145 +2,270 @@ package openapi3
|
|||
|
||||
import (
|
||||
"context"
|
||||
"path/filepath"
|
||||
"path"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type RefNameResolver func(string) string
|
||||
// RefNameResolver maps a component to an name that is used as it's internalized name.
|
||||
//
|
||||
// The function should avoid name collisions (i.e. be a injective mapping).
|
||||
// It must only contain characters valid for fixed field names: [IdentifierRegExp].
|
||||
type RefNameResolver func(*T, ComponentRef) string
|
||||
|
||||
// DefaultRefResolver is a default implementation of refNameResolver for the
|
||||
// InternalizeRefs function.
|
||||
//
|
||||
// If a reference points to an element inside a document, it returns the last
|
||||
// element in the reference using filepath.Base. Otherwise if the reference points
|
||||
// to a file, it returns the file name trimmed of all extensions.
|
||||
func DefaultRefNameResolver(ref string) string {
|
||||
if ref == "" {
|
||||
return ""
|
||||
// The external reference is internalized to (hopefully) a unique name. If
|
||||
// the external reference matches (by path) to another reference in the root
|
||||
// document then the name of that component is used.
|
||||
//
|
||||
// The transformation involves:
|
||||
// - Cutting the "#/components/<type>" part.
|
||||
// - Cutting the file extensions (.yaml/.json) from documents.
|
||||
// - Trimming the common directory with the root spec.
|
||||
// - Replace invalid characters with with underscores.
|
||||
//
|
||||
// This is an injective mapping over a "reasonable" amount of the possible openapi
|
||||
// spec domain space but is not perfect. There might be edge cases.
|
||||
func DefaultRefNameResolver(doc *T, ref ComponentRef) string {
|
||||
if ref.RefString() == "" || ref.RefPath() == nil {
|
||||
panic("unable to resolve reference to name")
|
||||
}
|
||||
split := strings.SplitN(ref, "#", 2)
|
||||
if len(split) == 2 {
|
||||
return filepath.Base(split[1])
|
||||
|
||||
name := ref.RefPath()
|
||||
|
||||
// If refering to a component in the root spec, no need to internalize just use
|
||||
// the existing component.
|
||||
// XXX(percivalalb): since this function call is iterating over components behind the
|
||||
// scenes during an internalization call it actually starts interating over
|
||||
// new & replaced internalized components. This might caused some edge cases,
|
||||
// haven't found one yet but this might need to actually be used on a frozen copy
|
||||
// of doc.
|
||||
if nameInRoot, found := ReferencesComponentInRootDocument(doc, ref); found {
|
||||
nameInRoot = strings.TrimPrefix(nameInRoot, "#")
|
||||
|
||||
rootCompURI := copyURI(doc.url)
|
||||
rootCompURI.Fragment = nameInRoot
|
||||
name = rootCompURI
|
||||
}
|
||||
ref = split[0]
|
||||
for ext := filepath.Ext(ref); len(ext) > 0; ext = filepath.Ext(ref) {
|
||||
ref = strings.TrimSuffix(ref, ext)
|
||||
|
||||
filePath, componentPath := name.Path, name.Fragment
|
||||
|
||||
// Cut out the "#/components/<type>" to make the names shorter.
|
||||
// XXX(percivalalb): This might cause collisions but is worth the brevity.
|
||||
if b, a, ok := strings.Cut(componentPath, path.Join("components", ref.CollectionName(), "")); ok {
|
||||
componentPath = path.Join(b, a)
|
||||
}
|
||||
return filepath.Base(ref)
|
||||
|
||||
if filePath != "" {
|
||||
// If the path is the same as the root doc, just remove.
|
||||
if doc.url != nil && filePath == doc.url.Path {
|
||||
filePath = ""
|
||||
}
|
||||
|
||||
// Remove the path extentions to make this JSON/YAML agnostic.
|
||||
for ext := path.Ext(filePath); len(ext) > 0; ext = path.Ext(filePath) {
|
||||
filePath = strings.TrimSuffix(filePath, ext)
|
||||
}
|
||||
|
||||
// Trim the common prefix with the root doc path.
|
||||
if doc.url != nil {
|
||||
commonDir := path.Dir(doc.url.Path)
|
||||
for {
|
||||
if commonDir == "." { // no common prefix
|
||||
break
|
||||
}
|
||||
|
||||
if p, found := cutDirectories(filePath, commonDir); found {
|
||||
filePath = p
|
||||
break
|
||||
}
|
||||
|
||||
commonDir = path.Dir(commonDir)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var internalizedName string
|
||||
|
||||
// Trim .'s & slashes from start e.g. otherwise ./doc.yaml would end up as __doc
|
||||
if filePath != "" {
|
||||
internalizedName = strings.TrimLeft(filePath, "./")
|
||||
}
|
||||
|
||||
if componentPath != "" {
|
||||
if internalizedName != "" {
|
||||
internalizedName += "_"
|
||||
}
|
||||
|
||||
internalizedName += strings.TrimLeft(componentPath, "./")
|
||||
}
|
||||
|
||||
// Replace invalid characters in component fixed field names.
|
||||
internalizedName = InvalidIdentifierCharRegExp.ReplaceAllString(internalizedName, "_")
|
||||
|
||||
return internalizedName
|
||||
}
|
||||
|
||||
func schemaNames(s Schemas) []string {
|
||||
out := make([]string, 0, len(s))
|
||||
for i := range s {
|
||||
out = append(out, i)
|
||||
// cutDirectories removes the given directories from the start of the path if
|
||||
// the path is a child.
|
||||
func cutDirectories(p, dirs string) (string, bool) {
|
||||
if dirs == "" || p == "" {
|
||||
return p, false
|
||||
}
|
||||
return out
|
||||
|
||||
p = strings.TrimRight(p, "/")
|
||||
dirs = strings.TrimRight(dirs, "/")
|
||||
|
||||
var sb strings.Builder
|
||||
sb.Grow(len(ParameterInHeader))
|
||||
for _, segments := range strings.Split(p, "/") {
|
||||
sb.WriteString(segments)
|
||||
|
||||
if sb.String() == p {
|
||||
return strings.TrimPrefix(p, dirs), true
|
||||
}
|
||||
|
||||
sb.WriteRune('/')
|
||||
}
|
||||
|
||||
return p, false
|
||||
}
|
||||
|
||||
func parametersMapNames(s ParametersMap) []string {
|
||||
out := make([]string, 0, len(s))
|
||||
for i := range s {
|
||||
out = append(out, i)
|
||||
}
|
||||
return out
|
||||
func isExternalRef(ref string, parentIsExternal bool) bool {
|
||||
return ref != "" && (!strings.HasPrefix(ref, "#/components/") || parentIsExternal)
|
||||
}
|
||||
|
||||
func isExternalRef(ref string) bool {
|
||||
return ref != "" && !strings.HasPrefix(ref, "#/components/")
|
||||
}
|
||||
|
||||
func (doc *T) addSchemaToSpec(s *SchemaRef, refNameResolver RefNameResolver) {
|
||||
if s == nil || !isExternalRef(s.Ref) {
|
||||
return
|
||||
func (doc *T) addSchemaToSpec(s *SchemaRef, refNameResolver RefNameResolver, parentIsExternal bool) bool {
|
||||
if s == nil || !isExternalRef(s.Ref, parentIsExternal) {
|
||||
return false
|
||||
}
|
||||
|
||||
name := refNameResolver(s.Ref)
|
||||
if _, ok := doc.Components.Schemas[name]; ok {
|
||||
s.Ref = "#/components/schemas/" + name
|
||||
return
|
||||
name := refNameResolver(doc, s)
|
||||
if doc.Components != nil {
|
||||
if _, ok := doc.Components.Schemas[name]; ok {
|
||||
s.Ref = "#/components/schemas/" + name
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
if doc.Components == nil {
|
||||
doc.Components = &Components{}
|
||||
}
|
||||
if doc.Components.Schemas == nil {
|
||||
doc.Components.Schemas = make(Schemas)
|
||||
}
|
||||
doc.Components.Schemas[name] = s.Value.NewRef()
|
||||
s.Ref = "#/components/schemas/" + name
|
||||
return true
|
||||
}
|
||||
|
||||
func (doc *T) addParameterToSpec(p *ParameterRef, refNameResolver RefNameResolver) {
|
||||
if p == nil || !isExternalRef(p.Ref) {
|
||||
return
|
||||
func (doc *T) addParameterToSpec(p *ParameterRef, refNameResolver RefNameResolver, parentIsExternal bool) bool {
|
||||
if p == nil || !isExternalRef(p.Ref, parentIsExternal) {
|
||||
return false
|
||||
}
|
||||
name := refNameResolver(p.Ref)
|
||||
if _, ok := doc.Components.Parameters[name]; ok {
|
||||
p.Ref = "#/components/parameters/" + name
|
||||
return
|
||||
name := refNameResolver(doc, p)
|
||||
if doc.Components != nil {
|
||||
if _, ok := doc.Components.Parameters[name]; ok {
|
||||
p.Ref = "#/components/parameters/" + name
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
if doc.Components == nil {
|
||||
doc.Components = &Components{}
|
||||
}
|
||||
if doc.Components.Parameters == nil {
|
||||
doc.Components.Parameters = make(ParametersMap)
|
||||
}
|
||||
doc.Components.Parameters[name] = &ParameterRef{Value: p.Value}
|
||||
p.Ref = "#/components/parameters/" + name
|
||||
return true
|
||||
}
|
||||
|
||||
func (doc *T) addHeaderToSpec(h *HeaderRef, refNameResolver RefNameResolver) {
|
||||
if h == nil || !isExternalRef(h.Ref) {
|
||||
return
|
||||
func (doc *T) addHeaderToSpec(h *HeaderRef, refNameResolver RefNameResolver, parentIsExternal bool) bool {
|
||||
if h == nil || !isExternalRef(h.Ref, parentIsExternal) {
|
||||
return false
|
||||
}
|
||||
name := refNameResolver(h.Ref)
|
||||
if _, ok := doc.Components.Headers[name]; ok {
|
||||
h.Ref = "#/components/headers/" + name
|
||||
return
|
||||
name := refNameResolver(doc, h)
|
||||
if doc.Components != nil {
|
||||
if _, ok := doc.Components.Headers[name]; ok {
|
||||
h.Ref = "#/components/headers/" + name
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
if doc.Components == nil {
|
||||
doc.Components = &Components{}
|
||||
}
|
||||
if doc.Components.Headers == nil {
|
||||
doc.Components.Headers = make(Headers)
|
||||
}
|
||||
doc.Components.Headers[name] = &HeaderRef{Value: h.Value}
|
||||
h.Ref = "#/components/headers/" + name
|
||||
return true
|
||||
}
|
||||
|
||||
func (doc *T) addRequestBodyToSpec(r *RequestBodyRef, refNameResolver RefNameResolver) {
|
||||
if r == nil || !isExternalRef(r.Ref) {
|
||||
return
|
||||
func (doc *T) addRequestBodyToSpec(r *RequestBodyRef, refNameResolver RefNameResolver, parentIsExternal bool) bool {
|
||||
if r == nil || !isExternalRef(r.Ref, parentIsExternal) {
|
||||
return false
|
||||
}
|
||||
name := refNameResolver(r.Ref)
|
||||
if _, ok := doc.Components.RequestBodies[name]; ok {
|
||||
r.Ref = "#/components/requestBodies/" + name
|
||||
return
|
||||
name := refNameResolver(doc, r)
|
||||
if doc.Components != nil {
|
||||
if _, ok := doc.Components.RequestBodies[name]; ok {
|
||||
r.Ref = "#/components/requestBodies/" + name
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
if doc.Components == nil {
|
||||
doc.Components = &Components{}
|
||||
}
|
||||
if doc.Components.RequestBodies == nil {
|
||||
doc.Components.RequestBodies = make(RequestBodies)
|
||||
}
|
||||
doc.Components.RequestBodies[name] = &RequestBodyRef{Value: r.Value}
|
||||
r.Ref = "#/components/requestBodies/" + name
|
||||
return true
|
||||
}
|
||||
|
||||
func (doc *T) addResponseToSpec(r *ResponseRef, refNameResolver RefNameResolver) {
|
||||
if r == nil || !isExternalRef(r.Ref) {
|
||||
return
|
||||
func (doc *T) addResponseToSpec(r *ResponseRef, refNameResolver RefNameResolver, parentIsExternal bool) bool {
|
||||
if r == nil || !isExternalRef(r.Ref, parentIsExternal) {
|
||||
return false
|
||||
}
|
||||
name := refNameResolver(r.Ref)
|
||||
if _, ok := doc.Components.Responses[name]; ok {
|
||||
r.Ref = "#/components/responses/" + name
|
||||
return
|
||||
name := refNameResolver(doc, r)
|
||||
if doc.Components != nil {
|
||||
if _, ok := doc.Components.Responses[name]; ok {
|
||||
r.Ref = "#/components/responses/" + name
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
if doc.Components == nil {
|
||||
doc.Components = &Components{}
|
||||
}
|
||||
if doc.Components.Responses == nil {
|
||||
doc.Components.Responses = make(Responses)
|
||||
doc.Components.Responses = make(ResponseBodies)
|
||||
}
|
||||
doc.Components.Responses[name] = &ResponseRef{Value: r.Value}
|
||||
r.Ref = "#/components/responses/" + name
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (doc *T) addSecuritySchemeToSpec(ss *SecuritySchemeRef, refNameResolver RefNameResolver) {
|
||||
if ss == nil || !isExternalRef(ss.Ref) {
|
||||
func (doc *T) addSecuritySchemeToSpec(ss *SecuritySchemeRef, refNameResolver RefNameResolver, parentIsExternal bool) {
|
||||
if ss == nil || !isExternalRef(ss.Ref, parentIsExternal) {
|
||||
return
|
||||
}
|
||||
name := refNameResolver(ss.Ref)
|
||||
if _, ok := doc.Components.SecuritySchemes[name]; ok {
|
||||
ss.Ref = "#/components/securitySchemes/" + name
|
||||
return
|
||||
name := refNameResolver(doc, ss)
|
||||
if doc.Components != nil {
|
||||
if _, ok := doc.Components.SecuritySchemes[name]; ok {
|
||||
ss.Ref = "#/components/securitySchemes/" + name
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if doc.Components == nil {
|
||||
doc.Components = &Components{}
|
||||
}
|
||||
if doc.Components.SecuritySchemes == nil {
|
||||
doc.Components.SecuritySchemes = make(SecuritySchemes)
|
||||
|
|
@ -150,14 +275,20 @@ func (doc *T) addSecuritySchemeToSpec(ss *SecuritySchemeRef, refNameResolver Ref
|
|||
|
||||
}
|
||||
|
||||
func (doc *T) addExampleToSpec(e *ExampleRef, refNameResolver RefNameResolver) {
|
||||
if e == nil || !isExternalRef(e.Ref) {
|
||||
func (doc *T) addExampleToSpec(e *ExampleRef, refNameResolver RefNameResolver, parentIsExternal bool) {
|
||||
if e == nil || !isExternalRef(e.Ref, parentIsExternal) {
|
||||
return
|
||||
}
|
||||
name := refNameResolver(e.Ref)
|
||||
if _, ok := doc.Components.Examples[name]; ok {
|
||||
e.Ref = "#/components/examples/" + name
|
||||
return
|
||||
name := refNameResolver(doc, e)
|
||||
if doc.Components != nil {
|
||||
if _, ok := doc.Components.Examples[name]; ok {
|
||||
e.Ref = "#/components/examples/" + name
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if doc.Components == nil {
|
||||
doc.Components = &Components{}
|
||||
}
|
||||
if doc.Components.Examples == nil {
|
||||
doc.Components.Examples = make(Examples)
|
||||
|
|
@ -167,14 +298,20 @@ func (doc *T) addExampleToSpec(e *ExampleRef, refNameResolver RefNameResolver) {
|
|||
|
||||
}
|
||||
|
||||
func (doc *T) addLinkToSpec(l *LinkRef, refNameResolver RefNameResolver) {
|
||||
if l == nil || !isExternalRef(l.Ref) {
|
||||
func (doc *T) addLinkToSpec(l *LinkRef, refNameResolver RefNameResolver, parentIsExternal bool) {
|
||||
if l == nil || !isExternalRef(l.Ref, parentIsExternal) {
|
||||
return
|
||||
}
|
||||
name := refNameResolver(l.Ref)
|
||||
if _, ok := doc.Components.Links[name]; ok {
|
||||
l.Ref = "#/components/links/" + name
|
||||
return
|
||||
name := refNameResolver(doc, l)
|
||||
if doc.Components != nil {
|
||||
if _, ok := doc.Components.Links[name]; ok {
|
||||
l.Ref = "#/components/links/" + name
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if doc.Components == nil {
|
||||
doc.Components = &Components{}
|
||||
}
|
||||
if doc.Components.Links == nil {
|
||||
doc.Components.Links = make(Links)
|
||||
|
|
@ -184,124 +321,158 @@ func (doc *T) addLinkToSpec(l *LinkRef, refNameResolver RefNameResolver) {
|
|||
|
||||
}
|
||||
|
||||
func (doc *T) addCallbackToSpec(c *CallbackRef, refNameResolver RefNameResolver) {
|
||||
if c == nil || !isExternalRef(c.Ref) {
|
||||
return
|
||||
func (doc *T) addCallbackToSpec(c *CallbackRef, refNameResolver RefNameResolver, parentIsExternal bool) bool {
|
||||
if c == nil || !isExternalRef(c.Ref, parentIsExternal) {
|
||||
return false
|
||||
}
|
||||
name := refNameResolver(c.Ref)
|
||||
if _, ok := doc.Components.Callbacks[name]; ok {
|
||||
c.Ref = "#/components/callbacks/" + name
|
||||
name := refNameResolver(doc, c)
|
||||
|
||||
if doc.Components == nil {
|
||||
doc.Components = &Components{}
|
||||
}
|
||||
if doc.Components.Callbacks == nil {
|
||||
doc.Components.Callbacks = make(Callbacks)
|
||||
}
|
||||
doc.Components.Callbacks[name] = &CallbackRef{Value: c.Value}
|
||||
c.Ref = "#/components/callbacks/" + name
|
||||
doc.Components.Callbacks[name] = &CallbackRef{Value: c.Value}
|
||||
return true
|
||||
}
|
||||
|
||||
func (doc *T) derefSchema(s *Schema, refNameResolver RefNameResolver) {
|
||||
if s == nil {
|
||||
func (doc *T) derefSchema(s *Schema, refNameResolver RefNameResolver, parentIsExternal bool) {
|
||||
if s == nil || doc.isVisitedSchema(s) {
|
||||
return
|
||||
}
|
||||
|
||||
for _, list := range []SchemaRefs{s.AllOf, s.AnyOf, s.OneOf} {
|
||||
for _, s2 := range list {
|
||||
doc.addSchemaToSpec(s2, refNameResolver)
|
||||
isExternal := doc.addSchemaToSpec(s2, refNameResolver, parentIsExternal)
|
||||
if s2 != nil {
|
||||
doc.derefSchema(s2.Value, refNameResolver)
|
||||
doc.derefSchema(s2.Value, refNameResolver, isExternal || parentIsExternal)
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, s2 := range s.Properties {
|
||||
doc.addSchemaToSpec(s2, refNameResolver)
|
||||
|
||||
for _, name := range componentNames(s.Properties) {
|
||||
s2 := s.Properties[name]
|
||||
isExternal := doc.addSchemaToSpec(s2, refNameResolver, parentIsExternal)
|
||||
if s2 != nil {
|
||||
doc.derefSchema(s2.Value, refNameResolver)
|
||||
doc.derefSchema(s2.Value, refNameResolver, isExternal || parentIsExternal)
|
||||
}
|
||||
}
|
||||
for _, ref := range []*SchemaRef{s.Not, s.AdditionalProperties, s.Items} {
|
||||
doc.addSchemaToSpec(ref, refNameResolver)
|
||||
for _, ref := range []*SchemaRef{s.Not, s.AdditionalProperties.Schema, s.Items} {
|
||||
isExternal := doc.addSchemaToSpec(ref, refNameResolver, parentIsExternal)
|
||||
if ref != nil {
|
||||
doc.derefSchema(ref.Value, refNameResolver)
|
||||
doc.derefSchema(ref.Value, refNameResolver, isExternal || parentIsExternal)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (doc *T) derefHeaders(hs Headers, refNameResolver RefNameResolver) {
|
||||
for _, h := range hs {
|
||||
doc.addHeaderToSpec(h, refNameResolver)
|
||||
doc.derefParameter(h.Value.Parameter, refNameResolver)
|
||||
func (doc *T) derefHeaders(hs Headers, refNameResolver RefNameResolver, parentIsExternal bool) {
|
||||
for _, name := range componentNames(hs) {
|
||||
h := hs[name]
|
||||
isExternal := doc.addHeaderToSpec(h, refNameResolver, parentIsExternal)
|
||||
if doc.isVisitedHeader(h.Value) {
|
||||
continue
|
||||
}
|
||||
doc.derefParameter(h.Value.Parameter, refNameResolver, parentIsExternal || isExternal)
|
||||
}
|
||||
}
|
||||
|
||||
func (doc *T) derefExamples(es Examples, refNameResolver RefNameResolver) {
|
||||
for _, e := range es {
|
||||
doc.addExampleToSpec(e, refNameResolver)
|
||||
func (doc *T) derefExamples(es Examples, refNameResolver RefNameResolver, parentIsExternal bool) {
|
||||
for _, name := range componentNames(es) {
|
||||
e := es[name]
|
||||
doc.addExampleToSpec(e, refNameResolver, parentIsExternal)
|
||||
}
|
||||
}
|
||||
|
||||
func (doc *T) derefContent(c Content, refNameResolver RefNameResolver) {
|
||||
for _, mediatype := range c {
|
||||
doc.addSchemaToSpec(mediatype.Schema, refNameResolver)
|
||||
func (doc *T) derefContent(c Content, refNameResolver RefNameResolver, parentIsExternal bool) {
|
||||
for _, name := range componentNames(c) {
|
||||
mediatype := c[name]
|
||||
isExternal := doc.addSchemaToSpec(mediatype.Schema, refNameResolver, parentIsExternal)
|
||||
if mediatype.Schema != nil {
|
||||
doc.derefSchema(mediatype.Schema.Value, refNameResolver)
|
||||
doc.derefSchema(mediatype.Schema.Value, refNameResolver, isExternal || parentIsExternal)
|
||||
}
|
||||
doc.derefExamples(mediatype.Examples, refNameResolver)
|
||||
for _, e := range mediatype.Encoding {
|
||||
doc.derefHeaders(e.Headers, refNameResolver)
|
||||
doc.derefExamples(mediatype.Examples, refNameResolver, parentIsExternal)
|
||||
for _, name := range componentNames(mediatype.Encoding) {
|
||||
e := mediatype.Encoding[name]
|
||||
doc.derefHeaders(e.Headers, refNameResolver, parentIsExternal)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (doc *T) derefLinks(ls Links, refNameResolver RefNameResolver) {
|
||||
for _, l := range ls {
|
||||
doc.addLinkToSpec(l, refNameResolver)
|
||||
func (doc *T) derefLinks(ls Links, refNameResolver RefNameResolver, parentIsExternal bool) {
|
||||
for _, name := range componentNames(ls) {
|
||||
l := ls[name]
|
||||
doc.addLinkToSpec(l, refNameResolver, parentIsExternal)
|
||||
}
|
||||
}
|
||||
|
||||
func (doc *T) derefResponses(es Responses, refNameResolver RefNameResolver) {
|
||||
for _, e := range es {
|
||||
doc.addResponseToSpec(e, refNameResolver)
|
||||
if e.Value != nil {
|
||||
doc.derefHeaders(e.Value.Headers, refNameResolver)
|
||||
doc.derefContent(e.Value.Content, refNameResolver)
|
||||
doc.derefLinks(e.Value.Links, refNameResolver)
|
||||
}
|
||||
func (doc *T) derefResponse(r *ResponseRef, refNameResolver RefNameResolver, parentIsExternal bool) {
|
||||
isExternal := doc.addResponseToSpec(r, refNameResolver, parentIsExternal)
|
||||
if v := r.Value; v != nil {
|
||||
doc.derefHeaders(v.Headers, refNameResolver, isExternal || parentIsExternal)
|
||||
doc.derefContent(v.Content, refNameResolver, isExternal || parentIsExternal)
|
||||
doc.derefLinks(v.Links, refNameResolver, isExternal || parentIsExternal)
|
||||
}
|
||||
}
|
||||
|
||||
func (doc *T) derefParameter(p Parameter, refNameResolver RefNameResolver) {
|
||||
doc.addSchemaToSpec(p.Schema, refNameResolver)
|
||||
doc.derefContent(p.Content, refNameResolver)
|
||||
func (doc *T) derefResponses(rs *Responses, refNameResolver RefNameResolver, parentIsExternal bool) {
|
||||
doc.derefResponseBodies(rs.Map(), refNameResolver, parentIsExternal)
|
||||
}
|
||||
|
||||
func (doc *T) derefResponseBodies(es ResponseBodies, refNameResolver RefNameResolver, parentIsExternal bool) {
|
||||
for _, name := range componentNames(es) {
|
||||
e := es[name]
|
||||
doc.derefResponse(e, refNameResolver, parentIsExternal)
|
||||
}
|
||||
}
|
||||
|
||||
func (doc *T) derefParameter(p Parameter, refNameResolver RefNameResolver, parentIsExternal bool) {
|
||||
isExternal := doc.addSchemaToSpec(p.Schema, refNameResolver, parentIsExternal)
|
||||
doc.derefContent(p.Content, refNameResolver, parentIsExternal)
|
||||
if p.Schema != nil {
|
||||
doc.derefSchema(p.Schema.Value, refNameResolver)
|
||||
doc.derefSchema(p.Schema.Value, refNameResolver, isExternal || parentIsExternal)
|
||||
}
|
||||
}
|
||||
|
||||
func (doc *T) derefRequestBody(r RequestBody, refNameResolver RefNameResolver) {
|
||||
doc.derefContent(r.Content, refNameResolver)
|
||||
func (doc *T) derefRequestBody(r RequestBody, refNameResolver RefNameResolver, parentIsExternal bool) {
|
||||
doc.derefContent(r.Content, refNameResolver, parentIsExternal)
|
||||
}
|
||||
|
||||
func (doc *T) derefPaths(paths map[string]*PathItem, refNameResolver RefNameResolver) {
|
||||
for _, ops := range paths {
|
||||
func (doc *T) derefPaths(paths map[string]*PathItem, refNameResolver RefNameResolver, parentIsExternal bool) {
|
||||
for _, name := range componentNames(paths) {
|
||||
ops := paths[name]
|
||||
pathIsExternal := isExternalRef(ops.Ref, parentIsExternal)
|
||||
// inline full operations
|
||||
ops.Ref = ""
|
||||
|
||||
for _, op := range ops.Operations() {
|
||||
doc.addRequestBodyToSpec(op.RequestBody, refNameResolver)
|
||||
if op.RequestBody != nil && op.RequestBody.Value != nil {
|
||||
doc.derefRequestBody(*op.RequestBody.Value, refNameResolver)
|
||||
for _, param := range ops.Parameters {
|
||||
isExternal := doc.addParameterToSpec(param, refNameResolver, pathIsExternal)
|
||||
if param.Value != nil {
|
||||
doc.derefParameter(*param.Value, refNameResolver, pathIsExternal || isExternal)
|
||||
}
|
||||
for _, cb := range op.Callbacks {
|
||||
doc.addCallbackToSpec(cb, refNameResolver)
|
||||
}
|
||||
|
||||
opsWithMethod := ops.Operations()
|
||||
for _, name := range componentNames(opsWithMethod) {
|
||||
op := opsWithMethod[name]
|
||||
isExternal := doc.addRequestBodyToSpec(op.RequestBody, refNameResolver, pathIsExternal)
|
||||
if op.RequestBody != nil && op.RequestBody.Value != nil {
|
||||
doc.derefRequestBody(*op.RequestBody.Value, refNameResolver, pathIsExternal || isExternal)
|
||||
}
|
||||
for _, name := range componentNames(op.Callbacks) {
|
||||
cb := op.Callbacks[name]
|
||||
isExternal := doc.addCallbackToSpec(cb, refNameResolver, pathIsExternal)
|
||||
if cb.Value != nil {
|
||||
doc.derefPaths(*cb.Value, refNameResolver)
|
||||
cbValue := (*cb.Value).Map()
|
||||
doc.derefPaths(cbValue, refNameResolver, pathIsExternal || isExternal)
|
||||
}
|
||||
}
|
||||
doc.derefResponses(op.Responses, refNameResolver)
|
||||
doc.derefResponses(op.Responses, refNameResolver, pathIsExternal)
|
||||
for _, param := range op.Parameters {
|
||||
doc.addParameterToSpec(param, refNameResolver)
|
||||
isExternal := doc.addParameterToSpec(param, refNameResolver, pathIsExternal)
|
||||
if param.Value != nil {
|
||||
doc.derefParameter(*param.Value, refNameResolver)
|
||||
doc.derefParameter(*param.Value, refNameResolver, pathIsExternal || isExternal)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -314,56 +485,62 @@ func (doc *T) derefPaths(paths map[string]*PathItem, refNameResolver RefNameReso
|
|||
// refNameResolver takes in references to returns a name to store the reference under locally.
|
||||
// It MUST return a unique name for each reference type.
|
||||
// A default implementation is provided that will suffice for most use cases. See the function
|
||||
// documention for more details.
|
||||
// documentation for more details.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// doc.InternalizeRefs(context.Background(), nil)
|
||||
func (doc *T) InternalizeRefs(ctx context.Context, refNameResolver func(ref string) string) {
|
||||
// doc.InternalizeRefs(context.Background(), nil)
|
||||
func (doc *T) InternalizeRefs(ctx context.Context, refNameResolver func(*T, ComponentRef) string) {
|
||||
doc.resetVisited()
|
||||
|
||||
if refNameResolver == nil {
|
||||
refNameResolver = DefaultRefNameResolver
|
||||
}
|
||||
|
||||
// Handle components section
|
||||
names := schemaNames(doc.Components.Schemas)
|
||||
for _, name := range names {
|
||||
schema := doc.Components.Schemas[name]
|
||||
doc.addSchemaToSpec(schema, refNameResolver)
|
||||
if schema != nil {
|
||||
schema.Ref = "" // always dereference the top level
|
||||
doc.derefSchema(schema.Value, refNameResolver)
|
||||
if components := doc.Components; components != nil {
|
||||
for _, name := range componentNames(components.Schemas) {
|
||||
schema := components.Schemas[name]
|
||||
isExternal := doc.addSchemaToSpec(schema, refNameResolver, false)
|
||||
if schema != nil {
|
||||
schema.Ref = "" // always dereference the top level
|
||||
doc.derefSchema(schema.Value, refNameResolver, isExternal)
|
||||
}
|
||||
}
|
||||
}
|
||||
names = parametersMapNames(doc.Components.Parameters)
|
||||
for _, name := range names {
|
||||
p := doc.Components.Parameters[name]
|
||||
doc.addParameterToSpec(p, refNameResolver)
|
||||
if p != nil && p.Value != nil {
|
||||
p.Ref = "" // always dereference the top level
|
||||
doc.derefParameter(*p.Value, refNameResolver)
|
||||
for _, name := range componentNames(components.Parameters) {
|
||||
p := components.Parameters[name]
|
||||
isExternal := doc.addParameterToSpec(p, refNameResolver, false)
|
||||
if p != nil && p.Value != nil {
|
||||
p.Ref = "" // always dereference the top level
|
||||
doc.derefParameter(*p.Value, refNameResolver, isExternal)
|
||||
}
|
||||
}
|
||||
}
|
||||
doc.derefHeaders(doc.Components.Headers, refNameResolver)
|
||||
for _, req := range doc.Components.RequestBodies {
|
||||
doc.addRequestBodyToSpec(req, refNameResolver)
|
||||
if req != nil && req.Value != nil {
|
||||
req.Ref = "" // always dereference the top level
|
||||
doc.derefRequestBody(*req.Value, refNameResolver)
|
||||
doc.derefHeaders(components.Headers, refNameResolver, false)
|
||||
for _, name := range componentNames(components.RequestBodies) {
|
||||
req := components.RequestBodies[name]
|
||||
isExternal := doc.addRequestBodyToSpec(req, refNameResolver, false)
|
||||
if req != nil && req.Value != nil {
|
||||
req.Ref = "" // always dereference the top level
|
||||
doc.derefRequestBody(*req.Value, refNameResolver, isExternal)
|
||||
}
|
||||
}
|
||||
}
|
||||
doc.derefResponses(doc.Components.Responses, refNameResolver)
|
||||
for _, ss := range doc.Components.SecuritySchemes {
|
||||
doc.addSecuritySchemeToSpec(ss, refNameResolver)
|
||||
}
|
||||
doc.derefExamples(doc.Components.Examples, refNameResolver)
|
||||
doc.derefLinks(doc.Components.Links, refNameResolver)
|
||||
for _, cb := range doc.Components.Callbacks {
|
||||
doc.addCallbackToSpec(cb, refNameResolver)
|
||||
if cb != nil && cb.Value != nil {
|
||||
cb.Ref = "" // always dereference the top level
|
||||
doc.derefPaths(*cb.Value, refNameResolver)
|
||||
doc.derefResponseBodies(components.Responses, refNameResolver, false)
|
||||
for _, name := range componentNames(components.SecuritySchemes) {
|
||||
ss := components.SecuritySchemes[name]
|
||||
doc.addSecuritySchemeToSpec(ss, refNameResolver, false)
|
||||
}
|
||||
doc.derefExamples(components.Examples, refNameResolver, false)
|
||||
doc.derefLinks(components.Links, refNameResolver, false)
|
||||
|
||||
for _, name := range componentNames(components.Callbacks) {
|
||||
cb := components.Callbacks[name]
|
||||
isExternal := doc.addCallbackToSpec(cb, refNameResolver, false)
|
||||
if cb != nil && cb.Value != nil {
|
||||
cb.Ref = "" // always dereference the top level
|
||||
cbValue := (*cb.Value).Map()
|
||||
doc.derefPaths(cbValue, refNameResolver, isExternal)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
doc.derefPaths(doc.Paths, refNameResolver)
|
||||
doc.derefPaths(doc.Paths.Map(), refNameResolver, false)
|
||||
}
|
||||
|
|
|
|||
68
vendor/github.com/getkin/kin-openapi/openapi3/license.go
generated
vendored
Normal file
68
vendor/github.com/getkin/kin-openapi/openapi3/license.go
generated
vendored
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
package openapi3
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
)
|
||||
|
||||
// License is specified by OpenAPI/Swagger standard version 3.
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#license-object
|
||||
type License struct {
|
||||
Extensions map[string]any `json:"-" yaml:"-"`
|
||||
Origin *Origin `json:"__origin__,omitempty" yaml:"__origin__,omitempty"`
|
||||
|
||||
Name string `json:"name" yaml:"name"` // Required
|
||||
URL string `json:"url,omitempty" yaml:"url,omitempty"`
|
||||
}
|
||||
|
||||
// MarshalJSON returns the JSON encoding of License.
|
||||
func (license License) MarshalJSON() ([]byte, error) {
|
||||
x, err := license.MarshalYAML()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return json.Marshal(x)
|
||||
}
|
||||
|
||||
// MarshalYAML returns the YAML encoding of License.
|
||||
func (license License) MarshalYAML() (any, error) {
|
||||
m := make(map[string]any, 2+len(license.Extensions))
|
||||
for k, v := range license.Extensions {
|
||||
m[k] = v
|
||||
}
|
||||
m["name"] = license.Name
|
||||
if x := license.URL; x != "" {
|
||||
m["url"] = x
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON sets License to a copy of data.
|
||||
func (license *License) UnmarshalJSON(data []byte) error {
|
||||
type LicenseBis License
|
||||
var x LicenseBis
|
||||
if err := json.Unmarshal(data, &x); err != nil {
|
||||
return unmarshalError(err)
|
||||
}
|
||||
_ = json.Unmarshal(data, &x.Extensions)
|
||||
delete(x.Extensions, originKey)
|
||||
delete(x.Extensions, "name")
|
||||
delete(x.Extensions, "url")
|
||||
if len(x.Extensions) == 0 {
|
||||
x.Extensions = nil
|
||||
}
|
||||
*license = License(x)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Validate returns an error if License does not comply with the OpenAPI spec.
|
||||
func (license *License) Validate(ctx context.Context, opts ...ValidationOption) error {
|
||||
ctx = WithValidationOptions(ctx, opts...)
|
||||
|
||||
if license.Name == "" {
|
||||
return errors.New("value of license name must be a non-empty string")
|
||||
}
|
||||
|
||||
return validateExtensions(ctx, license.Extensions)
|
||||
}
|
||||
126
vendor/github.com/getkin/kin-openapi/openapi3/link.go
generated
vendored
126
vendor/github.com/getkin/kin-openapi/openapi3/link.go
generated
vendored
|
|
@ -2,56 +2,102 @@ package openapi3
|
|||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/getkin/kin-openapi/jsoninfo"
|
||||
"github.com/go-openapi/jsonpointer"
|
||||
)
|
||||
|
||||
type Links map[string]*LinkRef
|
||||
|
||||
func (l Links) JSONLookup(token string) (interface{}, error) {
|
||||
ref, ok := l[token]
|
||||
if ok == false {
|
||||
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#linkObject
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#link-object
|
||||
type Link struct {
|
||||
ExtensionProps
|
||||
Extensions map[string]any `json:"-" yaml:"-"`
|
||||
Origin *Origin `json:"__origin__,omitempty" yaml:"__origin__,omitempty"`
|
||||
|
||||
OperationRef string `json:"operationRef,omitempty" yaml:"operationRef,omitempty"`
|
||||
OperationID string `json:"operationId,omitempty" yaml:"operationId,omitempty"`
|
||||
Description string `json:"description,omitempty" yaml:"description,omitempty"`
|
||||
Parameters map[string]interface{} `json:"parameters,omitempty" yaml:"parameters,omitempty"`
|
||||
Server *Server `json:"server,omitempty" yaml:"server,omitempty"`
|
||||
RequestBody interface{} `json:"requestBody,omitempty" yaml:"requestBody,omitempty"`
|
||||
OperationRef string `json:"operationRef,omitempty" yaml:"operationRef,omitempty"`
|
||||
OperationID string `json:"operationId,omitempty" yaml:"operationId,omitempty"`
|
||||
Description string `json:"description,omitempty" yaml:"description,omitempty"`
|
||||
Parameters map[string]any `json:"parameters,omitempty" yaml:"parameters,omitempty"`
|
||||
Server *Server `json:"server,omitempty" yaml:"server,omitempty"`
|
||||
RequestBody any `json:"requestBody,omitempty" yaml:"requestBody,omitempty"`
|
||||
}
|
||||
|
||||
func (value *Link) MarshalJSON() ([]byte, error) {
|
||||
return jsoninfo.MarshalStrictStruct(value)
|
||||
}
|
||||
|
||||
func (value *Link) UnmarshalJSON(data []byte) error {
|
||||
return jsoninfo.UnmarshalStrictStruct(data, value)
|
||||
}
|
||||
|
||||
func (value *Link) Validate(ctx context.Context) error {
|
||||
if value.OperationID == "" && value.OperationRef == "" {
|
||||
return errors.New("missing operationId or operationRef on link")
|
||||
// MarshalJSON returns the JSON encoding of Link.
|
||||
func (link Link) MarshalJSON() ([]byte, error) {
|
||||
x, err := link.MarshalYAML()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if value.OperationID != "" && value.OperationRef != "" {
|
||||
return fmt.Errorf("operationId %q and operationRef %q are mutually exclusive", value.OperationID, value.OperationRef)
|
||||
return json.Marshal(x)
|
||||
}
|
||||
|
||||
// MarshalYAML returns the YAML encoding of Link.
|
||||
func (link Link) MarshalYAML() (any, error) {
|
||||
m := make(map[string]any, 6+len(link.Extensions))
|
||||
for k, v := range link.Extensions {
|
||||
m[k] = v
|
||||
}
|
||||
|
||||
if x := link.OperationRef; x != "" {
|
||||
m["operationRef"] = x
|
||||
}
|
||||
if x := link.OperationID; x != "" {
|
||||
m["operationId"] = x
|
||||
}
|
||||
if x := link.Description; x != "" {
|
||||
m["description"] = x
|
||||
}
|
||||
if x := link.Parameters; len(x) != 0 {
|
||||
m["parameters"] = x
|
||||
}
|
||||
if x := link.Server; x != nil {
|
||||
m["server"] = x
|
||||
}
|
||||
if x := link.RequestBody; x != nil {
|
||||
m["requestBody"] = x
|
||||
}
|
||||
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON sets Link to a copy of data.
|
||||
func (link *Link) UnmarshalJSON(data []byte) error {
|
||||
type LinkBis Link
|
||||
var x LinkBis
|
||||
if err := json.Unmarshal(data, &x); err != nil {
|
||||
return unmarshalError(err)
|
||||
}
|
||||
_ = json.Unmarshal(data, &x.Extensions)
|
||||
|
||||
delete(x.Extensions, originKey)
|
||||
delete(x.Extensions, "operationRef")
|
||||
delete(x.Extensions, "operationId")
|
||||
delete(x.Extensions, "description")
|
||||
delete(x.Extensions, "parameters")
|
||||
delete(x.Extensions, "server")
|
||||
delete(x.Extensions, "requestBody")
|
||||
if len(x.Extensions) == 0 {
|
||||
x.Extensions = nil
|
||||
}
|
||||
*link = Link(x)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Validate returns an error if Link does not comply with the OpenAPI spec.
|
||||
func (link *Link) Validate(ctx context.Context, opts ...ValidationOption) error {
|
||||
ctx = WithValidationOptions(ctx, opts...)
|
||||
|
||||
if link.OperationID == "" && link.OperationRef == "" {
|
||||
return errors.New("missing operationId or operationRef on link")
|
||||
}
|
||||
if link.OperationID != "" && link.OperationRef != "" {
|
||||
return fmt.Errorf("operationId %q and operationRef %q are mutually exclusive", link.OperationID, link.OperationRef)
|
||||
}
|
||||
|
||||
return validateExtensions(ctx, link.Extensions)
|
||||
}
|
||||
|
||||
// UnmarshalJSON sets Links to a copy of data.
|
||||
func (links *Links) UnmarshalJSON(data []byte) (err error) {
|
||||
*links, _, err = unmarshalStringMapP[LinkRef](data)
|
||||
return
|
||||
}
|
||||
|
|
|
|||
950
vendor/github.com/getkin/kin-openapi/openapi3/loader.go
generated
vendored
950
vendor/github.com/getkin/kin-openapi/openapi3/loader.go
generated
vendored
File diff suppressed because it is too large
Load diff
26
vendor/github.com/getkin/kin-openapi/openapi3/loader_uri_reader.go
generated
vendored
26
vendor/github.com/getkin/kin-openapi/openapi3/loader_uri_reader.go
generated
vendored
|
|
@ -3,16 +3,20 @@ package openapi3
|
|||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// ReadFromURIFunc defines a function which reads the contents of a resource
|
||||
// located at a URI.
|
||||
type ReadFromURIFunc func(loader *Loader, url *url.URL) ([]byte, error)
|
||||
|
||||
var uriMu = &sync.RWMutex{}
|
||||
|
||||
// ErrURINotSupported indicates the ReadFromURIFunc does not know how to handle a
|
||||
// given URI.
|
||||
var ErrURINotSupported = errors.New("unsupported URI")
|
||||
|
|
@ -60,19 +64,22 @@ func ReadFromHTTP(cl *http.Client) ReadFromURIFunc {
|
|||
if resp.StatusCode > 399 {
|
||||
return nil, fmt.Errorf("error loading %q: request returned status code %d", location.String(), resp.StatusCode)
|
||||
}
|
||||
return ioutil.ReadAll(resp.Body)
|
||||
return io.ReadAll(resp.Body)
|
||||
}
|
||||
}
|
||||
|
||||
func is_file(location *url.URL) bool {
|
||||
return location.Path != "" &&
|
||||
location.Host == "" &&
|
||||
(location.Scheme == "" || location.Scheme == "file")
|
||||
}
|
||||
|
||||
// ReadFromFile is a ReadFromURIFunc which reads local file URIs.
|
||||
func ReadFromFile(loader *Loader, location *url.URL) ([]byte, error) {
|
||||
if location.Host != "" {
|
||||
if !is_file(location) {
|
||||
return nil, ErrURINotSupported
|
||||
}
|
||||
if location.Scheme != "" && location.Scheme != "file" {
|
||||
return nil, ErrURINotSupported
|
||||
}
|
||||
return ioutil.ReadFile(location.Path)
|
||||
return os.ReadFile(filepath.FromSlash(location.Path))
|
||||
}
|
||||
|
||||
// URIMapCache returns a ReadFromURIFunc that caches the contents read from URI
|
||||
|
|
@ -92,12 +99,17 @@ func URIMapCache(reader ReadFromURIFunc) ReadFromURIFunc {
|
|||
}
|
||||
uri := location.String()
|
||||
var ok bool
|
||||
uriMu.RLock()
|
||||
if buf, ok = cache[uri]; ok {
|
||||
uriMu.RUnlock()
|
||||
return
|
||||
}
|
||||
uriMu.RUnlock()
|
||||
if buf, err = reader(loader, location); err != nil {
|
||||
return
|
||||
}
|
||||
uriMu.Lock()
|
||||
defer uriMu.Unlock()
|
||||
cache[uri] = buf
|
||||
return
|
||||
}
|
||||
|
|
|
|||
435
vendor/github.com/getkin/kin-openapi/openapi3/maplike.go
generated
vendored
Normal file
435
vendor/github.com/getkin/kin-openapi/openapi3/maplike.go
generated
vendored
Normal file
|
|
@ -0,0 +1,435 @@
|
|||
package openapi3
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/go-openapi/jsonpointer"
|
||||
)
|
||||
|
||||
// NewResponsesWithCapacity builds a responses object of the given capacity.
|
||||
func NewResponsesWithCapacity(cap int) *Responses {
|
||||
if cap == 0 {
|
||||
return &Responses{m: make(map[string]*ResponseRef)}
|
||||
}
|
||||
return &Responses{m: make(map[string]*ResponseRef, cap)}
|
||||
}
|
||||
|
||||
// Value returns the responses for key or nil
|
||||
func (responses *Responses) Value(key string) *ResponseRef {
|
||||
if responses.Len() == 0 {
|
||||
return nil
|
||||
}
|
||||
return responses.m[key]
|
||||
}
|
||||
|
||||
// Set adds or replaces key 'key' of 'responses' with 'value'.
|
||||
// Note: 'responses' MUST be non-nil
|
||||
func (responses *Responses) Set(key string, value *ResponseRef) {
|
||||
if responses.m == nil {
|
||||
responses.m = make(map[string]*ResponseRef)
|
||||
}
|
||||
responses.m[key] = value
|
||||
}
|
||||
|
||||
// Len returns the amount of keys in responses excluding responses.Extensions.
|
||||
func (responses *Responses) Len() int {
|
||||
if responses == nil || responses.m == nil {
|
||||
return 0
|
||||
}
|
||||
return len(responses.m)
|
||||
}
|
||||
|
||||
// Delete removes the entry associated with key 'key' from 'responses'.
|
||||
func (responses *Responses) Delete(key string) {
|
||||
if responses != nil && responses.m != nil {
|
||||
delete(responses.m, key)
|
||||
}
|
||||
}
|
||||
|
||||
// Map returns responses as a 'map'.
|
||||
// Note: iteration on Go maps is not ordered.
|
||||
func (responses *Responses) Map() (m map[string]*ResponseRef) {
|
||||
if responses == nil || len(responses.m) == 0 {
|
||||
return make(map[string]*ResponseRef)
|
||||
}
|
||||
m = make(map[string]*ResponseRef, len(responses.m))
|
||||
for k, v := range responses.m {
|
||||
m[k] = v
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
var _ jsonpointer.JSONPointable = (*Responses)(nil)
|
||||
|
||||
// JSONLookup implements https://github.com/go-openapi/jsonpointer#JSONPointable
|
||||
func (responses Responses) JSONLookup(token string) (any, error) {
|
||||
if v := responses.Value(token); v == nil {
|
||||
vv, _, err := jsonpointer.GetForToken(responses.Extensions, token)
|
||||
return vv, err
|
||||
} else if ref := v.Ref; ref != "" {
|
||||
return &Ref{Ref: ref}, nil
|
||||
} else {
|
||||
var vv *Response = v.Value
|
||||
return vv, nil
|
||||
}
|
||||
}
|
||||
|
||||
// MarshalYAML returns the YAML encoding of Responses.
|
||||
func (responses *Responses) MarshalYAML() (any, error) {
|
||||
if responses == nil {
|
||||
return nil, nil
|
||||
}
|
||||
m := make(map[string]any, responses.Len()+len(responses.Extensions))
|
||||
for k, v := range responses.Extensions {
|
||||
m[k] = v
|
||||
}
|
||||
for k, v := range responses.Map() {
|
||||
m[k] = v
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// MarshalJSON returns the JSON encoding of Responses.
|
||||
func (responses *Responses) MarshalJSON() ([]byte, error) {
|
||||
responsesYaml, err := responses.MarshalYAML()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return json.Marshal(responsesYaml)
|
||||
}
|
||||
|
||||
// UnmarshalJSON sets Responses to a copy of data.
|
||||
func (responses *Responses) UnmarshalJSON(data []byte) (err error) {
|
||||
var m map[string]any
|
||||
if err = json.Unmarshal(data, &m); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
ks := make([]string, 0, len(m))
|
||||
for k := range m {
|
||||
ks = append(ks, k)
|
||||
}
|
||||
sort.Strings(ks)
|
||||
|
||||
x := Responses{
|
||||
Extensions: make(map[string]any),
|
||||
m: make(map[string]*ResponseRef, len(m)),
|
||||
}
|
||||
|
||||
for _, k := range ks {
|
||||
v := m[k]
|
||||
if strings.HasPrefix(k, "x-") {
|
||||
x.Extensions[k] = v
|
||||
continue
|
||||
}
|
||||
|
||||
if k == originKey {
|
||||
var data []byte
|
||||
if data, err = json.Marshal(v); err != nil {
|
||||
return
|
||||
}
|
||||
if err = json.Unmarshal(data, &x.Origin); err != nil {
|
||||
return
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
var data []byte
|
||||
if data, err = json.Marshal(v); err != nil {
|
||||
return
|
||||
}
|
||||
var vv ResponseRef
|
||||
if err = vv.UnmarshalJSON(data); err != nil {
|
||||
return
|
||||
}
|
||||
x.m[k] = &vv
|
||||
}
|
||||
*responses = x
|
||||
return
|
||||
}
|
||||
|
||||
// NewCallbackWithCapacity builds a callback object of the given capacity.
|
||||
func NewCallbackWithCapacity(cap int) *Callback {
|
||||
if cap == 0 {
|
||||
return &Callback{m: make(map[string]*PathItem)}
|
||||
}
|
||||
return &Callback{m: make(map[string]*PathItem, cap)}
|
||||
}
|
||||
|
||||
// Value returns the callback for key or nil
|
||||
func (callback *Callback) Value(key string) *PathItem {
|
||||
if callback.Len() == 0 {
|
||||
return nil
|
||||
}
|
||||
return callback.m[key]
|
||||
}
|
||||
|
||||
// Set adds or replaces key 'key' of 'callback' with 'value'.
|
||||
// Note: 'callback' MUST be non-nil
|
||||
func (callback *Callback) Set(key string, value *PathItem) {
|
||||
if callback.m == nil {
|
||||
callback.m = make(map[string]*PathItem)
|
||||
}
|
||||
callback.m[key] = value
|
||||
}
|
||||
|
||||
// Len returns the amount of keys in callback excluding callback.Extensions.
|
||||
func (callback *Callback) Len() int {
|
||||
if callback == nil || callback.m == nil {
|
||||
return 0
|
||||
}
|
||||
return len(callback.m)
|
||||
}
|
||||
|
||||
// Delete removes the entry associated with key 'key' from 'callback'.
|
||||
func (callback *Callback) Delete(key string) {
|
||||
if callback != nil && callback.m != nil {
|
||||
delete(callback.m, key)
|
||||
}
|
||||
}
|
||||
|
||||
// Map returns callback as a 'map'.
|
||||
// Note: iteration on Go maps is not ordered.
|
||||
func (callback *Callback) Map() (m map[string]*PathItem) {
|
||||
if callback == nil || len(callback.m) == 0 {
|
||||
return make(map[string]*PathItem)
|
||||
}
|
||||
m = make(map[string]*PathItem, len(callback.m))
|
||||
for k, v := range callback.m {
|
||||
m[k] = v
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
var _ jsonpointer.JSONPointable = (*Callback)(nil)
|
||||
|
||||
// JSONLookup implements https://github.com/go-openapi/jsonpointer#JSONPointable
|
||||
func (callback Callback) JSONLookup(token string) (any, error) {
|
||||
if v := callback.Value(token); v == nil {
|
||||
vv, _, err := jsonpointer.GetForToken(callback.Extensions, token)
|
||||
return vv, err
|
||||
} else if ref := v.Ref; ref != "" {
|
||||
return &Ref{Ref: ref}, nil
|
||||
} else {
|
||||
var vv *PathItem = v
|
||||
return vv, nil
|
||||
}
|
||||
}
|
||||
|
||||
// MarshalYAML returns the YAML encoding of Callback.
|
||||
func (callback *Callback) MarshalYAML() (any, error) {
|
||||
if callback == nil {
|
||||
return nil, nil
|
||||
}
|
||||
m := make(map[string]any, callback.Len()+len(callback.Extensions))
|
||||
for k, v := range callback.Extensions {
|
||||
m[k] = v
|
||||
}
|
||||
for k, v := range callback.Map() {
|
||||
m[k] = v
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// MarshalJSON returns the JSON encoding of Callback.
|
||||
func (callback *Callback) MarshalJSON() ([]byte, error) {
|
||||
callbackYaml, err := callback.MarshalYAML()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return json.Marshal(callbackYaml)
|
||||
}
|
||||
|
||||
// UnmarshalJSON sets Callback to a copy of data.
|
||||
func (callback *Callback) UnmarshalJSON(data []byte) (err error) {
|
||||
var m map[string]any
|
||||
if err = json.Unmarshal(data, &m); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
ks := make([]string, 0, len(m))
|
||||
for k := range m {
|
||||
ks = append(ks, k)
|
||||
}
|
||||
sort.Strings(ks)
|
||||
|
||||
x := Callback{
|
||||
Extensions: make(map[string]any),
|
||||
m: make(map[string]*PathItem, len(m)),
|
||||
}
|
||||
|
||||
for _, k := range ks {
|
||||
v := m[k]
|
||||
if strings.HasPrefix(k, "x-") {
|
||||
x.Extensions[k] = v
|
||||
continue
|
||||
}
|
||||
|
||||
if k == originKey {
|
||||
var data []byte
|
||||
if data, err = json.Marshal(v); err != nil {
|
||||
return
|
||||
}
|
||||
if err = json.Unmarshal(data, &x.Origin); err != nil {
|
||||
return
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
var data []byte
|
||||
if data, err = json.Marshal(v); err != nil {
|
||||
return
|
||||
}
|
||||
var vv PathItem
|
||||
if err = vv.UnmarshalJSON(data); err != nil {
|
||||
return
|
||||
}
|
||||
x.m[k] = &vv
|
||||
}
|
||||
*callback = x
|
||||
return
|
||||
}
|
||||
|
||||
// NewPathsWithCapacity builds a paths object of the given capacity.
|
||||
func NewPathsWithCapacity(cap int) *Paths {
|
||||
if cap == 0 {
|
||||
return &Paths{m: make(map[string]*PathItem)}
|
||||
}
|
||||
return &Paths{m: make(map[string]*PathItem, cap)}
|
||||
}
|
||||
|
||||
// Value returns the paths for key or nil
|
||||
func (paths *Paths) Value(key string) *PathItem {
|
||||
if paths.Len() == 0 {
|
||||
return nil
|
||||
}
|
||||
return paths.m[key]
|
||||
}
|
||||
|
||||
// Set adds or replaces key 'key' of 'paths' with 'value'.
|
||||
// Note: 'paths' MUST be non-nil
|
||||
func (paths *Paths) Set(key string, value *PathItem) {
|
||||
if paths.m == nil {
|
||||
paths.m = make(map[string]*PathItem)
|
||||
}
|
||||
paths.m[key] = value
|
||||
}
|
||||
|
||||
// Len returns the amount of keys in paths excluding paths.Extensions.
|
||||
func (paths *Paths) Len() int {
|
||||
if paths == nil || paths.m == nil {
|
||||
return 0
|
||||
}
|
||||
return len(paths.m)
|
||||
}
|
||||
|
||||
// Delete removes the entry associated with key 'key' from 'paths'.
|
||||
func (paths *Paths) Delete(key string) {
|
||||
if paths != nil && paths.m != nil {
|
||||
delete(paths.m, key)
|
||||
}
|
||||
}
|
||||
|
||||
// Map returns paths as a 'map'.
|
||||
// Note: iteration on Go maps is not ordered.
|
||||
func (paths *Paths) Map() (m map[string]*PathItem) {
|
||||
if paths == nil || len(paths.m) == 0 {
|
||||
return make(map[string]*PathItem)
|
||||
}
|
||||
m = make(map[string]*PathItem, len(paths.m))
|
||||
for k, v := range paths.m {
|
||||
m[k] = v
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
var _ jsonpointer.JSONPointable = (*Paths)(nil)
|
||||
|
||||
// JSONLookup implements https://github.com/go-openapi/jsonpointer#JSONPointable
|
||||
func (paths Paths) JSONLookup(token string) (any, error) {
|
||||
if v := paths.Value(token); v == nil {
|
||||
vv, _, err := jsonpointer.GetForToken(paths.Extensions, token)
|
||||
return vv, err
|
||||
} else if ref := v.Ref; ref != "" {
|
||||
return &Ref{Ref: ref}, nil
|
||||
} else {
|
||||
var vv *PathItem = v
|
||||
return vv, nil
|
||||
}
|
||||
}
|
||||
|
||||
// MarshalYAML returns the YAML encoding of Paths.
|
||||
func (paths *Paths) MarshalYAML() (any, error) {
|
||||
if paths == nil {
|
||||
return nil, nil
|
||||
}
|
||||
m := make(map[string]any, paths.Len()+len(paths.Extensions))
|
||||
for k, v := range paths.Extensions {
|
||||
m[k] = v
|
||||
}
|
||||
for k, v := range paths.Map() {
|
||||
m[k] = v
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// MarshalJSON returns the JSON encoding of Paths.
|
||||
func (paths *Paths) MarshalJSON() ([]byte, error) {
|
||||
pathsYaml, err := paths.MarshalYAML()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return json.Marshal(pathsYaml)
|
||||
}
|
||||
|
||||
// UnmarshalJSON sets Paths to a copy of data.
|
||||
func (paths *Paths) UnmarshalJSON(data []byte) (err error) {
|
||||
var m map[string]any
|
||||
if err = json.Unmarshal(data, &m); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
ks := make([]string, 0, len(m))
|
||||
for k := range m {
|
||||
ks = append(ks, k)
|
||||
}
|
||||
sort.Strings(ks)
|
||||
|
||||
x := Paths{
|
||||
Extensions: make(map[string]any),
|
||||
m: make(map[string]*PathItem, len(m)),
|
||||
}
|
||||
|
||||
for _, k := range ks {
|
||||
v := m[k]
|
||||
if strings.HasPrefix(k, "x-") {
|
||||
x.Extensions[k] = v
|
||||
continue
|
||||
}
|
||||
|
||||
if k == originKey {
|
||||
var data []byte
|
||||
if data, err = json.Marshal(v); err != nil {
|
||||
return
|
||||
}
|
||||
if err = json.Unmarshal(data, &x.Origin); err != nil {
|
||||
return
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
var data []byte
|
||||
if data, err = json.Marshal(v); err != nil {
|
||||
return
|
||||
}
|
||||
var vv PathItem
|
||||
if err = vv.UnmarshalJSON(data); err != nil {
|
||||
return
|
||||
}
|
||||
x.m[k] = &vv
|
||||
}
|
||||
*paths = x
|
||||
return
|
||||
}
|
||||
34
vendor/github.com/getkin/kin-openapi/openapi3/marsh.go
generated
vendored
Normal file
34
vendor/github.com/getkin/kin-openapi/openapi3/marsh.go
generated
vendored
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
package openapi3
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/oasdiff/yaml"
|
||||
)
|
||||
|
||||
func unmarshalError(jsonUnmarshalErr error) error {
|
||||
if before, after, found := strings.Cut(jsonUnmarshalErr.Error(), "Bis"); found && before != "" && after != "" {
|
||||
before = strings.ReplaceAll(before, " Go struct ", " ")
|
||||
return fmt.Errorf("%s%s", before, strings.ReplaceAll(after, "Bis", ""))
|
||||
}
|
||||
return jsonUnmarshalErr
|
||||
}
|
||||
|
||||
func unmarshal(data []byte, v any, includeOrigin bool) error {
|
||||
var jsonErr, yamlErr error
|
||||
|
||||
// See https://github.com/getkin/kin-openapi/issues/680
|
||||
if jsonErr = json.Unmarshal(data, v); jsonErr == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnmarshalStrict(data, v) TODO: investigate how ymlv3 handles duplicate map keys
|
||||
if yamlErr = yaml.UnmarshalWithOrigin(data, v, includeOrigin); yamlErr == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// If both unmarshaling attempts fail, return a new error that includes both errors
|
||||
return fmt.Errorf("failed to unmarshal data: json error: %v, yaml error: %v", jsonErr, yamlErr)
|
||||
}
|
||||
118
vendor/github.com/getkin/kin-openapi/openapi3/media_type.go
generated
vendored
118
vendor/github.com/getkin/kin-openapi/openapi3/media_type.go
generated
vendored
|
|
@ -2,18 +2,22 @@ package openapi3
|
|||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"sort"
|
||||
|
||||
"github.com/getkin/kin-openapi/jsoninfo"
|
||||
"github.com/go-openapi/jsonpointer"
|
||||
)
|
||||
|
||||
// MediaType is specified by OpenAPI/Swagger 3.0 standard.
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#mediaTypeObject
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#media-type-object
|
||||
type MediaType struct {
|
||||
ExtensionProps
|
||||
Extensions map[string]any `json:"-" yaml:"-"`
|
||||
Origin *Origin `json:"__origin__,omitempty" yaml:"__origin__,omitempty"`
|
||||
|
||||
Schema *SchemaRef `json:"schema,omitempty" yaml:"schema,omitempty"`
|
||||
Example interface{} `json:"example,omitempty" yaml:"example,omitempty"`
|
||||
Example any `json:"example,omitempty" yaml:"example,omitempty"`
|
||||
Examples Examples `json:"examples,omitempty" yaml:"examples,omitempty"`
|
||||
Encoding map[string]*Encoding `json:"encoding,omitempty" yaml:"encoding,omitempty"`
|
||||
}
|
||||
|
|
@ -38,7 +42,7 @@ func (mediaType *MediaType) WithSchemaRef(schema *SchemaRef) *MediaType {
|
|||
return mediaType
|
||||
}
|
||||
|
||||
func (mediaType *MediaType) WithExample(name string, value interface{}) *MediaType {
|
||||
func (mediaType *MediaType) WithExample(name string, value any) *MediaType {
|
||||
example := mediaType.Examples
|
||||
if example == nil {
|
||||
example = make(map[string]*ExampleRef)
|
||||
|
|
@ -60,27 +64,103 @@ func (mediaType *MediaType) WithEncoding(name string, enc *Encoding) *MediaType
|
|||
return mediaType
|
||||
}
|
||||
|
||||
func (mediaType *MediaType) MarshalJSON() ([]byte, error) {
|
||||
return jsoninfo.MarshalStrictStruct(mediaType)
|
||||
// MarshalJSON returns the JSON encoding of MediaType.
|
||||
func (mediaType MediaType) MarshalJSON() ([]byte, error) {
|
||||
x, err := mediaType.MarshalYAML()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return json.Marshal(x)
|
||||
}
|
||||
|
||||
// MarshalYAML returns the YAML encoding of MediaType.
|
||||
func (mediaType MediaType) MarshalYAML() (any, error) {
|
||||
m := make(map[string]any, 4+len(mediaType.Extensions))
|
||||
for k, v := range mediaType.Extensions {
|
||||
m[k] = v
|
||||
}
|
||||
if x := mediaType.Schema; x != nil {
|
||||
m["schema"] = x
|
||||
}
|
||||
if x := mediaType.Example; x != nil {
|
||||
m["example"] = x
|
||||
}
|
||||
if x := mediaType.Examples; len(x) != 0 {
|
||||
m["examples"] = x
|
||||
}
|
||||
if x := mediaType.Encoding; len(x) != 0 {
|
||||
m["encoding"] = x
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON sets MediaType to a copy of data.
|
||||
func (mediaType *MediaType) UnmarshalJSON(data []byte) error {
|
||||
return jsoninfo.UnmarshalStrictStruct(data, mediaType)
|
||||
}
|
||||
|
||||
func (value *MediaType) Validate(ctx context.Context) error {
|
||||
if value == nil {
|
||||
return nil
|
||||
type MediaTypeBis MediaType
|
||||
var x MediaTypeBis
|
||||
if err := json.Unmarshal(data, &x); err != nil {
|
||||
return unmarshalError(err)
|
||||
}
|
||||
if schema := value.Schema; schema != nil {
|
||||
if err := schema.Validate(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
_ = json.Unmarshal(data, &x.Extensions)
|
||||
delete(x.Extensions, originKey)
|
||||
delete(x.Extensions, "schema")
|
||||
delete(x.Extensions, "example")
|
||||
delete(x.Extensions, "examples")
|
||||
delete(x.Extensions, "encoding")
|
||||
if len(x.Extensions) == 0 {
|
||||
x.Extensions = nil
|
||||
}
|
||||
*mediaType = MediaType(x)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mediaType MediaType) JSONLookup(token string) (interface{}, error) {
|
||||
// Validate returns an error if MediaType does not comply with the OpenAPI spec.
|
||||
func (mediaType *MediaType) Validate(ctx context.Context, opts ...ValidationOption) error {
|
||||
ctx = WithValidationOptions(ctx, opts...)
|
||||
|
||||
if mediaType == nil {
|
||||
return nil
|
||||
}
|
||||
if schema := mediaType.Schema; schema != nil {
|
||||
if err := schema.Validate(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if mediaType.Example != nil && mediaType.Examples != nil {
|
||||
return errors.New("example and examples are mutually exclusive")
|
||||
}
|
||||
|
||||
if vo := getValidationOptions(ctx); !vo.examplesValidationDisabled {
|
||||
if example := mediaType.Example; example != nil {
|
||||
if err := validateExampleValue(ctx, example, schema.Value); err != nil {
|
||||
return fmt.Errorf("invalid example: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
if examples := mediaType.Examples; examples != nil {
|
||||
names := make([]string, 0, len(examples))
|
||||
for name := range examples {
|
||||
names = append(names, name)
|
||||
}
|
||||
sort.Strings(names)
|
||||
for _, k := range names {
|
||||
v := examples[k]
|
||||
if err := v.Validate(ctx); err != nil {
|
||||
return fmt.Errorf("example %s: %w", k, err)
|
||||
}
|
||||
if err := validateExampleValue(ctx, v.Value.Value, schema.Value); err != nil {
|
||||
return fmt.Errorf("example %s: %w", k, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return validateExtensions(ctx, mediaType.Extensions)
|
||||
}
|
||||
|
||||
// JSONLookup implements https://pkg.go.dev/github.com/go-openapi/jsonpointer#JSONPointable
|
||||
func (mediaType MediaType) JSONLookup(token string) (any, error) {
|
||||
switch token {
|
||||
case "schema":
|
||||
if mediaType.Schema != nil {
|
||||
|
|
@ -96,6 +176,6 @@ func (mediaType MediaType) JSONLookup(token string) (interface{}, error) {
|
|||
case "encoding":
|
||||
return mediaType.Encoding, nil
|
||||
}
|
||||
v, _, err := jsonpointer.GetForToken(mediaType.ExtensionProps, token)
|
||||
v, _, err := jsonpointer.GetForToken(mediaType.Extensions, token)
|
||||
return v, err
|
||||
}
|
||||
|
|
|
|||
212
vendor/github.com/getkin/kin-openapi/openapi3/openapi3.go
generated
vendored
212
vendor/github.com/getkin/kin-openapi/openapi3/openapi3.go
generated
vendored
|
|
@ -2,45 +2,129 @@ package openapi3
|
|||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
|
||||
"github.com/getkin/kin-openapi/jsoninfo"
|
||||
"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#oasObject
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#openapi-object
|
||||
type T struct {
|
||||
ExtensionProps
|
||||
Extensions map[string]any `json:"-" yaml:"-"`
|
||||
|
||||
OpenAPI string `json:"openapi" yaml:"openapi"` // Required
|
||||
Components Components `json:"components,omitempty" yaml:"components,omitempty"`
|
||||
Components *Components `json:"components,omitempty" yaml:"components,omitempty"`
|
||||
Info *Info `json:"info" yaml:"info"` // Required
|
||||
Paths Paths `json:"paths" yaml:"paths"` // 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) {
|
||||
return jsoninfo.MarshalStrictStruct(doc)
|
||||
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 {
|
||||
return jsoninfo.UnmarshalStrictStruct(data, doc)
|
||||
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) {
|
||||
paths := doc.Paths
|
||||
if paths == nil {
|
||||
paths = make(Paths)
|
||||
doc.Paths = paths
|
||||
if doc.Paths == nil {
|
||||
doc.Paths = NewPaths()
|
||||
}
|
||||
pathItem := paths[path]
|
||||
pathItem := doc.Paths.Value(path)
|
||||
if pathItem == nil {
|
||||
pathItem = &PathItem{}
|
||||
paths[path] = pathItem
|
||||
doc.Paths.Set(path, pathItem)
|
||||
}
|
||||
pathItem.SetOperation(method, operation)
|
||||
}
|
||||
|
|
@ -49,77 +133,73 @@ func (doc *T) AddServer(server *Server) {
|
|||
doc.Servers = append(doc.Servers, server)
|
||||
}
|
||||
|
||||
func (value *T) Validate(ctx context.Context) error {
|
||||
if value.OpenAPI == "" {
|
||||
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")
|
||||
}
|
||||
|
||||
// NOTE: only mention info/components/paths/... key in this func's errors.
|
||||
var wrap func(error) error
|
||||
|
||||
{
|
||||
wrap := func(e error) error { return fmt.Errorf("invalid components: %v", e) }
|
||||
if err := value.Components.Validate(ctx); err != nil {
|
||||
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: %v", e) }
|
||||
if v := value.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 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 paths: %v", e) }
|
||||
if v := value.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 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 security: %v", e) }
|
||||
if v := value.Security; 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 servers: %v", e) }
|
||||
if v := value.Servers; 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)
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
wrap := func(e error) error { return fmt.Errorf("invalid tags: %w", e) }
|
||||
if v := value.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 := value.ExternalDocs; v != nil {
|
||||
if err := v.Validate(ctx); err != nil {
|
||||
return wrap(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
return validateExtensions(ctx, doc.Extensions)
|
||||
}
|
||||
|
|
|
|||
125
vendor/github.com/getkin/kin-openapi/openapi3/operation.go
generated
vendored
125
vendor/github.com/getkin/kin-openapi/openapi3/operation.go
generated
vendored
|
|
@ -2,18 +2,19 @@ package openapi3
|
|||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/getkin/kin-openapi/jsoninfo"
|
||||
"github.com/go-openapi/jsonpointer"
|
||||
)
|
||||
|
||||
// Operation represents "operation" specified by" OpenAPI/Swagger 3.0 standard.
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#operation-object
|
||||
type Operation struct {
|
||||
ExtensionProps
|
||||
Extensions map[string]any `json:"-" yaml:"-"`
|
||||
Origin *Origin `json:"__origin__,omitempty" yaml:"__origin__,omitempty"`
|
||||
|
||||
// Optional tags for documentation.
|
||||
Tags []string `json:"tags,omitempty" yaml:"tags,omitempty"`
|
||||
|
|
@ -34,7 +35,7 @@ type Operation struct {
|
|||
RequestBody *RequestBodyRef `json:"requestBody,omitempty" yaml:"requestBody,omitempty"`
|
||||
|
||||
// Responses.
|
||||
Responses Responses `json:"responses" yaml:"responses"` // Required
|
||||
Responses *Responses `json:"responses" yaml:"responses"` // Required
|
||||
|
||||
// Optional callbacks
|
||||
Callbacks Callbacks `json:"callbacks,omitempty" yaml:"callbacks,omitempty"`
|
||||
|
|
@ -56,15 +57,88 @@ func NewOperation() *Operation {
|
|||
return &Operation{}
|
||||
}
|
||||
|
||||
func (operation *Operation) MarshalJSON() ([]byte, error) {
|
||||
return jsoninfo.MarshalStrictStruct(operation)
|
||||
// MarshalJSON returns the JSON encoding of Operation.
|
||||
func (operation Operation) MarshalJSON() ([]byte, error) {
|
||||
x, err := operation.MarshalYAML()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return json.Marshal(x)
|
||||
}
|
||||
|
||||
// MarshalYAML returns the YAML encoding of Operation.
|
||||
func (operation Operation) MarshalYAML() (any, error) {
|
||||
m := make(map[string]any, 12+len(operation.Extensions))
|
||||
for k, v := range operation.Extensions {
|
||||
m[k] = v
|
||||
}
|
||||
if x := operation.Tags; len(x) != 0 {
|
||||
m["tags"] = x
|
||||
}
|
||||
if x := operation.Summary; x != "" {
|
||||
m["summary"] = x
|
||||
}
|
||||
if x := operation.Description; x != "" {
|
||||
m["description"] = x
|
||||
}
|
||||
if x := operation.OperationID; x != "" {
|
||||
m["operationId"] = x
|
||||
}
|
||||
if x := operation.Parameters; len(x) != 0 {
|
||||
m["parameters"] = x
|
||||
}
|
||||
if x := operation.RequestBody; x != nil {
|
||||
m["requestBody"] = x
|
||||
}
|
||||
m["responses"] = operation.Responses
|
||||
if x := operation.Callbacks; len(x) != 0 {
|
||||
m["callbacks"] = x
|
||||
}
|
||||
if x := operation.Deprecated; x {
|
||||
m["deprecated"] = x
|
||||
}
|
||||
if x := operation.Security; x != nil {
|
||||
m["security"] = x
|
||||
}
|
||||
if x := operation.Servers; x != nil {
|
||||
m["servers"] = x
|
||||
}
|
||||
if x := operation.ExternalDocs; x != nil {
|
||||
m["externalDocs"] = x
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON sets Operation to a copy of data.
|
||||
func (operation *Operation) UnmarshalJSON(data []byte) error {
|
||||
return jsoninfo.UnmarshalStrictStruct(data, operation)
|
||||
type OperationBis Operation
|
||||
var x OperationBis
|
||||
if err := json.Unmarshal(data, &x); err != nil {
|
||||
return unmarshalError(err)
|
||||
}
|
||||
_ = json.Unmarshal(data, &x.Extensions)
|
||||
delete(x.Extensions, originKey)
|
||||
delete(x.Extensions, "tags")
|
||||
delete(x.Extensions, "summary")
|
||||
delete(x.Extensions, "description")
|
||||
delete(x.Extensions, "operationId")
|
||||
delete(x.Extensions, "parameters")
|
||||
delete(x.Extensions, "requestBody")
|
||||
delete(x.Extensions, "responses")
|
||||
delete(x.Extensions, "callbacks")
|
||||
delete(x.Extensions, "deprecated")
|
||||
delete(x.Extensions, "security")
|
||||
delete(x.Extensions, "servers")
|
||||
delete(x.Extensions, "externalDocs")
|
||||
if len(x.Extensions) == 0 {
|
||||
x.Extensions = nil
|
||||
}
|
||||
*operation = Operation(x)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (operation Operation) JSONLookup(token string) (interface{}, error) {
|
||||
// JSONLookup implements https://pkg.go.dev/github.com/go-openapi/jsonpointer#JSONPointable
|
||||
func (operation Operation) JSONLookup(token string) (any, error) {
|
||||
switch token {
|
||||
case "requestBody":
|
||||
if operation.RequestBody != nil {
|
||||
|
|
@ -97,53 +171,54 @@ func (operation Operation) JSONLookup(token string) (interface{}, error) {
|
|||
return operation.ExternalDocs, nil
|
||||
}
|
||||
|
||||
v, _, err := jsonpointer.GetForToken(operation.ExtensionProps, token)
|
||||
v, _, err := jsonpointer.GetForToken(operation.Extensions, token)
|
||||
return v, err
|
||||
}
|
||||
|
||||
func (operation *Operation) AddParameter(p *Parameter) {
|
||||
operation.Parameters = append(operation.Parameters, &ParameterRef{
|
||||
Value: p,
|
||||
})
|
||||
operation.Parameters = append(operation.Parameters, &ParameterRef{Value: p})
|
||||
}
|
||||
|
||||
func (operation *Operation) AddResponse(status int, response *Response) {
|
||||
responses := operation.Responses
|
||||
if responses == nil {
|
||||
responses = NewResponses()
|
||||
operation.Responses = responses
|
||||
}
|
||||
code := "default"
|
||||
if status != 0 {
|
||||
if 0 < status && status < 1000 {
|
||||
code = strconv.FormatInt(int64(status), 10)
|
||||
}
|
||||
responses[code] = &ResponseRef{
|
||||
Value: response,
|
||||
if operation.Responses == nil {
|
||||
operation.Responses = NewResponses()
|
||||
}
|
||||
operation.Responses.Set(code, &ResponseRef{Value: response})
|
||||
}
|
||||
|
||||
func (value *Operation) Validate(ctx context.Context) error {
|
||||
if v := value.Parameters; v != nil {
|
||||
// Validate returns an error if Operation does not comply with the OpenAPI spec.
|
||||
func (operation *Operation) Validate(ctx context.Context, opts ...ValidationOption) error {
|
||||
ctx = WithValidationOptions(ctx, opts...)
|
||||
|
||||
if v := operation.Parameters; v != nil {
|
||||
if err := v.Validate(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if v := value.RequestBody; v != nil {
|
||||
|
||||
if v := operation.RequestBody; v != nil {
|
||||
if err := v.Validate(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if v := value.Responses; v != nil {
|
||||
|
||||
if v := operation.Responses; v != nil {
|
||||
if err := v.Validate(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
return errors.New("value of responses must be an object")
|
||||
}
|
||||
if v := value.ExternalDocs; v != nil {
|
||||
|
||||
if v := operation.ExternalDocs; v != nil {
|
||||
if err := v.Validate(ctx); err != nil {
|
||||
return fmt.Errorf("invalid external docs: %w", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
||||
return validateExtensions(ctx, operation.Extensions)
|
||||
}
|
||||
|
|
|
|||
17
vendor/github.com/getkin/kin-openapi/openapi3/origin.go
generated
vendored
Normal file
17
vendor/github.com/getkin/kin-openapi/openapi3/origin.go
generated
vendored
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
package openapi3
|
||||
|
||||
const originKey = "__origin__"
|
||||
|
||||
// Origin contains the origin of a collection.
|
||||
// Key is the location of the collection itself.
|
||||
// Fields is a map of the location of each field in the collection.
|
||||
type Origin struct {
|
||||
Key *Location `json:"key,omitempty" yaml:"key,omitempty"`
|
||||
Fields map[string]Location `json:"fields,omitempty" yaml:"fields,omitempty"`
|
||||
}
|
||||
|
||||
// Location is a struct that contains the location of a field.
|
||||
type Location struct {
|
||||
Line int `json:"line,omitempty" yaml:"line,omitempty"`
|
||||
Column int `json:"column,omitempty" yaml:"column,omitempty"`
|
||||
}
|
||||
340
vendor/github.com/getkin/kin-openapi/openapi3/parameter.go
generated
vendored
340
vendor/github.com/getkin/kin-openapi/openapi3/parameter.go
generated
vendored
|
|
@ -2,47 +2,31 @@ package openapi3
|
|||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strconv"
|
||||
|
||||
"github.com/getkin/kin-openapi/jsoninfo"
|
||||
"github.com/go-openapi/jsonpointer"
|
||||
)
|
||||
|
||||
type ParametersMap map[string]*ParameterRef
|
||||
|
||||
var _ jsonpointer.JSONPointable = (*ParametersMap)(nil)
|
||||
|
||||
func (p ParametersMap) JSONLookup(token string) (interface{}, error) {
|
||||
ref, ok := p[token]
|
||||
if ref == nil || ok == false {
|
||||
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
|
||||
|
||||
var _ jsonpointer.JSONPointable = (*Parameters)(nil)
|
||||
|
||||
func (p Parameters) JSONLookup(token string) (interface{}, error) {
|
||||
// JSONLookup implements https://pkg.go.dev/github.com/go-openapi/jsonpointer#JSONPointable
|
||||
func (p Parameters) JSONLookup(token string) (any, error) {
|
||||
index, err := strconv.Atoi(token)
|
||||
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
|
||||
}
|
||||
|
|
@ -64,10 +48,13 @@ func (parameters Parameters) GetByInAndName(in string, name string) *Parameter {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (value Parameters) Validate(ctx context.Context) error {
|
||||
// Validate returns an error if Parameters does not comply with the OpenAPI spec.
|
||||
func (parameters Parameters) Validate(ctx context.Context, opts ...ValidationOption) error {
|
||||
ctx = WithValidationOptions(ctx, opts...)
|
||||
|
||||
dupes := make(map[string]struct{})
|
||||
for _, item := range value {
|
||||
if v := item.Value; v != nil {
|
||||
for _, parameterRef := range parameters {
|
||||
if v := parameterRef.Value; v != nil {
|
||||
key := v.In + ":" + v.Name
|
||||
if _, ok := dupes[key]; ok {
|
||||
return fmt.Errorf("more than one %q parameter has name %q", v.In, v.Name)
|
||||
|
|
@ -75,7 +62,7 @@ func (value Parameters) Validate(ctx context.Context) error {
|
|||
dupes[key] = struct{}{}
|
||||
}
|
||||
|
||||
if err := item.Validate(ctx); err != nil {
|
||||
if err := parameterRef.Validate(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
|
@ -83,23 +70,24 @@ func (value Parameters) Validate(ctx context.Context) error {
|
|||
}
|
||||
|
||||
// Parameter is specified by OpenAPI/Swagger 3.0 standard.
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#parameterObject
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#parameter-object
|
||||
type Parameter struct {
|
||||
ExtensionProps
|
||||
Extensions map[string]any `json:"-" yaml:"-"`
|
||||
Origin *Origin `json:"__origin__,omitempty" yaml:"__origin__,omitempty"`
|
||||
|
||||
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
||||
In string `json:"in,omitempty" yaml:"in,omitempty"`
|
||||
Description string `json:"description,omitempty" yaml:"description,omitempty"`
|
||||
Style string `json:"style,omitempty" yaml:"style,omitempty"`
|
||||
Explode *bool `json:"explode,omitempty" yaml:"explode,omitempty"`
|
||||
AllowEmptyValue bool `json:"allowEmptyValue,omitempty" yaml:"allowEmptyValue,omitempty"`
|
||||
AllowReserved bool `json:"allowReserved,omitempty" yaml:"allowReserved,omitempty"`
|
||||
Deprecated bool `json:"deprecated,omitempty" yaml:"deprecated,omitempty"`
|
||||
Required bool `json:"required,omitempty" yaml:"required,omitempty"`
|
||||
Schema *SchemaRef `json:"schema,omitempty" yaml:"schema,omitempty"`
|
||||
Example interface{} `json:"example,omitempty" yaml:"example,omitempty"`
|
||||
Examples Examples `json:"examples,omitempty" yaml:"examples,omitempty"`
|
||||
Content Content `json:"content,omitempty" yaml:"content,omitempty"`
|
||||
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
||||
In string `json:"in,omitempty" yaml:"in,omitempty"`
|
||||
Description string `json:"description,omitempty" yaml:"description,omitempty"`
|
||||
Style string `json:"style,omitempty" yaml:"style,omitempty"`
|
||||
Explode *bool `json:"explode,omitempty" yaml:"explode,omitempty"`
|
||||
AllowEmptyValue bool `json:"allowEmptyValue,omitempty" yaml:"allowEmptyValue,omitempty"`
|
||||
AllowReserved bool `json:"allowReserved,omitempty" yaml:"allowReserved,omitempty"`
|
||||
Deprecated bool `json:"deprecated,omitempty" yaml:"deprecated,omitempty"`
|
||||
Required bool `json:"required,omitempty" yaml:"required,omitempty"`
|
||||
Schema *SchemaRef `json:"schema,omitempty" yaml:"schema,omitempty"`
|
||||
Example any `json:"example,omitempty" yaml:"example,omitempty"`
|
||||
Examples Examples `json:"examples,omitempty" yaml:"examples,omitempty"`
|
||||
Content Content `json:"content,omitempty" yaml:"content,omitempty"`
|
||||
}
|
||||
|
||||
var _ jsonpointer.JSONPointable = (*Parameter)(nil)
|
||||
|
|
@ -161,50 +149,133 @@ func (parameter *Parameter) WithSchema(value *Schema) *Parameter {
|
|||
return parameter
|
||||
}
|
||||
|
||||
func (parameter *Parameter) MarshalJSON() ([]byte, error) {
|
||||
return jsoninfo.MarshalStrictStruct(parameter)
|
||||
// MarshalJSON returns the JSON encoding of Parameter.
|
||||
func (parameter Parameter) MarshalJSON() ([]byte, error) {
|
||||
x, err := parameter.MarshalYAML()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return json.Marshal(x)
|
||||
}
|
||||
|
||||
func (parameter *Parameter) UnmarshalJSON(data []byte) error {
|
||||
return jsoninfo.UnmarshalStrictStruct(data, parameter)
|
||||
}
|
||||
|
||||
func (value Parameter) JSONLookup(token string) (interface{}, error) {
|
||||
switch token {
|
||||
case "schema":
|
||||
if value.Schema != nil {
|
||||
if value.Schema.Ref != "" {
|
||||
return &Ref{Ref: value.Schema.Ref}, nil
|
||||
}
|
||||
return value.Schema.Value, nil
|
||||
}
|
||||
case "name":
|
||||
return value.Name, nil
|
||||
case "in":
|
||||
return value.In, nil
|
||||
case "description":
|
||||
return value.Description, nil
|
||||
case "style":
|
||||
return value.Style, nil
|
||||
case "explode":
|
||||
return value.Explode, nil
|
||||
case "allowEmptyValue":
|
||||
return value.AllowEmptyValue, nil
|
||||
case "allowReserved":
|
||||
return value.AllowReserved, nil
|
||||
case "deprecated":
|
||||
return value.Deprecated, nil
|
||||
case "required":
|
||||
return value.Required, nil
|
||||
case "example":
|
||||
return value.Example, nil
|
||||
case "examples":
|
||||
return value.Examples, nil
|
||||
case "content":
|
||||
return value.Content, nil
|
||||
// MarshalYAML returns the YAML encoding of Parameter.
|
||||
func (parameter Parameter) MarshalYAML() (any, error) {
|
||||
m := make(map[string]any, 13+len(parameter.Extensions))
|
||||
for k, v := range parameter.Extensions {
|
||||
m[k] = v
|
||||
}
|
||||
|
||||
v, _, err := jsonpointer.GetForToken(value.ExtensionProps, token)
|
||||
if x := parameter.Name; x != "" {
|
||||
m["name"] = x
|
||||
}
|
||||
if x := parameter.In; x != "" {
|
||||
m["in"] = x
|
||||
}
|
||||
if x := parameter.Description; x != "" {
|
||||
m["description"] = x
|
||||
}
|
||||
if x := parameter.Style; x != "" {
|
||||
m["style"] = x
|
||||
}
|
||||
if x := parameter.Explode; x != nil {
|
||||
m["explode"] = x
|
||||
}
|
||||
if x := parameter.AllowEmptyValue; x {
|
||||
m["allowEmptyValue"] = x
|
||||
}
|
||||
if x := parameter.AllowReserved; x {
|
||||
m["allowReserved"] = x
|
||||
}
|
||||
if x := parameter.Deprecated; x {
|
||||
m["deprecated"] = x
|
||||
}
|
||||
if x := parameter.Required; x {
|
||||
m["required"] = x
|
||||
}
|
||||
if x := parameter.Schema; x != nil {
|
||||
m["schema"] = x
|
||||
}
|
||||
if x := parameter.Example; x != nil {
|
||||
m["example"] = x
|
||||
}
|
||||
if x := parameter.Examples; len(x) != 0 {
|
||||
m["examples"] = x
|
||||
}
|
||||
if x := parameter.Content; len(x) != 0 {
|
||||
m["content"] = x
|
||||
}
|
||||
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON sets Parameter to a copy of data.
|
||||
func (parameter *Parameter) UnmarshalJSON(data []byte) error {
|
||||
type ParameterBis Parameter
|
||||
var x ParameterBis
|
||||
if err := json.Unmarshal(data, &x); err != nil {
|
||||
return unmarshalError(err)
|
||||
}
|
||||
_ = json.Unmarshal(data, &x.Extensions)
|
||||
|
||||
delete(x.Extensions, originKey)
|
||||
delete(x.Extensions, "name")
|
||||
delete(x.Extensions, "in")
|
||||
delete(x.Extensions, "description")
|
||||
delete(x.Extensions, "style")
|
||||
delete(x.Extensions, "explode")
|
||||
delete(x.Extensions, "allowEmptyValue")
|
||||
delete(x.Extensions, "allowReserved")
|
||||
delete(x.Extensions, "deprecated")
|
||||
delete(x.Extensions, "required")
|
||||
delete(x.Extensions, "schema")
|
||||
delete(x.Extensions, "example")
|
||||
delete(x.Extensions, "examples")
|
||||
delete(x.Extensions, "content")
|
||||
if len(x.Extensions) == 0 {
|
||||
x.Extensions = nil
|
||||
}
|
||||
|
||||
*parameter = Parameter(x)
|
||||
return nil
|
||||
}
|
||||
|
||||
// JSONLookup implements https://pkg.go.dev/github.com/go-openapi/jsonpointer#JSONPointable
|
||||
func (parameter Parameter) JSONLookup(token string) (any, error) {
|
||||
switch token {
|
||||
case "schema":
|
||||
if parameter.Schema != nil {
|
||||
if parameter.Schema.Ref != "" {
|
||||
return &Ref{Ref: parameter.Schema.Ref}, nil
|
||||
}
|
||||
return parameter.Schema.Value, nil
|
||||
}
|
||||
case "name":
|
||||
return parameter.Name, nil
|
||||
case "in":
|
||||
return parameter.In, nil
|
||||
case "description":
|
||||
return parameter.Description, nil
|
||||
case "style":
|
||||
return parameter.Style, nil
|
||||
case "explode":
|
||||
return parameter.Explode, nil
|
||||
case "allowEmptyValue":
|
||||
return parameter.AllowEmptyValue, nil
|
||||
case "allowReserved":
|
||||
return parameter.AllowReserved, nil
|
||||
case "deprecated":
|
||||
return parameter.Deprecated, nil
|
||||
case "required":
|
||||
return parameter.Required, nil
|
||||
case "example":
|
||||
return parameter.Example, nil
|
||||
case "examples":
|
||||
return parameter.Examples, nil
|
||||
case "content":
|
||||
return parameter.Content, nil
|
||||
}
|
||||
|
||||
v, _, err := jsonpointer.GetForToken(parameter.Extensions, token)
|
||||
return v, err
|
||||
}
|
||||
|
||||
|
|
@ -238,11 +309,14 @@ func (parameter *Parameter) SerializationMethod() (*SerializationMethod, error)
|
|||
}
|
||||
}
|
||||
|
||||
func (value *Parameter) Validate(ctx context.Context) error {
|
||||
if value.Name == "" {
|
||||
// Validate returns an error if Parameter does not comply with the OpenAPI spec.
|
||||
func (parameter *Parameter) Validate(ctx context.Context, opts ...ValidationOption) error {
|
||||
ctx = WithValidationOptions(ctx, opts...)
|
||||
|
||||
if parameter.Name == "" {
|
||||
return errors.New("parameter name can't be blank")
|
||||
}
|
||||
in := value.In
|
||||
in := parameter.In
|
||||
switch in {
|
||||
case
|
||||
ParameterInPath,
|
||||
|
|
@ -250,61 +324,101 @@ func (value *Parameter) Validate(ctx context.Context) error {
|
|||
ParameterInHeader,
|
||||
ParameterInCookie:
|
||||
default:
|
||||
return fmt.Errorf("parameter can't have 'in' value %q", value.In)
|
||||
return fmt.Errorf("parameter can't have 'in' value %q", parameter.In)
|
||||
}
|
||||
|
||||
if in == ParameterInPath && !value.Required {
|
||||
return fmt.Errorf("path parameter %q must be required", value.Name)
|
||||
if in == ParameterInPath && !parameter.Required {
|
||||
return fmt.Errorf("path parameter %q must be required", parameter.Name)
|
||||
}
|
||||
|
||||
// Validate a parameter's serialization method.
|
||||
sm, err := value.SerializationMethod()
|
||||
sm, err := parameter.SerializationMethod()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var smSupported bool
|
||||
switch {
|
||||
case value.In == ParameterInPath && sm.Style == SerializationSimple && !sm.Explode,
|
||||
value.In == ParameterInPath && sm.Style == SerializationSimple && sm.Explode,
|
||||
value.In == ParameterInPath && sm.Style == SerializationLabel && !sm.Explode,
|
||||
value.In == ParameterInPath && sm.Style == SerializationLabel && sm.Explode,
|
||||
value.In == ParameterInPath && sm.Style == SerializationMatrix && !sm.Explode,
|
||||
value.In == ParameterInPath && sm.Style == SerializationMatrix && sm.Explode,
|
||||
case parameter.In == ParameterInPath && sm.Style == SerializationSimple && !sm.Explode,
|
||||
parameter.In == ParameterInPath && sm.Style == SerializationSimple && sm.Explode,
|
||||
parameter.In == ParameterInPath && sm.Style == SerializationLabel && !sm.Explode,
|
||||
parameter.In == ParameterInPath && sm.Style == SerializationLabel && sm.Explode,
|
||||
parameter.In == ParameterInPath && sm.Style == SerializationMatrix && !sm.Explode,
|
||||
parameter.In == ParameterInPath && sm.Style == SerializationMatrix && sm.Explode,
|
||||
|
||||
value.In == ParameterInQuery && sm.Style == SerializationForm && sm.Explode,
|
||||
value.In == ParameterInQuery && sm.Style == SerializationForm && !sm.Explode,
|
||||
value.In == ParameterInQuery && sm.Style == SerializationSpaceDelimited && sm.Explode,
|
||||
value.In == ParameterInQuery && sm.Style == SerializationSpaceDelimited && !sm.Explode,
|
||||
value.In == ParameterInQuery && sm.Style == SerializationPipeDelimited && sm.Explode,
|
||||
value.In == ParameterInQuery && sm.Style == SerializationPipeDelimited && !sm.Explode,
|
||||
value.In == ParameterInQuery && sm.Style == SerializationDeepObject && sm.Explode,
|
||||
parameter.In == ParameterInQuery && sm.Style == SerializationForm && sm.Explode,
|
||||
parameter.In == ParameterInQuery && sm.Style == SerializationForm && !sm.Explode,
|
||||
parameter.In == ParameterInQuery && sm.Style == SerializationSpaceDelimited && sm.Explode,
|
||||
parameter.In == ParameterInQuery && sm.Style == SerializationSpaceDelimited && !sm.Explode,
|
||||
parameter.In == ParameterInQuery && sm.Style == SerializationPipeDelimited && sm.Explode,
|
||||
parameter.In == ParameterInQuery && sm.Style == SerializationPipeDelimited && !sm.Explode,
|
||||
parameter.In == ParameterInQuery && sm.Style == SerializationDeepObject && sm.Explode,
|
||||
|
||||
value.In == ParameterInHeader && sm.Style == SerializationSimple && !sm.Explode,
|
||||
value.In == ParameterInHeader && sm.Style == SerializationSimple && sm.Explode,
|
||||
parameter.In == ParameterInHeader && sm.Style == SerializationSimple && !sm.Explode,
|
||||
parameter.In == ParameterInHeader && sm.Style == SerializationSimple && sm.Explode,
|
||||
|
||||
value.In == ParameterInCookie && sm.Style == SerializationForm && !sm.Explode,
|
||||
value.In == ParameterInCookie && sm.Style == SerializationForm && sm.Explode:
|
||||
parameter.In == ParameterInCookie && sm.Style == SerializationForm && !sm.Explode,
|
||||
parameter.In == ParameterInCookie && sm.Style == SerializationForm && sm.Explode:
|
||||
smSupported = true
|
||||
}
|
||||
if !smSupported {
|
||||
e := fmt.Errorf("serialization method with style=%q and explode=%v is not supported by a %s parameter", sm.Style, sm.Explode, in)
|
||||
return fmt.Errorf("parameter %q schema is invalid: %v", value.Name, e)
|
||||
return fmt.Errorf("parameter %q schema is invalid: %w", parameter.Name, e)
|
||||
}
|
||||
|
||||
if (value.Schema == nil) == (value.Content == nil) {
|
||||
if (parameter.Schema == nil) == (len(parameter.Content) == 0) {
|
||||
e := errors.New("parameter must contain exactly one of content and schema")
|
||||
return fmt.Errorf("parameter %q schema is invalid: %v", value.Name, e)
|
||||
return fmt.Errorf("parameter %q schema is invalid: %w", parameter.Name, e)
|
||||
}
|
||||
if schema := value.Schema; schema != nil {
|
||||
if err := schema.Validate(ctx); err != nil {
|
||||
return fmt.Errorf("parameter %q schema is invalid: %v", value.Name, err)
|
||||
|
||||
if content := parameter.Content; content != nil {
|
||||
e := errors.New("parameter content must only contain one entry")
|
||||
if len(content) > 1 {
|
||||
return fmt.Errorf("parameter %q content is invalid: %w", parameter.Name, e)
|
||||
}
|
||||
|
||||
if err := content.Validate(ctx); err != nil {
|
||||
return fmt.Errorf("parameter %q content is invalid: %w", parameter.Name, err)
|
||||
}
|
||||
}
|
||||
|
||||
if content := value.Content; content != nil {
|
||||
if err := content.Validate(ctx); err != nil {
|
||||
return fmt.Errorf("parameter %q content is invalid: %v", value.Name, err)
|
||||
if schema := parameter.Schema; schema != nil {
|
||||
if err := schema.Validate(ctx); err != nil {
|
||||
return fmt.Errorf("parameter %q schema is invalid: %w", parameter.Name, err)
|
||||
}
|
||||
if parameter.Example != nil && parameter.Examples != nil {
|
||||
return fmt.Errorf("parameter %q example and examples are mutually exclusive", parameter.Name)
|
||||
}
|
||||
|
||||
if vo := getValidationOptions(ctx); vo.examplesValidationDisabled {
|
||||
return nil
|
||||
}
|
||||
if example := parameter.Example; example != nil {
|
||||
if err := validateExampleValue(ctx, example, schema.Value); err != nil {
|
||||
return fmt.Errorf("invalid example: %w", err)
|
||||
}
|
||||
} else if examples := parameter.Examples; examples != nil {
|
||||
names := make([]string, 0, len(examples))
|
||||
for name := range examples {
|
||||
names = append(names, name)
|
||||
}
|
||||
sort.Strings(names)
|
||||
for _, k := range names {
|
||||
v := examples[k]
|
||||
if err := v.Validate(ctx); err != nil {
|
||||
return fmt.Errorf("%s: %w", k, err)
|
||||
}
|
||||
if err := validateExampleValue(ctx, v.Value.Value, schema.Value); err != nil {
|
||||
return fmt.Errorf("%s: %w", k, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
||||
return validateExtensions(ctx, parameter.Extensions)
|
||||
}
|
||||
|
||||
// UnmarshalJSON sets ParametersMap to a copy of data.
|
||||
func (parametersMap *ParametersMap) UnmarshalJSON(data []byte) (err error) {
|
||||
*parametersMap, _, err = unmarshalStringMapP[ParameterRef](data)
|
||||
return
|
||||
}
|
||||
|
|
|
|||
143
vendor/github.com/getkin/kin-openapi/openapi3/path_item.go
generated
vendored
143
vendor/github.com/getkin/kin-openapi/openapi3/path_item.go
generated
vendored
|
|
@ -2,16 +2,17 @@ package openapi3
|
|||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/getkin/kin-openapi/jsoninfo"
|
||||
"sort"
|
||||
)
|
||||
|
||||
// PathItem is specified by OpenAPI/Swagger standard version 3.
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#pathItemObject
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#path-item-object
|
||||
type PathItem struct {
|
||||
ExtensionProps
|
||||
Extensions map[string]any `json:"-" yaml:"-"`
|
||||
Origin *Origin `json:"__origin__,omitempty" yaml:"__origin__,omitempty"`
|
||||
|
||||
Ref string `json:"$ref,omitempty" yaml:"$ref,omitempty"`
|
||||
Summary string `json:"summary,omitempty" yaml:"summary,omitempty"`
|
||||
|
|
@ -29,16 +30,99 @@ type PathItem struct {
|
|||
Parameters Parameters `json:"parameters,omitempty" yaml:"parameters,omitempty"`
|
||||
}
|
||||
|
||||
func (pathItem *PathItem) MarshalJSON() ([]byte, error) {
|
||||
return jsoninfo.MarshalStrictStruct(pathItem)
|
||||
// MarshalJSON returns the JSON encoding of PathItem.
|
||||
func (pathItem PathItem) MarshalJSON() ([]byte, error) {
|
||||
x, err := pathItem.MarshalYAML()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return json.Marshal(x)
|
||||
}
|
||||
|
||||
// MarshalYAML returns the YAML encoding of PathItem.
|
||||
func (pathItem PathItem) MarshalYAML() (any, error) {
|
||||
if ref := pathItem.Ref; ref != "" {
|
||||
return Ref{Ref: ref}, nil
|
||||
}
|
||||
|
||||
m := make(map[string]any, 13+len(pathItem.Extensions))
|
||||
for k, v := range pathItem.Extensions {
|
||||
m[k] = v
|
||||
}
|
||||
if x := pathItem.Summary; x != "" {
|
||||
m["summary"] = x
|
||||
}
|
||||
if x := pathItem.Description; x != "" {
|
||||
m["description"] = x
|
||||
}
|
||||
if x := pathItem.Connect; x != nil {
|
||||
m["connect"] = x
|
||||
}
|
||||
if x := pathItem.Delete; x != nil {
|
||||
m["delete"] = x
|
||||
}
|
||||
if x := pathItem.Get; x != nil {
|
||||
m["get"] = x
|
||||
}
|
||||
if x := pathItem.Head; x != nil {
|
||||
m["head"] = x
|
||||
}
|
||||
if x := pathItem.Options; x != nil {
|
||||
m["options"] = x
|
||||
}
|
||||
if x := pathItem.Patch; x != nil {
|
||||
m["patch"] = x
|
||||
}
|
||||
if x := pathItem.Post; x != nil {
|
||||
m["post"] = x
|
||||
}
|
||||
if x := pathItem.Put; x != nil {
|
||||
m["put"] = x
|
||||
}
|
||||
if x := pathItem.Trace; x != nil {
|
||||
m["trace"] = x
|
||||
}
|
||||
if x := pathItem.Servers; len(x) != 0 {
|
||||
m["servers"] = x
|
||||
}
|
||||
if x := pathItem.Parameters; len(x) != 0 {
|
||||
m["parameters"] = x
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON sets PathItem to a copy of data.
|
||||
func (pathItem *PathItem) UnmarshalJSON(data []byte) error {
|
||||
return jsoninfo.UnmarshalStrictStruct(data, pathItem)
|
||||
type PathItemBis PathItem
|
||||
var x PathItemBis
|
||||
if err := json.Unmarshal(data, &x); err != nil {
|
||||
return unmarshalError(err)
|
||||
}
|
||||
_ = json.Unmarshal(data, &x.Extensions)
|
||||
delete(x.Extensions, originKey)
|
||||
delete(x.Extensions, "$ref")
|
||||
delete(x.Extensions, "summary")
|
||||
delete(x.Extensions, "description")
|
||||
delete(x.Extensions, "connect")
|
||||
delete(x.Extensions, "delete")
|
||||
delete(x.Extensions, "get")
|
||||
delete(x.Extensions, "head")
|
||||
delete(x.Extensions, "options")
|
||||
delete(x.Extensions, "patch")
|
||||
delete(x.Extensions, "post")
|
||||
delete(x.Extensions, "put")
|
||||
delete(x.Extensions, "trace")
|
||||
delete(x.Extensions, "servers")
|
||||
delete(x.Extensions, "parameters")
|
||||
if len(x.Extensions) == 0 {
|
||||
x.Extensions = nil
|
||||
}
|
||||
*pathItem = PathItem(x)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (pathItem *PathItem) Operations() map[string]*Operation {
|
||||
operations := make(map[string]*Operation, 4)
|
||||
operations := make(map[string]*Operation)
|
||||
if v := pathItem.Connect; v != nil {
|
||||
operations[http.MethodConnect] = v
|
||||
}
|
||||
|
|
@ -119,11 +203,48 @@ func (pathItem *PathItem) SetOperation(method string, operation *Operation) {
|
|||
}
|
||||
}
|
||||
|
||||
func (value *PathItem) Validate(ctx context.Context) error {
|
||||
for _, operation := range value.Operations() {
|
||||
// Validate returns an error if PathItem does not comply with the OpenAPI spec.
|
||||
func (pathItem *PathItem) Validate(ctx context.Context, opts ...ValidationOption) error {
|
||||
ctx = WithValidationOptions(ctx, opts...)
|
||||
|
||||
operations := pathItem.Operations()
|
||||
|
||||
methods := make([]string, 0, len(operations))
|
||||
for method := range operations {
|
||||
methods = append(methods, method)
|
||||
}
|
||||
sort.Strings(methods)
|
||||
for _, method := range methods {
|
||||
operation := operations[method]
|
||||
if err := operation.Validate(ctx); err != nil {
|
||||
return fmt.Errorf("invalid operation %s: %v", method, err)
|
||||
}
|
||||
}
|
||||
|
||||
if v := pathItem.Parameters; v != nil {
|
||||
if err := v.Validate(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
||||
return validateExtensions(ctx, pathItem.Extensions)
|
||||
}
|
||||
|
||||
// isEmpty's introduced in 546590b1
|
||||
func (pathItem *PathItem) isEmpty() bool {
|
||||
// NOTE: ignores pathItem.Extensions
|
||||
// NOTE: ignores pathItem.Ref
|
||||
return pathItem.Summary == "" &&
|
||||
pathItem.Description == "" &&
|
||||
pathItem.Connect == nil &&
|
||||
pathItem.Delete == nil &&
|
||||
pathItem.Get == nil &&
|
||||
pathItem.Head == nil &&
|
||||
pathItem.Options == nil &&
|
||||
pathItem.Patch == nil &&
|
||||
pathItem.Post == nil &&
|
||||
pathItem.Put == nil &&
|
||||
pathItem.Trace == nil &&
|
||||
len(pathItem.Servers) == 0 &&
|
||||
len(pathItem.Parameters) == 0
|
||||
}
|
||||
|
|
|
|||
113
vendor/github.com/getkin/kin-openapi/openapi3/paths.go
generated
vendored
113
vendor/github.com/getkin/kin-openapi/openapi3/paths.go
generated
vendored
|
|
@ -3,23 +3,60 @@ package openapi3
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Paths is specified by OpenAPI/Swagger standard version 3.
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#paths-object
|
||||
type Paths map[string]*PathItem
|
||||
type Paths struct {
|
||||
Extensions map[string]any `json:"-" yaml:"-"`
|
||||
Origin *Origin `json:"__origin__,omitempty" yaml:"__origin__,omitempty"`
|
||||
|
||||
func (value Paths) Validate(ctx context.Context) error {
|
||||
normalizedPaths := make(map[string]string)
|
||||
for path, pathItem := range value {
|
||||
m map[string]*PathItem
|
||||
}
|
||||
|
||||
// NewPaths builds a paths object with path items in insertion order.
|
||||
func NewPaths(opts ...NewPathsOption) *Paths {
|
||||
paths := NewPathsWithCapacity(len(opts))
|
||||
for _, opt := range opts {
|
||||
opt(paths)
|
||||
}
|
||||
return paths
|
||||
}
|
||||
|
||||
// NewPathsOption describes options to NewPaths func
|
||||
type NewPathsOption func(*Paths)
|
||||
|
||||
// WithPath adds a named path item
|
||||
func WithPath(path string, pathItem *PathItem) NewPathsOption {
|
||||
return func(paths *Paths) {
|
||||
if p := pathItem; p != nil && path != "" {
|
||||
paths.Set(path, p)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Validate returns an error if Paths does not comply with the OpenAPI spec.
|
||||
func (paths *Paths) Validate(ctx context.Context, opts ...ValidationOption) error {
|
||||
ctx = WithValidationOptions(ctx, opts...)
|
||||
|
||||
normalizedPaths := make(map[string]string, paths.Len())
|
||||
|
||||
keys := make([]string, 0, paths.Len())
|
||||
for key := range paths.Map() {
|
||||
keys = append(keys, key)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
for _, path := range keys {
|
||||
pathItem := paths.Value(path)
|
||||
if path == "" || path[0] != '/' {
|
||||
return fmt.Errorf("path %q does not start with a forward slash (/)", path)
|
||||
}
|
||||
|
||||
if pathItem == nil {
|
||||
value[path] = &PathItem{}
|
||||
pathItem = value[path]
|
||||
pathItem = &PathItem{}
|
||||
paths.Set(path, pathItem)
|
||||
}
|
||||
|
||||
normalizedPath, _, varsInPath := normalizeTemplatedPath(path)
|
||||
|
|
@ -36,7 +73,14 @@ func (value Paths) Validate(ctx context.Context) error {
|
|||
}
|
||||
}
|
||||
}
|
||||
for method, operation := range pathItem.Operations() {
|
||||
operations := pathItem.Operations()
|
||||
methods := make([]string, 0, len(operations))
|
||||
for method := range operations {
|
||||
methods = append(methods, method)
|
||||
}
|
||||
sort.Strings(methods)
|
||||
for _, method := range methods {
|
||||
operation := operations[method]
|
||||
var setParams []string
|
||||
for _, parameterRef := range operation.Parameters {
|
||||
if parameterRef != nil {
|
||||
|
|
@ -80,15 +124,46 @@ func (value Paths) Validate(ctx context.Context) error {
|
|||
}
|
||||
|
||||
if err := pathItem.Validate(ctx); err != nil {
|
||||
return err
|
||||
return fmt.Errorf("invalid path %s: %v", path, err)
|
||||
}
|
||||
}
|
||||
|
||||
if err := value.validateUniqueOperationIDs(); err != nil {
|
||||
if err := paths.validateUniqueOperationIDs(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
return validateExtensions(ctx, paths.Extensions)
|
||||
}
|
||||
|
||||
// InMatchingOrder returns paths in the order they are matched against URLs.
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#paths-object
|
||||
// When matching URLs, concrete (non-templated) paths would be matched
|
||||
// before their templated counterparts.
|
||||
func (paths *Paths) InMatchingOrder() []string {
|
||||
// NOTE: sorting by number of variables ASC then by descending lexicographical
|
||||
// order seems to be a good heuristic.
|
||||
if paths.Len() == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
vars := make(map[int][]string)
|
||||
max := 0
|
||||
for path := range paths.Map() {
|
||||
count := strings.Count(path, "}")
|
||||
vars[count] = append(vars[count], path)
|
||||
if count > max {
|
||||
max = count
|
||||
}
|
||||
}
|
||||
|
||||
ordered := make([]string, 0, paths.Len())
|
||||
for c := 0; c <= max; c++ {
|
||||
if ps, ok := vars[c]; ok {
|
||||
sort.Sort(sort.Reverse(sort.StringSlice(ps)))
|
||||
ordered = append(ordered, ps...)
|
||||
}
|
||||
}
|
||||
return ordered
|
||||
}
|
||||
|
||||
// Find returns a path that matches the key.
|
||||
|
|
@ -97,21 +172,21 @@ func (value Paths) Validate(ctx context.Context) error {
|
|||
//
|
||||
// For example:
|
||||
//
|
||||
// paths := openapi3.Paths {
|
||||
// "/person/{personName}": &openapi3.PathItem{},
|
||||
// }
|
||||
// pathItem := path.Find("/person/{name}")
|
||||
// paths := openapi3.Paths {
|
||||
// "/person/{personName}": &openapi3.PathItem{},
|
||||
// }
|
||||
// pathItem := path.Find("/person/{name}")
|
||||
//
|
||||
// would return the correct path item.
|
||||
func (paths Paths) Find(key string) *PathItem {
|
||||
func (paths *Paths) Find(key string) *PathItem {
|
||||
// Try directly access the map
|
||||
pathItem := paths[key]
|
||||
pathItem := paths.Value(key)
|
||||
if pathItem != nil {
|
||||
return pathItem
|
||||
}
|
||||
|
||||
normalizedPath, expected, _ := normalizeTemplatedPath(key)
|
||||
for path, pathItem := range paths {
|
||||
for path, pathItem := range paths.Map() {
|
||||
pathNormalized, got, _ := normalizeTemplatedPath(path)
|
||||
if got == expected && pathNormalized == normalizedPath {
|
||||
return pathItem
|
||||
|
|
@ -120,9 +195,9 @@ func (paths Paths) Find(key string) *PathItem {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (value Paths) validateUniqueOperationIDs() error {
|
||||
func (paths *Paths) validateUniqueOperationIDs() error {
|
||||
operationIDs := make(map[string]string)
|
||||
for urlPath, pathItem := range value {
|
||||
for urlPath, pathItem := range paths.Map() {
|
||||
if pathItem == nil {
|
||||
continue
|
||||
}
|
||||
|
|
|
|||
10
vendor/github.com/getkin/kin-openapi/openapi3/ref.go
generated
vendored
Normal file
10
vendor/github.com/getkin/kin-openapi/openapi3/ref.go
generated
vendored
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
package openapi3
|
||||
|
||||
//go:generate go run refsgenerator.go
|
||||
|
||||
// Ref is specified by OpenAPI/Swagger 3.0 standard.
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#reference-object
|
||||
type Ref struct {
|
||||
Ref string `json:"$ref" yaml:"$ref"`
|
||||
Origin *Origin `json:"__origin__,omitempty" yaml:"__origin__,omitempty"`
|
||||
}
|
||||
1187
vendor/github.com/getkin/kin-openapi/openapi3/refs.go
generated
vendored
1187
vendor/github.com/getkin/kin-openapi/openapi3/refs.go
generated
vendored
File diff suppressed because it is too large
Load diff
153
vendor/github.com/getkin/kin-openapi/openapi3/refs.tmpl
generated
vendored
Normal file
153
vendor/github.com/getkin/kin-openapi/openapi3/refs.tmpl
generated
vendored
Normal file
|
|
@ -0,0 +1,153 @@
|
|||
// Code generated by go generate; DO NOT EDIT.
|
||||
package {{ .Package }}
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/go-openapi/jsonpointer"
|
||||
"github.com/perimeterx/marshmallow"
|
||||
)
|
||||
{{ range $type := .Types }}
|
||||
// {{ $type.Name }}Ref represents either a {{ $type.Name }} or a $ref to a {{ $type.Name }}.
|
||||
// When serializing and both fields are set, Ref is preferred over Value.
|
||||
type {{ $type.Name }}Ref struct {
|
||||
// Extensions only captures fields starting with 'x-' as no other fields
|
||||
// are allowed by the openapi spec.
|
||||
Extensions map[string]any
|
||||
Origin *Origin
|
||||
|
||||
Ref string
|
||||
Value *{{ $type.Name }}
|
||||
extra []string
|
||||
|
||||
refPath *url.URL
|
||||
}
|
||||
|
||||
var _ jsonpointer.JSONPointable = (*{{ $type.Name }}Ref)(nil)
|
||||
|
||||
func (x *{{ $type.Name }}Ref) isEmpty() bool { return x == nil || x.Ref == "" && x.Value == nil }
|
||||
|
||||
// RefString returns the $ref value.
|
||||
func (x *{{ $type.Name }}Ref) RefString() string { return x.Ref }
|
||||
|
||||
// CollectionName returns the JSON string used for a collection of these components.
|
||||
func (x *{{ $type.Name }}Ref) CollectionName() string { return "{{ $type.CollectionName }}" }
|
||||
|
||||
// RefPath returns the path of the $ref relative to the root document.
|
||||
func (x *{{ $type.Name }}Ref) RefPath() *url.URL { return copyURI(x.refPath) }
|
||||
|
||||
func (x *{{ $type.Name }}Ref) setRefPath(u *url.URL) {
|
||||
// Once the refPath is set don't override. References can be loaded
|
||||
// multiple times not all with access to the correct path info.
|
||||
if x.refPath != nil {
|
||||
return
|
||||
}
|
||||
|
||||
x.refPath = copyURI(u)
|
||||
}
|
||||
|
||||
// MarshalYAML returns the YAML encoding of {{ $type.Name }}Ref.
|
||||
func (x {{ $type.Name }}Ref) MarshalYAML() (any, error) {
|
||||
if ref := x.Ref; ref != "" {
|
||||
return &Ref{Ref: ref}, nil
|
||||
}
|
||||
return x.Value.MarshalYAML()
|
||||
}
|
||||
|
||||
// MarshalJSON returns the JSON encoding of {{ $type.Name }}Ref.
|
||||
func (x {{ $type.Name }}Ref) MarshalJSON() ([]byte, error) {
|
||||
y, err := x.MarshalYAML()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return json.Marshal(y)
|
||||
}
|
||||
|
||||
// UnmarshalJSON sets {{ $type.Name }}Ref to a copy of data.
|
||||
func (x *{{ $type.Name }}Ref) UnmarshalJSON(data []byte) error {
|
||||
var refOnly Ref
|
||||
if extra, err := marshmallow.Unmarshal(data, &refOnly, marshmallow.WithExcludeKnownFieldsFromMap(true)); err == nil && refOnly.Ref != "" {
|
||||
x.Ref = refOnly.Ref
|
||||
x.Origin = refOnly.Origin
|
||||
if len(extra) != 0 {
|
||||
x.extra = make([]string, 0, len(extra))
|
||||
for key := range extra {
|
||||
x.extra = append(x.extra, key)
|
||||
}
|
||||
sort.Strings(x.extra)
|
||||
for k := range extra {
|
||||
if !strings.HasPrefix(k, "x-") {
|
||||
delete(extra, k)
|
||||
}
|
||||
}
|
||||
if len(extra) != 0 {
|
||||
x.Extensions = extra
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return json.Unmarshal(data, &x.Value)
|
||||
}
|
||||
|
||||
// Validate returns an error if {{ $type.Name }}Ref does not comply with the OpenAPI spec.
|
||||
func (x *{{ $type.Name }}Ref) Validate(ctx context.Context, opts ...ValidationOption) error {
|
||||
ctx = WithValidationOptions(ctx, opts...)
|
||||
exProhibited := getValidationOptions(ctx).schemaExtensionsInRefProhibited
|
||||
var extras []string
|
||||
if extra := x.extra; len(extra) != 0 {
|
||||
allowed := getValidationOptions(ctx).extraSiblingFieldsAllowed
|
||||
for _, ex := range extra {
|
||||
if allowed != nil {
|
||||
if _, ok := allowed[ex]; ok {
|
||||
continue
|
||||
}
|
||||
}
|
||||
// extras in the Extensions checked below
|
||||
if _, ok := x.Extensions[ex]; !ok {
|
||||
extras = append(extras, ex)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if extra := x.Extensions; exProhibited && len(extra) != 0 {
|
||||
allowed := getValidationOptions(ctx).extraSiblingFieldsAllowed
|
||||
for ex := range extra {
|
||||
if allowed != nil {
|
||||
if _, ok := allowed[ex]; ok {
|
||||
continue
|
||||
}
|
||||
}
|
||||
extras = append(extras, ex)
|
||||
}
|
||||
}
|
||||
|
||||
if len(extras) != 0 {
|
||||
return fmt.Errorf("extra sibling fields: %+v", extras)
|
||||
}
|
||||
|
||||
if v := x.Value; v != nil {
|
||||
return v.Validate(ctx)
|
||||
}
|
||||
|
||||
return foundUnresolvedRef(x.Ref)
|
||||
}
|
||||
|
||||
// JSONLookup implements https://pkg.go.dev/github.com/go-openapi/jsonpointer#JSONPointable
|
||||
func (x *{{ $type.Name }}Ref) JSONLookup(token string) (any, error) {
|
||||
if token == "$ref" {
|
||||
return x.Ref, nil
|
||||
}
|
||||
|
||||
if v, ok := x.Extensions[token]; ok {
|
||||
return v, nil
|
||||
}
|
||||
|
||||
ptr, _, err := jsonpointer.GetForToken(x.Value, token)
|
||||
return ptr, err
|
||||
}
|
||||
{{ end -}}
|
||||
54
vendor/github.com/getkin/kin-openapi/openapi3/refs_test.tmpl
generated
vendored
Normal file
54
vendor/github.com/getkin/kin-openapi/openapi3/refs_test.tmpl
generated
vendored
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
// Code generated by go generate; DO NOT EDIT.
|
||||
package {{ .Package }}
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
{{ range $type := .Types }}
|
||||
func Test{{ $type.Name }}Ref_Extensions(t *testing.T) {
|
||||
data := []byte(`{"$ref":"#/components/schemas/Pet","something":"integer","x-order":1}`)
|
||||
|
||||
ref := {{ $type.Name }}Ref{}
|
||||
err := json.Unmarshal(data, &ref)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// captures extension
|
||||
assert.Equal(t, "#/components/schemas/Pet", ref.Ref)
|
||||
assert.Equal(t, float64(1), ref.Extensions["x-order"])
|
||||
|
||||
// does not capture non-extensions
|
||||
assert.Nil(t, ref.Extensions["something"])
|
||||
|
||||
// validation
|
||||
err = ref.Validate(context.Background())
|
||||
require.EqualError(t, err, "extra sibling fields: [something]")
|
||||
|
||||
err = ref.Validate(context.Background(), ProhibitExtensionsWithRef())
|
||||
require.EqualError(t, err, "extra sibling fields: [something x-order]")
|
||||
|
||||
err = ref.Validate(context.Background(), AllowExtraSiblingFields("something"))
|
||||
assert.ErrorContains(t, err, "found unresolved ref") // expected since value not defined
|
||||
|
||||
// non-extension not json lookable
|
||||
_, err = ref.JSONLookup("something")
|
||||
assert.Error(t, err)
|
||||
{{ if ne $type.Name "Header" }}
|
||||
t.Run("extentions in value", func(t *testing.T) {
|
||||
ref.Value = &{{ $type.Name }}{Extensions: map[string]any{}}
|
||||
ref.Value.Extensions["x-order"] = 2.0
|
||||
|
||||
// prefers the value next to the \$ref over the one in the \$ref.
|
||||
v, err := ref.JSONLookup("x-order")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, float64(1), v)
|
||||
})
|
||||
{{ else }}
|
||||
// Header does not have its own extensions.
|
||||
{{ end -}}
|
||||
}
|
||||
{{ end -}}
|
||||
94
vendor/github.com/getkin/kin-openapi/openapi3/request_body.go
generated
vendored
94
vendor/github.com/getkin/kin-openapi/openapi3/request_body.go
generated
vendored
|
|
@ -2,33 +2,15 @@ package openapi3
|
|||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/getkin/kin-openapi/jsoninfo"
|
||||
"github.com/go-openapi/jsonpointer"
|
||||
)
|
||||
|
||||
type RequestBodies map[string]*RequestBodyRef
|
||||
|
||||
var _ jsonpointer.JSONPointable = (*RequestBodyRef)(nil)
|
||||
|
||||
func (r RequestBodies) JSONLookup(token string) (interface{}, error) {
|
||||
ref, ok := r[token]
|
||||
if ok == false {
|
||||
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#requestBodyObject
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#request-body-object
|
||||
type RequestBody struct {
|
||||
ExtensionProps
|
||||
Extensions map[string]any `json:"-" yaml:"-"`
|
||||
Origin *Origin `json:"__origin__,omitempty" yaml:"__origin__,omitempty"`
|
||||
|
||||
Description string `json:"description,omitempty" yaml:"description,omitempty"`
|
||||
Required bool `json:"required,omitempty" yaml:"required,omitempty"`
|
||||
|
|
@ -92,17 +74,73 @@ func (requestBody *RequestBody) GetMediaType(mediaType string) *MediaType {
|
|||
return m[mediaType]
|
||||
}
|
||||
|
||||
func (requestBody *RequestBody) MarshalJSON() ([]byte, error) {
|
||||
return jsoninfo.MarshalStrictStruct(requestBody)
|
||||
// MarshalJSON returns the JSON encoding of RequestBody.
|
||||
func (requestBody RequestBody) MarshalJSON() ([]byte, error) {
|
||||
x, err := requestBody.MarshalYAML()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return json.Marshal(x)
|
||||
}
|
||||
|
||||
// MarshalYAML returns the YAML encoding of RequestBody.
|
||||
func (requestBody RequestBody) MarshalYAML() (any, error) {
|
||||
m := make(map[string]any, 3+len(requestBody.Extensions))
|
||||
for k, v := range requestBody.Extensions {
|
||||
m[k] = v
|
||||
}
|
||||
if x := requestBody.Description; x != "" {
|
||||
m["description"] = requestBody.Description
|
||||
}
|
||||
if x := requestBody.Required; x {
|
||||
m["required"] = x
|
||||
}
|
||||
if x := requestBody.Content; true {
|
||||
m["content"] = x
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON sets RequestBody to a copy of data.
|
||||
func (requestBody *RequestBody) UnmarshalJSON(data []byte) error {
|
||||
return jsoninfo.UnmarshalStrictStruct(data, requestBody)
|
||||
type RequestBodyBis RequestBody
|
||||
var x RequestBodyBis
|
||||
if err := json.Unmarshal(data, &x); err != nil {
|
||||
return unmarshalError(err)
|
||||
}
|
||||
_ = json.Unmarshal(data, &x.Extensions)
|
||||
delete(x.Extensions, originKey)
|
||||
delete(x.Extensions, "description")
|
||||
delete(x.Extensions, "required")
|
||||
delete(x.Extensions, "content")
|
||||
if len(x.Extensions) == 0 {
|
||||
x.Extensions = nil
|
||||
}
|
||||
*requestBody = RequestBody(x)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (value *RequestBody) Validate(ctx context.Context) error {
|
||||
if value.Content == nil {
|
||||
// Validate returns an error if RequestBody does not comply with the OpenAPI spec.
|
||||
func (requestBody *RequestBody) Validate(ctx context.Context, opts ...ValidationOption) error {
|
||||
ctx = WithValidationOptions(ctx, opts...)
|
||||
|
||||
if requestBody.Content == nil {
|
||||
return errors.New("content of the request body is required")
|
||||
}
|
||||
return value.Content.Validate(ctx)
|
||||
|
||||
if vo := getValidationOptions(ctx); !vo.examplesValidationDisabled {
|
||||
vo.examplesValidationAsReq, vo.examplesValidationAsRes = true, false
|
||||
}
|
||||
|
||||
if err := requestBody.Content.Validate(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return validateExtensions(ctx, requestBody.Extensions)
|
||||
}
|
||||
|
||||
// UnmarshalJSON sets RequestBodies to a copy of data.
|
||||
func (requestBodies *RequestBodies) UnmarshalJSON(data []byte) (err error) {
|
||||
*requestBodies, _, err = unmarshalStringMapP[RequestBodyRef](data)
|
||||
return
|
||||
}
|
||||
|
|
|
|||
202
vendor/github.com/getkin/kin-openapi/openapi3/response.go
generated
vendored
202
vendor/github.com/getkin/kin-openapi/openapi3/response.go
generated
vendored
|
|
@ -2,62 +2,108 @@ package openapi3
|
|||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strconv"
|
||||
|
||||
"github.com/getkin/kin-openapi/jsoninfo"
|
||||
"github.com/go-openapi/jsonpointer"
|
||||
)
|
||||
|
||||
// Responses is specified by OpenAPI/Swagger 3.0 standard.
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#responsesObject
|
||||
type Responses map[string]*ResponseRef
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#responses-object
|
||||
type Responses struct {
|
||||
Extensions map[string]any `json:"-" yaml:"-"`
|
||||
Origin *Origin `json:"-" yaml:"-"`
|
||||
|
||||
var _ jsonpointer.JSONPointable = (*Responses)(nil)
|
||||
|
||||
func NewResponses() Responses {
|
||||
r := make(Responses)
|
||||
r["default"] = &ResponseRef{Value: NewResponse().WithDescription("")}
|
||||
return r
|
||||
m map[string]*ResponseRef
|
||||
}
|
||||
|
||||
func (responses Responses) Default() *ResponseRef {
|
||||
return responses["default"]
|
||||
}
|
||||
|
||||
func (responses Responses) Get(status int) *ResponseRef {
|
||||
return responses[strconv.FormatInt(int64(status), 10)]
|
||||
}
|
||||
|
||||
func (value Responses) Validate(ctx context.Context) error {
|
||||
if len(value) == 0 {
|
||||
return errors.New("the responses object MUST contain at least one response code")
|
||||
// NewResponses builds a responses object with response objects in insertion order.
|
||||
// Given no arguments, NewResponses returns a valid responses object containing a default match-all reponse.
|
||||
func NewResponses(opts ...NewResponsesOption) *Responses {
|
||||
if len(opts) == 0 {
|
||||
return NewResponses(WithName("default", NewResponse().WithDescription("")))
|
||||
}
|
||||
for _, v := range value {
|
||||
if err := v.Validate(ctx); err != nil {
|
||||
return err
|
||||
responses := NewResponsesWithCapacity(len(opts))
|
||||
for _, opt := range opts {
|
||||
opt(responses)
|
||||
}
|
||||
return responses
|
||||
}
|
||||
|
||||
// NewResponsesOption describes options to NewResponses func
|
||||
type NewResponsesOption func(*Responses)
|
||||
|
||||
// WithStatus adds a status code keyed ResponseRef
|
||||
func WithStatus(status int, responseRef *ResponseRef) NewResponsesOption {
|
||||
return func(responses *Responses) {
|
||||
if r := responseRef; r != nil {
|
||||
code := strconv.FormatInt(int64(status), 10)
|
||||
responses.Set(code, r)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WithName adds a name-keyed Response
|
||||
func WithName(name string, response *Response) NewResponsesOption {
|
||||
return func(responses *Responses) {
|
||||
if r := response; r != nil && name != "" {
|
||||
responses.Set(name, &ResponseRef{Value: r})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Default returns the default response
|
||||
func (responses *Responses) Default() *ResponseRef {
|
||||
return responses.Value("default")
|
||||
}
|
||||
|
||||
// Status returns a ResponseRef for the given status
|
||||
// If an exact match isn't initially found a patterned field is checked using
|
||||
// the first digit to determine the range (eg: 201 to 2XX)
|
||||
// See https://spec.openapis.org/oas/v3.0.3#patterned-fields-0
|
||||
func (responses *Responses) Status(status int) *ResponseRef {
|
||||
st := strconv.FormatInt(int64(status), 10)
|
||||
if rref := responses.Value(st); rref != nil {
|
||||
return rref
|
||||
}
|
||||
if 99 < status && status < 600 {
|
||||
st = string(st[0]) + "XX"
|
||||
switch st {
|
||||
case "1XX", "2XX", "3XX", "4XX", "5XX":
|
||||
return responses.Value(st)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (responses Responses) JSONLookup(token string) (interface{}, error) {
|
||||
ref, ok := responses[token]
|
||||
if ok == false {
|
||||
return nil, fmt.Errorf("invalid token reference: %q", token)
|
||||
// Validate returns an error if Responses does not comply with the OpenAPI spec.
|
||||
func (responses *Responses) Validate(ctx context.Context, opts ...ValidationOption) error {
|
||||
ctx = WithValidationOptions(ctx, opts...)
|
||||
|
||||
if responses.Len() == 0 {
|
||||
return errors.New("the responses object MUST contain at least one response code")
|
||||
}
|
||||
|
||||
if ref != nil && ref.Ref != "" {
|
||||
return &Ref{Ref: ref.Ref}, nil
|
||||
keys := make([]string, 0, responses.Len())
|
||||
for key := range responses.Map() {
|
||||
keys = append(keys, key)
|
||||
}
|
||||
return ref.Value, nil
|
||||
sort.Strings(keys)
|
||||
for _, key := range keys {
|
||||
v := responses.Value(key)
|
||||
if err := v.Validate(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return validateExtensions(ctx, responses.Extensions)
|
||||
}
|
||||
|
||||
// Response is specified by OpenAPI/Swagger 3.0 standard.
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#responseObject
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#response-object
|
||||
type Response struct {
|
||||
ExtensionProps
|
||||
Extensions map[string]any `json:"-" yaml:"-"`
|
||||
Origin *Origin `json:"__origin__,omitempty" yaml:"__origin__,omitempty"`
|
||||
|
||||
Description *string `json:"description,omitempty" yaml:"description,omitempty"`
|
||||
Headers Headers `json:"headers,omitempty" yaml:"headers,omitempty"`
|
||||
|
|
@ -89,34 +135,102 @@ func (response *Response) WithJSONSchemaRef(schema *SchemaRef) *Response {
|
|||
return response
|
||||
}
|
||||
|
||||
func (response *Response) MarshalJSON() ([]byte, error) {
|
||||
return jsoninfo.MarshalStrictStruct(response)
|
||||
// MarshalJSON returns the JSON encoding of Response.
|
||||
func (response Response) MarshalJSON() ([]byte, error) {
|
||||
x, err := response.MarshalYAML()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return json.Marshal(x)
|
||||
}
|
||||
|
||||
// MarshalYAML returns the YAML encoding of Response.
|
||||
func (response Response) MarshalYAML() (any, error) {
|
||||
m := make(map[string]any, 4+len(response.Extensions))
|
||||
for k, v := range response.Extensions {
|
||||
m[k] = v
|
||||
}
|
||||
if x := response.Description; x != nil {
|
||||
m["description"] = x
|
||||
}
|
||||
if x := response.Headers; len(x) != 0 {
|
||||
m["headers"] = x
|
||||
}
|
||||
if x := response.Content; len(x) != 0 {
|
||||
m["content"] = x
|
||||
}
|
||||
if x := response.Links; len(x) != 0 {
|
||||
m["links"] = x
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON sets Response to a copy of data.
|
||||
func (response *Response) UnmarshalJSON(data []byte) error {
|
||||
return jsoninfo.UnmarshalStrictStruct(data, response)
|
||||
type ResponseBis Response
|
||||
var x ResponseBis
|
||||
if err := json.Unmarshal(data, &x); err != nil {
|
||||
return unmarshalError(err)
|
||||
}
|
||||
_ = json.Unmarshal(data, &x.Extensions)
|
||||
delete(x.Extensions, originKey)
|
||||
delete(x.Extensions, "description")
|
||||
delete(x.Extensions, "headers")
|
||||
delete(x.Extensions, "content")
|
||||
delete(x.Extensions, "links")
|
||||
if len(x.Extensions) == 0 {
|
||||
x.Extensions = nil
|
||||
}
|
||||
*response = Response(x)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (value *Response) Validate(ctx context.Context) error {
|
||||
if value.Description == nil {
|
||||
// Validate returns an error if Response does not comply with the OpenAPI spec.
|
||||
func (response *Response) Validate(ctx context.Context, opts ...ValidationOption) error {
|
||||
ctx = WithValidationOptions(ctx, opts...)
|
||||
|
||||
if response.Description == nil {
|
||||
return errors.New("a short description of the response is required")
|
||||
}
|
||||
if vo := getValidationOptions(ctx); !vo.examplesValidationDisabled {
|
||||
vo.examplesValidationAsReq, vo.examplesValidationAsRes = false, true
|
||||
}
|
||||
|
||||
if content := value.Content; content != nil {
|
||||
if content := response.Content; content != nil {
|
||||
if err := content.Validate(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
for _, header := range value.Headers {
|
||||
|
||||
headers := make([]string, 0, len(response.Headers))
|
||||
for name := range response.Headers {
|
||||
headers = append(headers, name)
|
||||
}
|
||||
sort.Strings(headers)
|
||||
for _, name := range headers {
|
||||
header := response.Headers[name]
|
||||
if err := header.Validate(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
for _, link := range value.Links {
|
||||
links := make([]string, 0, len(response.Links))
|
||||
for name := range response.Links {
|
||||
links = append(links, name)
|
||||
}
|
||||
sort.Strings(links)
|
||||
for _, name := range links {
|
||||
link := response.Links[name]
|
||||
if err := link.Validate(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
||||
return validateExtensions(ctx, response.Extensions)
|
||||
}
|
||||
|
||||
// UnmarshalJSON sets ResponseBodies to a copy of data.
|
||||
func (responseBodies *ResponseBodies) UnmarshalJSON(data []byte) (err error) {
|
||||
*responseBodies, _, err = unmarshalStringMapP[ResponseRef](data)
|
||||
return
|
||||
}
|
||||
|
|
|
|||
1554
vendor/github.com/getkin/kin-openapi/openapi3/schema.go
generated
vendored
1554
vendor/github.com/getkin/kin-openapi/openapi3/schema.go
generated
vendored
File diff suppressed because it is too large
Load diff
234
vendor/github.com/getkin/kin-openapi/openapi3/schema_formats.go
generated
vendored
234
vendor/github.com/getkin/kin-openapi/openapi3/schema_formats.go
generated
vendored
|
|
@ -2,104 +2,170 @@ package openapi3
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"math"
|
||||
"net/netip"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type (
|
||||
// FormatValidator is an interface for custom format validators.
|
||||
FormatValidator[T any] interface {
|
||||
Validate(value T) error
|
||||
}
|
||||
// StringFormatValidator is a type alias for FormatValidator[string]
|
||||
StringFormatValidator = FormatValidator[string]
|
||||
// NumberFormatValidator is a type alias for FormatValidator[float64]
|
||||
NumberFormatValidator = FormatValidator[float64]
|
||||
// IntegerFormatValidator is a type alias for FormatValidator[int64]
|
||||
IntegerFormatValidator = FormatValidator[int64]
|
||||
)
|
||||
|
||||
var (
|
||||
// SchemaStringFormats is a map of custom string format validators.
|
||||
SchemaStringFormats = make(map[string]StringFormatValidator)
|
||||
// SchemaNumberFormats is a map of custom number format validators.
|
||||
SchemaNumberFormats = make(map[string]NumberFormatValidator)
|
||||
// SchemaIntegerFormats is a map of custom integer format validators.
|
||||
SchemaIntegerFormats = make(map[string]IntegerFormatValidator)
|
||||
)
|
||||
|
||||
const (
|
||||
// FormatOfStringForUUIDOfRFC4122 is an optional predefined format for UUID v1-v5 as specified by RFC4122
|
||||
FormatOfStringForUUIDOfRFC4122 = `^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-5][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$`
|
||||
FormatOfStringForUUIDOfRFC4122 = `^(?:[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-5][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000)$`
|
||||
|
||||
// FormatOfStringForEmail pattern catches only some suspiciously wrong-looking email addresses.
|
||||
// Use DefineStringFormat(...) if you need something stricter.
|
||||
FormatOfStringForEmail = `^[^@]+@[^@<>",\s]+$`
|
||||
|
||||
// FormatOfStringByte is a regexp for base64-encoded characters, for example, "U3dhZ2dlciByb2Nrcw=="
|
||||
FormatOfStringByte = `(^$|^[a-zA-Z0-9+/\-_]*=*$)`
|
||||
|
||||
// FormatOfStringDate is a RFC3339 date format regexp, for example "2017-07-21".
|
||||
FormatOfStringDate = `^[0-9]{4}-(0[1-9]|10|11|12)-(0[1-9]|[12][0-9]|3[01])$`
|
||||
|
||||
// FormatOfStringDateTime is a RFC3339 date-time format regexp, for example "2017-07-21T17:32:28Z".
|
||||
FormatOfStringDateTime = `^[0-9]{4}-(0[1-9]|10|11|12)-(0[1-9]|[12][0-9]|3[01])T([0-1][0-9]|2[0-3]):[0-5][0-9]:([0-5][0-9]|60)(\.[0-9]+)?(Z|(\+|-)[0-9]{2}:[0-9]{2})?$`
|
||||
)
|
||||
|
||||
//FormatCallback custom check on exotic formats
|
||||
type FormatCallback func(Val string) error
|
||||
|
||||
type Format struct {
|
||||
regexp *regexp.Regexp
|
||||
callback FormatCallback
|
||||
}
|
||||
|
||||
//SchemaStringFormats allows for validating strings format
|
||||
var SchemaStringFormats = make(map[string]Format, 8)
|
||||
|
||||
//DefineStringFormat Defines a new regexp pattern for a given format
|
||||
func DefineStringFormat(name string, pattern string) {
|
||||
re, err := regexp.Compile(pattern)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("format %q has invalid pattern %q: %v", name, pattern, err)
|
||||
panic(err)
|
||||
}
|
||||
SchemaStringFormats[name] = Format{regexp: re}
|
||||
}
|
||||
|
||||
// DefineStringFormatCallback adds a validation function for a specific schema format entry
|
||||
func DefineStringFormatCallback(name string, callback FormatCallback) {
|
||||
SchemaStringFormats[name] = Format{callback: callback}
|
||||
}
|
||||
|
||||
func validateIP(ip string) error {
|
||||
parsed := net.ParseIP(ip)
|
||||
if parsed == nil {
|
||||
return &SchemaError{
|
||||
Value: ip,
|
||||
Reason: "Not an IP address",
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateIPv4(ip string) error {
|
||||
if err := validateIP(ip); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !(strings.Count(ip, ":") < 2) {
|
||||
return &SchemaError{
|
||||
Value: ip,
|
||||
Reason: "Not an IPv4 address (it's IPv6)",
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateIPv6(ip string) error {
|
||||
if err := validateIP(ip); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !(strings.Count(ip, ":") >= 2) {
|
||||
return &SchemaError{
|
||||
Value: ip,
|
||||
Reason: "Not an IPv6 address (it's IPv4)",
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
// This pattern catches only some suspiciously wrong-looking email addresses.
|
||||
// Use DefineStringFormat(...) if you need something stricter.
|
||||
DefineStringFormat("email", `^[^@]+@[^@<>",\s]+$`)
|
||||
|
||||
// Base64
|
||||
// The pattern supports base64 and b./ase64url. Padding ('=') is supported.
|
||||
DefineStringFormat("byte", `(^$|^[a-zA-Z0-9+/\-_]*=*$)`)
|
||||
|
||||
// date
|
||||
DefineStringFormat("date", `^[0-9]{4}-(0[0-9]|10|11|12)-([0-2][0-9]|30|31)$`)
|
||||
|
||||
// date-time
|
||||
DefineStringFormat("date-time", `^[0-9]{4}-(0[0-9]|10|11|12)-([0-2][0-9]|30|31)T[0-9]{2}:[0-9]{2}:[0-9]{2}(\.[0-9]+)?(Z|(\+|-)[0-9]{2}:[0-9]{2})?$`)
|
||||
|
||||
DefineStringFormatValidator("byte", NewRegexpFormatValidator(FormatOfStringByte))
|
||||
DefineStringFormatValidator("date", NewRegexpFormatValidator(FormatOfStringDate))
|
||||
DefineStringFormatValidator("date-time", NewRegexpFormatValidator(FormatOfStringDateTime))
|
||||
DefineIntegerFormatValidator("int32", NewRangeFormatValidator(int64(math.MinInt32), int64(math.MaxInt32)))
|
||||
DefineIntegerFormatValidator("int64", NewRangeFormatValidator(int64(math.MinInt64), int64(math.MaxInt64)))
|
||||
}
|
||||
|
||||
// DefineIPv4Format opts in ipv4 format validation on top of OAS 3 spec
|
||||
func DefineIPv4Format() {
|
||||
DefineStringFormatCallback("ipv4", validateIPv4)
|
||||
DefineStringFormatValidator("ipv4", NewIPValidator(true))
|
||||
}
|
||||
|
||||
// DefineIPv6Format opts in ipv6 format validation on top of OAS 3 spec
|
||||
func DefineIPv6Format() {
|
||||
DefineStringFormatCallback("ipv6", validateIPv6)
|
||||
DefineStringFormatValidator("ipv6", NewIPValidator(false))
|
||||
}
|
||||
|
||||
type stringRegexpFormatValidator struct {
|
||||
re *regexp.Regexp
|
||||
}
|
||||
|
||||
func (s stringRegexpFormatValidator) Validate(value string) error {
|
||||
if !s.re.MatchString(value) {
|
||||
return fmt.Errorf(`string doesn't match pattern "%s"`, s.re.String())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type callbackValidator[T any] struct {
|
||||
fn func(T) error
|
||||
}
|
||||
|
||||
func (c callbackValidator[T]) Validate(value T) error {
|
||||
return c.fn(value)
|
||||
}
|
||||
|
||||
type rangeFormat[T int64 | float64] struct {
|
||||
min, max T
|
||||
}
|
||||
|
||||
func (r rangeFormat[T]) Validate(value T) error {
|
||||
if value < r.min || value > r.max {
|
||||
return fmt.Errorf("value should be between %v and %v", r.min, r.max)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewRangeFormatValidator creates a new FormatValidator that validates the value is within a given range.
|
||||
func NewRangeFormatValidator[T int64 | float64](min, max T) FormatValidator[T] {
|
||||
return rangeFormat[T]{min: min, max: max}
|
||||
}
|
||||
|
||||
// NewRegexpFormatValidator creates a new FormatValidator that uses a regular expression to validate the value.
|
||||
func NewRegexpFormatValidator(pattern string) StringFormatValidator {
|
||||
re, err := regexp.Compile(pattern)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("string regexp format has invalid pattern %q: %w", pattern, err)
|
||||
panic(err)
|
||||
}
|
||||
return stringRegexpFormatValidator{re: re}
|
||||
}
|
||||
|
||||
// NewCallbackValidator creates a new FormatValidator that uses a callback function to validate the value.
|
||||
func NewCallbackValidator[T any](fn func(T) error) FormatValidator[T] {
|
||||
return callbackValidator[T]{fn: fn}
|
||||
}
|
||||
|
||||
// DefineStringFormatValidator defines a custom format validator for a given string format.
|
||||
func DefineStringFormatValidator(name string, validator StringFormatValidator) {
|
||||
SchemaStringFormats[name] = validator
|
||||
}
|
||||
|
||||
// DefineNumberFormatValidator defines a custom format validator for a given number format.
|
||||
func DefineNumberFormatValidator(name string, validator NumberFormatValidator) {
|
||||
SchemaNumberFormats[name] = validator
|
||||
}
|
||||
|
||||
// DefineIntegerFormatValidator defines a custom format validator for a given integer format.
|
||||
func DefineIntegerFormatValidator(name string, validator IntegerFormatValidator) {
|
||||
SchemaIntegerFormats[name] = validator
|
||||
}
|
||||
|
||||
// DefineStringFormat defines a regexp pattern for a given string format
|
||||
//
|
||||
// Deprecated: Use openapi3.DefineStringFormatValidator(name, NewRegexpFormatValidator(pattern)) instead.
|
||||
func DefineStringFormat(name string, pattern string) {
|
||||
DefineStringFormatValidator(name, NewRegexpFormatValidator(pattern))
|
||||
}
|
||||
|
||||
// DefineStringFormatCallback defines a callback function for a given string format
|
||||
//
|
||||
// Deprecated: Use openapi3.DefineStringFormatValidator(name, NewCallbackValidator(fn)) instead.
|
||||
func DefineStringFormatCallback(name string, callback func(string) error) {
|
||||
DefineStringFormatValidator(name, NewCallbackValidator(callback))
|
||||
}
|
||||
|
||||
// NewIPValidator creates a new FormatValidator that validates the value is an IP address.
|
||||
func NewIPValidator(isIPv4 bool) FormatValidator[string] {
|
||||
return callbackValidator[string]{fn: func(ip string) error {
|
||||
addr, err := netip.ParseAddr(ip)
|
||||
if err != nil {
|
||||
return &SchemaError{
|
||||
Value: ip,
|
||||
Reason: "Not an IP address",
|
||||
}
|
||||
}
|
||||
if isIPv4 && !addr.Is4() {
|
||||
return &SchemaError{
|
||||
Value: ip,
|
||||
Reason: "Not an IPv4 address (it's IPv6)",
|
||||
}
|
||||
}
|
||||
if !isIPv4 && !addr.Is6() {
|
||||
return &SchemaError{
|
||||
Value: ip,
|
||||
Reason: "Not an IPv6 address (it's IPv4)",
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}}
|
||||
}
|
||||
|
|
|
|||
35
vendor/github.com/getkin/kin-openapi/openapi3/schema_pattern.go
generated
vendored
Normal file
35
vendor/github.com/getkin/kin-openapi/openapi3/schema_pattern.go
generated
vendored
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
package openapi3
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
var patRewriteCodepoints = regexp.MustCompile(`(?P<replaced_with_slash_x>\\u)(?P<code>[0-9A-F]{4})`)
|
||||
|
||||
// See https://pkg.go.dev/regexp/syntax
|
||||
func intoGoRegexp(re string) string {
|
||||
return patRewriteCodepoints.ReplaceAllString(re, `\x{${code}}`)
|
||||
}
|
||||
|
||||
// NOTE: racey WRT [writes to schema.Pattern] vs [reads schema.Pattern then writes to compiledPatterns]
|
||||
func (schema *Schema) compilePattern(c RegexCompilerFunc) (cp RegexMatcher, err error) {
|
||||
pattern := schema.Pattern
|
||||
if c != nil {
|
||||
cp, err = c(pattern)
|
||||
} else {
|
||||
cp, err = regexp.Compile(intoGoRegexp(pattern))
|
||||
}
|
||||
if err != nil {
|
||||
err = &SchemaError{
|
||||
Schema: schema,
|
||||
SchemaField: "pattern",
|
||||
Origin: err,
|
||||
Reason: fmt.Sprintf("cannot compile pattern %q: %v", pattern, err),
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
var _ bool = compiledPatterns.CompareAndSwap(pattern, nil, cp)
|
||||
return
|
||||
}
|
||||
64
vendor/github.com/getkin/kin-openapi/openapi3/schema_validation_settings.go
generated
vendored
64
vendor/github.com/getkin/kin-openapi/openapi3/schema_validation_settings.go
generated
vendored
|
|
@ -1,12 +1,33 @@
|
|||
package openapi3
|
||||
|
||||
import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
// SchemaValidationOption describes options a user has when validating request / response bodies.
|
||||
type SchemaValidationOption func(*schemaValidationSettings)
|
||||
|
||||
type RegexCompilerFunc func(expr string) (RegexMatcher, error)
|
||||
|
||||
type RegexMatcher interface {
|
||||
MatchString(s string) bool
|
||||
}
|
||||
|
||||
type schemaValidationSettings struct {
|
||||
failfast bool
|
||||
multiError bool
|
||||
asreq, asrep bool // exclusive (XOR) fields
|
||||
failfast bool
|
||||
multiError bool
|
||||
asreq, asrep bool // exclusive (XOR) fields
|
||||
formatValidationEnabled bool
|
||||
patternValidationDisabled bool
|
||||
readOnlyValidationDisabled bool
|
||||
writeOnlyValidationDisabled bool
|
||||
|
||||
regexCompiler RegexCompilerFunc
|
||||
|
||||
onceSettingDefaults sync.Once
|
||||
defaultsSet func()
|
||||
|
||||
customizeMessageError func(err *SchemaError) string
|
||||
}
|
||||
|
||||
// FailFast returns schema validation errors quicker.
|
||||
|
|
@ -21,10 +42,47 @@ func MultiErrors() SchemaValidationOption {
|
|||
func VisitAsRequest() SchemaValidationOption {
|
||||
return func(s *schemaValidationSettings) { s.asreq, s.asrep = true, false }
|
||||
}
|
||||
|
||||
func VisitAsResponse() SchemaValidationOption {
|
||||
return func(s *schemaValidationSettings) { s.asreq, s.asrep = false, true }
|
||||
}
|
||||
|
||||
// EnableFormatValidation setting makes Validate not return an error when validating documents that mention schema formats that are not defined by the OpenAPIv3 specification.
|
||||
func EnableFormatValidation() SchemaValidationOption {
|
||||
return func(s *schemaValidationSettings) { s.formatValidationEnabled = true }
|
||||
}
|
||||
|
||||
// DisablePatternValidation setting makes Validate not return an error when validating patterns that are not supported by the Go regexp engine.
|
||||
func DisablePatternValidation() SchemaValidationOption {
|
||||
return func(s *schemaValidationSettings) { s.patternValidationDisabled = true }
|
||||
}
|
||||
|
||||
// DisableReadOnlyValidation setting makes Validate not return an error when validating properties marked as read-only
|
||||
func DisableReadOnlyValidation() SchemaValidationOption {
|
||||
return func(s *schemaValidationSettings) { s.readOnlyValidationDisabled = true }
|
||||
}
|
||||
|
||||
// DisableWriteOnlyValidation setting makes Validate not return an error when validating properties marked as write-only
|
||||
func DisableWriteOnlyValidation() SchemaValidationOption {
|
||||
return func(s *schemaValidationSettings) { s.writeOnlyValidationDisabled = true }
|
||||
}
|
||||
|
||||
// DefaultsSet executes the given callback (once) IFF schema validation set default values.
|
||||
func DefaultsSet(f func()) SchemaValidationOption {
|
||||
return func(s *schemaValidationSettings) { s.defaultsSet = f }
|
||||
}
|
||||
|
||||
// SetSchemaErrorMessageCustomizer allows to override the schema error message.
|
||||
// If the passed function returns an empty string, it returns to the previous Error() implementation.
|
||||
func SetSchemaErrorMessageCustomizer(f func(err *SchemaError) string) SchemaValidationOption {
|
||||
return func(s *schemaValidationSettings) { s.customizeMessageError = f }
|
||||
}
|
||||
|
||||
// SetSchemaRegexCompiler allows to override the regex implementation used to validate field "pattern".
|
||||
func SetSchemaRegexCompiler(c RegexCompilerFunc) SchemaValidationOption {
|
||||
return func(s *schemaValidationSettings) { s.regexCompiler = c }
|
||||
}
|
||||
|
||||
func newSchemaValidationSettings(opts ...SchemaValidationOption) *schemaValidationSettings {
|
||||
settings := &schemaValidationSettings{}
|
||||
for _, opt := range opts {
|
||||
|
|
|
|||
22
vendor/github.com/getkin/kin-openapi/openapi3/security_requirements.go
generated
vendored
22
vendor/github.com/getkin/kin-openapi/openapi3/security_requirements.go
generated
vendored
|
|
@ -15,9 +15,12 @@ func (srs *SecurityRequirements) With(securityRequirement SecurityRequirement) *
|
|||
return srs
|
||||
}
|
||||
|
||||
func (value SecurityRequirements) Validate(ctx context.Context) error {
|
||||
for _, item := range value {
|
||||
if err := item.Validate(ctx); err != nil {
|
||||
// Validate returns an error if SecurityRequirements does not comply with the OpenAPI spec.
|
||||
func (srs SecurityRequirements) Validate(ctx context.Context, opts ...ValidationOption) error {
|
||||
ctx = WithValidationOptions(ctx, opts...)
|
||||
|
||||
for _, security := range srs {
|
||||
if err := security.Validate(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
|
@ -25,7 +28,7 @@ func (value SecurityRequirements) Validate(ctx context.Context) error {
|
|||
}
|
||||
|
||||
// SecurityRequirement is specified by OpenAPI/Swagger standard version 3.
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#securityRequirementObject
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#security-requirement-object
|
||||
type SecurityRequirement map[string][]string
|
||||
|
||||
func NewSecurityRequirement() SecurityRequirement {
|
||||
|
|
@ -40,6 +43,15 @@ func (security SecurityRequirement) Authenticate(provider string, scopes ...stri
|
|||
return security
|
||||
}
|
||||
|
||||
func (value SecurityRequirement) Validate(ctx context.Context) error {
|
||||
// Validate returns an error if SecurityRequirement does not comply with the OpenAPI spec.
|
||||
func (security *SecurityRequirement) Validate(ctx context.Context, opts ...ValidationOption) error {
|
||||
ctx = WithValidationOptions(ctx, opts...)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON sets SecurityRequirement to a copy of data.
|
||||
func (security *SecurityRequirement) UnmarshalJSON(data []byte) (err error) {
|
||||
*security, _, err = unmarshalStringMap[[]string](data)
|
||||
return
|
||||
}
|
||||
|
|
|
|||
351
vendor/github.com/getkin/kin-openapi/openapi3/security_scheme.go
generated
vendored
351
vendor/github.com/getkin/kin-openapi/openapi3/security_scheme.go
generated
vendored
|
|
@ -2,33 +2,17 @@ package openapi3
|
|||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/getkin/kin-openapi/jsoninfo"
|
||||
"github.com/go-openapi/jsonpointer"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
type SecuritySchemes map[string]*SecuritySchemeRef
|
||||
|
||||
func (s SecuritySchemes) JSONLookup(token string) (interface{}, error) {
|
||||
ref, ok := s[token]
|
||||
if ref == nil || ok == false {
|
||||
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#securitySchemeObject
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#security-scheme-object
|
||||
type SecurityScheme struct {
|
||||
ExtensionProps
|
||||
Extensions map[string]any `json:"-" yaml:"-"`
|
||||
Origin *Origin `json:"__origin__,omitempty" yaml:"__origin__,omitempty"`
|
||||
|
||||
Type string `json:"type,omitempty" yaml:"type,omitempty"`
|
||||
Description string `json:"description,omitempty" yaml:"description,omitempty"`
|
||||
|
|
@ -67,12 +51,70 @@ func NewJWTSecurityScheme() *SecurityScheme {
|
|||
}
|
||||
}
|
||||
|
||||
func (ss *SecurityScheme) MarshalJSON() ([]byte, error) {
|
||||
return jsoninfo.MarshalStrictStruct(ss)
|
||||
// MarshalJSON returns the JSON encoding of SecurityScheme.
|
||||
func (ss SecurityScheme) MarshalJSON() ([]byte, error) {
|
||||
x, err := ss.MarshalYAML()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return json.Marshal(x)
|
||||
}
|
||||
|
||||
// MarshalYAML returns the YAML encoding of SecurityScheme.
|
||||
func (ss SecurityScheme) MarshalYAML() (any, error) {
|
||||
m := make(map[string]any, 8+len(ss.Extensions))
|
||||
for k, v := range ss.Extensions {
|
||||
m[k] = v
|
||||
}
|
||||
if x := ss.Type; x != "" {
|
||||
m["type"] = x
|
||||
}
|
||||
if x := ss.Description; x != "" {
|
||||
m["description"] = x
|
||||
}
|
||||
if x := ss.Name; x != "" {
|
||||
m["name"] = x
|
||||
}
|
||||
if x := ss.In; x != "" {
|
||||
m["in"] = x
|
||||
}
|
||||
if x := ss.Scheme; x != "" {
|
||||
m["scheme"] = x
|
||||
}
|
||||
if x := ss.BearerFormat; x != "" {
|
||||
m["bearerFormat"] = x
|
||||
}
|
||||
if x := ss.Flows; x != nil {
|
||||
m["flows"] = x
|
||||
}
|
||||
if x := ss.OpenIdConnectUrl; x != "" {
|
||||
m["openIdConnectUrl"] = x
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON sets SecurityScheme to a copy of data.
|
||||
func (ss *SecurityScheme) UnmarshalJSON(data []byte) error {
|
||||
return jsoninfo.UnmarshalStrictStruct(data, ss)
|
||||
type SecuritySchemeBis SecurityScheme
|
||||
var x SecuritySchemeBis
|
||||
if err := json.Unmarshal(data, &x); err != nil {
|
||||
return unmarshalError(err)
|
||||
}
|
||||
_ = json.Unmarshal(data, &x.Extensions)
|
||||
delete(x.Extensions, originKey)
|
||||
delete(x.Extensions, "type")
|
||||
delete(x.Extensions, "description")
|
||||
delete(x.Extensions, "name")
|
||||
delete(x.Extensions, "in")
|
||||
delete(x.Extensions, "scheme")
|
||||
delete(x.Extensions, "bearerFormat")
|
||||
delete(x.Extensions, "flows")
|
||||
delete(x.Extensions, "openIdConnectUrl")
|
||||
if len(x.Extensions) == 0 {
|
||||
x.Extensions = nil
|
||||
}
|
||||
*ss = SecurityScheme(x)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ss *SecurityScheme) WithType(value string) *SecurityScheme {
|
||||
|
|
@ -105,15 +147,18 @@ func (ss *SecurityScheme) WithBearerFormat(value string) *SecurityScheme {
|
|||
return ss
|
||||
}
|
||||
|
||||
func (value *SecurityScheme) Validate(ctx context.Context) error {
|
||||
// Validate returns an error if SecurityScheme does not comply with the OpenAPI spec.
|
||||
func (ss *SecurityScheme) Validate(ctx context.Context, opts ...ValidationOption) error {
|
||||
ctx = WithValidationOptions(ctx, opts...)
|
||||
|
||||
hasIn := false
|
||||
hasBearerFormat := false
|
||||
hasFlow := false
|
||||
switch value.Type {
|
||||
switch ss.Type {
|
||||
case "apiKey":
|
||||
hasIn = true
|
||||
case "http":
|
||||
scheme := value.Scheme
|
||||
scheme := ss.Scheme
|
||||
switch scheme {
|
||||
case "bearer":
|
||||
hasBearerFormat = true
|
||||
|
|
@ -124,54 +169,56 @@ func (value *SecurityScheme) Validate(ctx context.Context) error {
|
|||
case "oauth2":
|
||||
hasFlow = true
|
||||
case "openIdConnect":
|
||||
if value.OpenIdConnectUrl == "" {
|
||||
return fmt.Errorf("no OIDC URL found for openIdConnect security scheme %q", value.Name)
|
||||
if ss.OpenIdConnectUrl == "" {
|
||||
return fmt.Errorf("no OIDC URL found for openIdConnect security scheme %q", ss.Name)
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("security scheme 'type' can't be %q", value.Type)
|
||||
return fmt.Errorf("security scheme 'type' can't be %q", ss.Type)
|
||||
}
|
||||
|
||||
// Validate "in" and "name"
|
||||
if hasIn {
|
||||
switch value.In {
|
||||
switch ss.In {
|
||||
case "query", "header", "cookie":
|
||||
default:
|
||||
return fmt.Errorf("security scheme of type 'apiKey' should have 'in'. It can be 'query', 'header' or 'cookie', not %q", value.In)
|
||||
return fmt.Errorf("security scheme of type 'apiKey' should have 'in'. It can be 'query', 'header' or 'cookie', not %q", ss.In)
|
||||
}
|
||||
if value.Name == "" {
|
||||
if ss.Name == "" {
|
||||
return errors.New("security scheme of type 'apiKey' should have 'name'")
|
||||
}
|
||||
} else if len(value.In) > 0 {
|
||||
return fmt.Errorf("security scheme of type %q can't have 'in'", value.Type)
|
||||
} else if len(value.Name) > 0 {
|
||||
return errors.New("security scheme of type 'apiKey' can't have 'name'")
|
||||
} else if len(ss.In) > 0 {
|
||||
return fmt.Errorf("security scheme of type %q can't have 'in'", ss.Type)
|
||||
} else if len(ss.Name) > 0 {
|
||||
return fmt.Errorf("security scheme of type %q can't have 'name'", ss.Type)
|
||||
}
|
||||
|
||||
// Validate "format"
|
||||
// "bearerFormat" is an arbitrary string so we only check if the scheme supports it
|
||||
if !hasBearerFormat && len(value.BearerFormat) > 0 {
|
||||
return fmt.Errorf("security scheme of type %q can't have 'bearerFormat'", value.Type)
|
||||
if !hasBearerFormat && len(ss.BearerFormat) > 0 {
|
||||
return fmt.Errorf("security scheme of type %q can't have 'bearerFormat'", ss.Type)
|
||||
}
|
||||
|
||||
// Validate "flow"
|
||||
if hasFlow {
|
||||
flow := value.Flows
|
||||
flow := ss.Flows
|
||||
if flow == nil {
|
||||
return fmt.Errorf("security scheme of type %q should have 'flows'", value.Type)
|
||||
return fmt.Errorf("security scheme of type %q should have 'flows'", ss.Type)
|
||||
}
|
||||
if err := flow.Validate(ctx); err != nil {
|
||||
return fmt.Errorf("security scheme 'flow' is invalid: %v", err)
|
||||
return fmt.Errorf("security scheme 'flow' is invalid: %w", err)
|
||||
}
|
||||
} else if value.Flows != nil {
|
||||
return fmt.Errorf("security scheme of type %q can't have 'flows'", value.Type)
|
||||
} else if ss.Flows != nil {
|
||||
return fmt.Errorf("security scheme of type %q can't have 'flows'", ss.Type)
|
||||
}
|
||||
return nil
|
||||
|
||||
return validateExtensions(ctx, ss.Extensions)
|
||||
}
|
||||
|
||||
// OAuthFlows is specified by OpenAPI/Swagger standard version 3.
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#oauthFlowsObject
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#oauth-flows-object
|
||||
type OAuthFlows struct {
|
||||
ExtensionProps
|
||||
Extensions map[string]any `json:"-" yaml:"-"`
|
||||
Origin *Origin `json:"__origin__,omitempty" yaml:"__origin__,omitempty"`
|
||||
|
||||
Implicit *OAuthFlow `json:"implicit,omitempty" yaml:"implicit,omitempty"`
|
||||
Password *OAuthFlow `json:"password,omitempty" yaml:"password,omitempty"`
|
||||
|
|
@ -188,62 +235,208 @@ const (
|
|||
oAuthFlowAuthorizationCode
|
||||
)
|
||||
|
||||
func (flows *OAuthFlows) MarshalJSON() ([]byte, error) {
|
||||
return jsoninfo.MarshalStrictStruct(flows)
|
||||
// MarshalJSON returns the JSON encoding of OAuthFlows.
|
||||
func (flows OAuthFlows) MarshalJSON() ([]byte, error) {
|
||||
x, err := flows.MarshalYAML()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return json.Marshal(x)
|
||||
}
|
||||
|
||||
// MarshalYAML returns the YAML encoding of OAuthFlows.
|
||||
func (flows OAuthFlows) MarshalYAML() (any, error) {
|
||||
m := make(map[string]any, 4+len(flows.Extensions))
|
||||
for k, v := range flows.Extensions {
|
||||
m[k] = v
|
||||
}
|
||||
if x := flows.Implicit; x != nil {
|
||||
m["implicit"] = x
|
||||
}
|
||||
if x := flows.Password; x != nil {
|
||||
m["password"] = x
|
||||
}
|
||||
if x := flows.ClientCredentials; x != nil {
|
||||
m["clientCredentials"] = x
|
||||
}
|
||||
if x := flows.AuthorizationCode; x != nil {
|
||||
m["authorizationCode"] = x
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON sets OAuthFlows to a copy of data.
|
||||
func (flows *OAuthFlows) UnmarshalJSON(data []byte) error {
|
||||
return jsoninfo.UnmarshalStrictStruct(data, flows)
|
||||
type OAuthFlowsBis OAuthFlows
|
||||
var x OAuthFlowsBis
|
||||
if err := json.Unmarshal(data, &x); err != nil {
|
||||
return unmarshalError(err)
|
||||
}
|
||||
_ = json.Unmarshal(data, &x.Extensions)
|
||||
delete(x.Extensions, originKey)
|
||||
delete(x.Extensions, "implicit")
|
||||
delete(x.Extensions, "password")
|
||||
delete(x.Extensions, "clientCredentials")
|
||||
delete(x.Extensions, "authorizationCode")
|
||||
if len(x.Extensions) == 0 {
|
||||
x.Extensions = nil
|
||||
}
|
||||
*flows = OAuthFlows(x)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (flows *OAuthFlows) Validate(ctx context.Context) error {
|
||||
// Validate returns an error if OAuthFlows does not comply with the OpenAPI spec.
|
||||
func (flows *OAuthFlows) Validate(ctx context.Context, opts ...ValidationOption) error {
|
||||
ctx = WithValidationOptions(ctx, opts...)
|
||||
|
||||
if v := flows.Implicit; v != nil {
|
||||
return v.Validate(ctx, oAuthFlowTypeImplicit)
|
||||
if err := v.validate(ctx, oAuthFlowTypeImplicit, opts...); err != nil {
|
||||
return fmt.Errorf("the OAuth flow 'implicit' is invalid: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
if v := flows.Password; v != nil {
|
||||
return v.Validate(ctx, oAuthFlowTypePassword)
|
||||
if err := v.validate(ctx, oAuthFlowTypePassword, opts...); err != nil {
|
||||
return fmt.Errorf("the OAuth flow 'password' is invalid: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
if v := flows.ClientCredentials; v != nil {
|
||||
return v.Validate(ctx, oAuthFlowTypeClientCredentials)
|
||||
if err := v.validate(ctx, oAuthFlowTypeClientCredentials, opts...); err != nil {
|
||||
return fmt.Errorf("the OAuth flow 'clientCredentials' is invalid: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
if v := flows.AuthorizationCode; v != nil {
|
||||
return v.Validate(ctx, oAuthFlowAuthorizationCode)
|
||||
if err := v.validate(ctx, oAuthFlowAuthorizationCode, opts...); err != nil {
|
||||
return fmt.Errorf("the OAuth flow 'authorizationCode' is invalid: %w", err)
|
||||
}
|
||||
}
|
||||
return errors.New("no OAuth flow is defined")
|
||||
|
||||
return validateExtensions(ctx, flows.Extensions)
|
||||
}
|
||||
|
||||
// OAuthFlow is specified by OpenAPI/Swagger standard version 3.
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#oauthFlowObject
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#oauth-flow-object
|
||||
type OAuthFlow struct {
|
||||
ExtensionProps
|
||||
Extensions map[string]any `json:"-" yaml:"-"`
|
||||
Origin *Origin `json:"__origin__,omitempty" yaml:"__origin__,omitempty"`
|
||||
|
||||
AuthorizationURL string `json:"authorizationUrl,omitempty" yaml:"authorizationUrl,omitempty"`
|
||||
TokenURL string `json:"tokenUrl,omitempty" yaml:"tokenUrl,omitempty"`
|
||||
RefreshURL string `json:"refreshUrl,omitempty" yaml:"refreshUrl,omitempty"`
|
||||
Scopes map[string]string `json:"scopes" yaml:"scopes"`
|
||||
AuthorizationURL string `json:"authorizationUrl,omitempty" yaml:"authorizationUrl,omitempty"`
|
||||
TokenURL string `json:"tokenUrl,omitempty" yaml:"tokenUrl,omitempty"`
|
||||
RefreshURL string `json:"refreshUrl,omitempty" yaml:"refreshUrl,omitempty"`
|
||||
Scopes StringMap `json:"scopes" yaml:"scopes"` // required
|
||||
}
|
||||
|
||||
func (flow *OAuthFlow) MarshalJSON() ([]byte, error) {
|
||||
return jsoninfo.MarshalStrictStruct(flow)
|
||||
// MarshalJSON returns the JSON encoding of OAuthFlow.
|
||||
func (flow OAuthFlow) MarshalJSON() ([]byte, error) {
|
||||
x, err := flow.MarshalYAML()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return json.Marshal(x)
|
||||
}
|
||||
|
||||
// MarshalYAML returns the YAML encoding of OAuthFlow.
|
||||
func (flow OAuthFlow) MarshalYAML() (any, error) {
|
||||
m := make(map[string]any, 4+len(flow.Extensions))
|
||||
for k, v := range flow.Extensions {
|
||||
m[k] = v
|
||||
}
|
||||
if x := flow.AuthorizationURL; x != "" {
|
||||
m["authorizationUrl"] = x
|
||||
}
|
||||
if x := flow.TokenURL; x != "" {
|
||||
m["tokenUrl"] = x
|
||||
}
|
||||
if x := flow.RefreshURL; x != "" {
|
||||
m["refreshUrl"] = x
|
||||
}
|
||||
m["scopes"] = flow.Scopes
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON sets OAuthFlow to a copy of data.
|
||||
func (flow *OAuthFlow) UnmarshalJSON(data []byte) error {
|
||||
return jsoninfo.UnmarshalStrictStruct(data, flow)
|
||||
}
|
||||
type OAuthFlowBis OAuthFlow
|
||||
var x OAuthFlowBis
|
||||
if err := json.Unmarshal(data, &x); err != nil {
|
||||
return unmarshalError(err)
|
||||
}
|
||||
_ = json.Unmarshal(data, &x.Extensions)
|
||||
|
||||
func (flow *OAuthFlow) Validate(ctx context.Context, typ oAuthFlowType) error {
|
||||
if typ == oAuthFlowAuthorizationCode || typ == oAuthFlowTypeImplicit {
|
||||
if v := flow.AuthorizationURL; v == "" {
|
||||
return errors.New("an OAuth flow is missing 'authorizationUrl in authorizationCode or implicit '")
|
||||
}
|
||||
}
|
||||
if typ != oAuthFlowTypeImplicit {
|
||||
if v := flow.TokenURL; v == "" {
|
||||
return errors.New("an OAuth flow is missing 'tokenUrl in not implicit'")
|
||||
}
|
||||
}
|
||||
if v := flow.Scopes; v == nil {
|
||||
return errors.New("an OAuth flow is missing 'scopes'")
|
||||
delete(x.Extensions, originKey)
|
||||
delete(x.Extensions, "authorizationUrl")
|
||||
delete(x.Extensions, "tokenUrl")
|
||||
delete(x.Extensions, "refreshUrl")
|
||||
delete(x.Extensions, "scopes")
|
||||
if len(x.Extensions) == 0 {
|
||||
x.Extensions = nil
|
||||
}
|
||||
*flow = OAuthFlow(x)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Validate returns an error if OAuthFlows does not comply with the OpenAPI spec.
|
||||
func (flow *OAuthFlow) Validate(ctx context.Context, opts ...ValidationOption) error {
|
||||
ctx = WithValidationOptions(ctx, opts...)
|
||||
|
||||
if v := flow.RefreshURL; v != "" {
|
||||
if _, err := url.Parse(v); err != nil {
|
||||
return fmt.Errorf("field 'refreshUrl' is invalid: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
if flow.Scopes == nil {
|
||||
return errors.New("field 'scopes' is missing")
|
||||
}
|
||||
|
||||
return validateExtensions(ctx, flow.Extensions)
|
||||
}
|
||||
|
||||
func (flow *OAuthFlow) validate(ctx context.Context, typ oAuthFlowType, opts ...ValidationOption) error {
|
||||
ctx = WithValidationOptions(ctx, opts...)
|
||||
|
||||
typeIn := func(types ...oAuthFlowType) bool {
|
||||
for _, ty := range types {
|
||||
if ty == typ {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
if in := typeIn(oAuthFlowTypeImplicit, oAuthFlowAuthorizationCode); true {
|
||||
switch {
|
||||
case flow.AuthorizationURL == "" && in:
|
||||
return errors.New("field 'authorizationUrl' is empty or missing")
|
||||
case flow.AuthorizationURL != "" && !in:
|
||||
return errors.New("field 'authorizationUrl' should not be set")
|
||||
case flow.AuthorizationURL != "":
|
||||
if _, err := url.Parse(flow.AuthorizationURL); err != nil {
|
||||
return fmt.Errorf("field 'authorizationUrl' is invalid: %w", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if in := typeIn(oAuthFlowTypePassword, oAuthFlowTypeClientCredentials, oAuthFlowAuthorizationCode); true {
|
||||
switch {
|
||||
case flow.TokenURL == "" && in:
|
||||
return errors.New("field 'tokenUrl' is empty or missing")
|
||||
case flow.TokenURL != "" && !in:
|
||||
return errors.New("field 'tokenUrl' should not be set")
|
||||
case flow.TokenURL != "":
|
||||
if _, err := url.Parse(flow.TokenURL); err != nil {
|
||||
return fmt.Errorf("field 'tokenUrl' is invalid: %w", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return flow.Validate(ctx, opts...)
|
||||
}
|
||||
|
||||
// UnmarshalJSON sets SecuritySchemes to a copy of data.
|
||||
func (securitySchemes *SecuritySchemes) UnmarshalJSON(data []byte) (err error) {
|
||||
*securitySchemes, _, err = unmarshalStringMapP[SecuritySchemeRef](data)
|
||||
return
|
||||
}
|
||||
|
|
|
|||
182
vendor/github.com/getkin/kin-openapi/openapi3/server.go
generated
vendored
182
vendor/github.com/getkin/kin-openapi/openapi3/server.go
generated
vendored
|
|
@ -2,21 +2,22 @@ package openapi3
|
|||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"net/url"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/getkin/kin-openapi/jsoninfo"
|
||||
)
|
||||
|
||||
// Servers is specified by OpenAPI/Swagger standard version 3.
|
||||
type Servers []*Server
|
||||
|
||||
// Validate ensures servers are per the OpenAPIv3 specification.
|
||||
func (value Servers) Validate(ctx context.Context) error {
|
||||
for _, v := range value {
|
||||
// Validate returns an error if Servers does not comply with the OpenAPI spec.
|
||||
func (servers Servers) Validate(ctx context.Context, opts ...ValidationOption) error {
|
||||
ctx = WithValidationOptions(ctx, opts...)
|
||||
|
||||
for _, v := range servers {
|
||||
if err := v.Validate(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -24,6 +25,14 @@ func (value Servers) Validate(ctx context.Context) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// BasePath returns the base path of the first server in the list, or /.
|
||||
func (servers Servers) BasePath() (string, error) {
|
||||
for _, server := range servers {
|
||||
return server.BasePath()
|
||||
}
|
||||
return "/", nil
|
||||
}
|
||||
|
||||
func (servers Servers) MatchURL(parsedURL *url.URL) (*Server, []string, string) {
|
||||
rawURL := parsedURL.String()
|
||||
if i := strings.IndexByte(rawURL, '?'); i >= 0 {
|
||||
|
|
@ -39,21 +48,82 @@ func (servers Servers) MatchURL(parsedURL *url.URL) (*Server, []string, string)
|
|||
}
|
||||
|
||||
// Server is specified by OpenAPI/Swagger standard version 3.
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#serverObject
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#server-object
|
||||
type Server struct {
|
||||
ExtensionProps
|
||||
Extensions map[string]any `json:"-" yaml:"-"`
|
||||
Origin *Origin `json:"__origin__,omitempty" yaml:"__origin__,omitempty"`
|
||||
|
||||
URL string `json:"url" yaml:"url"`
|
||||
URL string `json:"url" yaml:"url"` // Required
|
||||
Description string `json:"description,omitempty" yaml:"description,omitempty"`
|
||||
Variables map[string]*ServerVariable `json:"variables,omitempty" yaml:"variables,omitempty"`
|
||||
}
|
||||
|
||||
func (server *Server) MarshalJSON() ([]byte, error) {
|
||||
return jsoninfo.MarshalStrictStruct(server)
|
||||
// BasePath returns the base path extracted from the default values of variables, if any.
|
||||
// Assumes a valid struct (per Validate()).
|
||||
func (server *Server) BasePath() (string, error) {
|
||||
if server == nil {
|
||||
return "/", nil
|
||||
}
|
||||
|
||||
uri := server.URL
|
||||
for name, svar := range server.Variables {
|
||||
uri = strings.ReplaceAll(uri, "{"+name+"}", svar.Default)
|
||||
}
|
||||
|
||||
u, err := url.ParseRequestURI(uri)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if bp := u.Path; bp != "" {
|
||||
return bp, nil
|
||||
}
|
||||
|
||||
return "/", nil
|
||||
}
|
||||
|
||||
// MarshalJSON returns the JSON encoding of Server.
|
||||
func (server Server) MarshalJSON() ([]byte, error) {
|
||||
x, err := server.MarshalYAML()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return json.Marshal(x)
|
||||
}
|
||||
|
||||
// MarshalYAML returns the YAML encoding of Server.
|
||||
func (server Server) MarshalYAML() (any, error) {
|
||||
m := make(map[string]any, 3+len(server.Extensions))
|
||||
for k, v := range server.Extensions {
|
||||
m[k] = v
|
||||
}
|
||||
m["url"] = server.URL
|
||||
if x := server.Description; x != "" {
|
||||
m["description"] = x
|
||||
}
|
||||
if x := server.Variables; len(x) != 0 {
|
||||
m["variables"] = x
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON sets Server to a copy of data.
|
||||
func (server *Server) UnmarshalJSON(data []byte) error {
|
||||
return jsoninfo.UnmarshalStrictStruct(data, server)
|
||||
type ServerBis Server
|
||||
var x ServerBis
|
||||
if err := json.Unmarshal(data, &x); err != nil {
|
||||
return unmarshalError(err)
|
||||
}
|
||||
_ = json.Unmarshal(data, &x.Extensions)
|
||||
delete(x.Extensions, originKey)
|
||||
delete(x.Extensions, "url")
|
||||
delete(x.Extensions, "description")
|
||||
delete(x.Extensions, "variables")
|
||||
if len(x.Extensions) == 0 {
|
||||
x.Extensions = nil
|
||||
}
|
||||
*server = Server(x)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (server Server) ParameterNames() ([]string, error) {
|
||||
|
|
@ -103,7 +173,7 @@ func (server Server) MatchRawURL(input string) ([]string, string, bool) {
|
|||
} else if ns < 0 {
|
||||
i = np
|
||||
} else {
|
||||
i = int(math.Min(float64(np), float64(ns)))
|
||||
i = min(np, ns)
|
||||
}
|
||||
if i < 0 {
|
||||
i = len(input)
|
||||
|
|
@ -127,53 +197,109 @@ func (server Server) MatchRawURL(input string) ([]string, string, bool) {
|
|||
return params, input, true
|
||||
}
|
||||
|
||||
func (value *Server) Validate(ctx context.Context) (err error) {
|
||||
if value.URL == "" {
|
||||
// Validate returns an error if Server does not comply with the OpenAPI spec.
|
||||
func (server *Server) Validate(ctx context.Context, opts ...ValidationOption) (err error) {
|
||||
ctx = WithValidationOptions(ctx, opts...)
|
||||
|
||||
if server.URL == "" {
|
||||
return errors.New("value of url must be a non-empty string")
|
||||
}
|
||||
opening, closing := strings.Count(value.URL, "{"), strings.Count(value.URL, "}")
|
||||
|
||||
opening, closing := strings.Count(server.URL, "{"), strings.Count(server.URL, "}")
|
||||
if opening != closing {
|
||||
return errors.New("server URL has mismatched { and }")
|
||||
}
|
||||
if opening != len(value.Variables) {
|
||||
|
||||
if opening != len(server.Variables) {
|
||||
return errors.New("server has undeclared variables")
|
||||
}
|
||||
for name, v := range value.Variables {
|
||||
if !strings.Contains(value.URL, fmt.Sprintf("{%s}", name)) {
|
||||
|
||||
variables := make([]string, 0, len(server.Variables))
|
||||
for name := range server.Variables {
|
||||
variables = append(variables, name)
|
||||
}
|
||||
sort.Strings(variables)
|
||||
for _, name := range variables {
|
||||
v := server.Variables[name]
|
||||
if !strings.Contains(server.URL, "{"+name+"}") {
|
||||
return errors.New("server has undeclared variables")
|
||||
}
|
||||
if err = v.Validate(ctx); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
|
||||
return validateExtensions(ctx, server.Extensions)
|
||||
}
|
||||
|
||||
// ServerVariable is specified by OpenAPI/Swagger standard version 3.
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#server-variable-object
|
||||
type ServerVariable struct {
|
||||
ExtensionProps
|
||||
Extensions map[string]any `json:"-" yaml:"-"`
|
||||
Origin *Origin `json:"__origin__,omitempty" yaml:"__origin__,omitempty"`
|
||||
|
||||
Enum []string `json:"enum,omitempty" yaml:"enum,omitempty"`
|
||||
Default string `json:"default,omitempty" yaml:"default,omitempty"`
|
||||
Description string `json:"description,omitempty" yaml:"description,omitempty"`
|
||||
}
|
||||
|
||||
func (serverVariable *ServerVariable) MarshalJSON() ([]byte, error) {
|
||||
return jsoninfo.MarshalStrictStruct(serverVariable)
|
||||
// MarshalJSON returns the JSON encoding of ServerVariable.
|
||||
func (serverVariable ServerVariable) MarshalJSON() ([]byte, error) {
|
||||
x, err := serverVariable.MarshalYAML()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return json.Marshal(x)
|
||||
}
|
||||
|
||||
// MarshalYAML returns the YAML encoding of ServerVariable.
|
||||
func (serverVariable ServerVariable) MarshalYAML() (any, error) {
|
||||
m := make(map[string]any, 4+len(serverVariable.Extensions))
|
||||
for k, v := range serverVariable.Extensions {
|
||||
m[k] = v
|
||||
}
|
||||
if x := serverVariable.Enum; len(x) != 0 {
|
||||
m["enum"] = x
|
||||
}
|
||||
if x := serverVariable.Default; x != "" {
|
||||
m["default"] = x
|
||||
}
|
||||
if x := serverVariable.Description; x != "" {
|
||||
m["description"] = x
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON sets ServerVariable to a copy of data.
|
||||
func (serverVariable *ServerVariable) UnmarshalJSON(data []byte) error {
|
||||
return jsoninfo.UnmarshalStrictStruct(data, serverVariable)
|
||||
type ServerVariableBis ServerVariable
|
||||
var x ServerVariableBis
|
||||
if err := json.Unmarshal(data, &x); err != nil {
|
||||
return unmarshalError(err)
|
||||
}
|
||||
_ = json.Unmarshal(data, &x.Extensions)
|
||||
delete(x.Extensions, originKey)
|
||||
delete(x.Extensions, "enum")
|
||||
delete(x.Extensions, "default")
|
||||
delete(x.Extensions, "description")
|
||||
if len(x.Extensions) == 0 {
|
||||
x.Extensions = nil
|
||||
}
|
||||
*serverVariable = ServerVariable(x)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (value *ServerVariable) Validate(ctx context.Context) error {
|
||||
if value.Default == "" {
|
||||
data, err := value.MarshalJSON()
|
||||
// Validate returns an error if ServerVariable does not comply with the OpenAPI spec.
|
||||
func (serverVariable *ServerVariable) Validate(ctx context.Context, opts ...ValidationOption) error {
|
||||
ctx = WithValidationOptions(ctx, opts...)
|
||||
|
||||
if serverVariable.Default == "" {
|
||||
data, err := serverVariable.MarshalJSON()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return fmt.Errorf("field default is required in %s", data)
|
||||
}
|
||||
return nil
|
||||
|
||||
return validateExtensions(ctx, serverVariable.Extensions)
|
||||
}
|
||||
|
|
|
|||
88
vendor/github.com/getkin/kin-openapi/openapi3/stringmap.go
generated
vendored
Normal file
88
vendor/github.com/getkin/kin-openapi/openapi3/stringmap.go
generated
vendored
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
package openapi3
|
||||
|
||||
import "encoding/json"
|
||||
|
||||
// StringMap is a map[string]string that ignores the origin in the underlying json representation.
|
||||
type StringMap map[string]string
|
||||
|
||||
// UnmarshalJSON sets StringMap to a copy of data.
|
||||
func (stringMap *StringMap) UnmarshalJSON(data []byte) (err error) {
|
||||
*stringMap, _, err = unmarshalStringMap[string](data)
|
||||
return
|
||||
}
|
||||
|
||||
// unmarshalStringMapP unmarshals given json into a map[string]*V
|
||||
func unmarshalStringMapP[V any](data []byte) (map[string]*V, *Origin, error) {
|
||||
var m map[string]any
|
||||
if err := json.Unmarshal(data, &m); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
origin, err := popOrigin(m, originKey)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
result := make(map[string]*V, len(m))
|
||||
for k, v := range m {
|
||||
value, err := deepCast[V](v)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
result[k] = value
|
||||
}
|
||||
|
||||
return result, origin, nil
|
||||
}
|
||||
|
||||
// unmarshalStringMap unmarshals given json into a map[string]V
|
||||
func unmarshalStringMap[V any](data []byte) (map[string]V, *Origin, error) {
|
||||
var m map[string]any
|
||||
if err := json.Unmarshal(data, &m); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
origin, err := popOrigin(m, originKey)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
result := make(map[string]V, len(m))
|
||||
for k, v := range m {
|
||||
value, err := deepCast[V](v)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
result[k] = *value
|
||||
}
|
||||
|
||||
return result, origin, nil
|
||||
}
|
||||
|
||||
// deepCast casts any value to a value of type V.
|
||||
func deepCast[V any](value any) (*V, error) {
|
||||
data, err := json.Marshal(value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var result V
|
||||
if err = json.Unmarshal(data, &result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &result, nil
|
||||
}
|
||||
|
||||
// popOrigin removes the origin from the map and returns it.
|
||||
func popOrigin(m map[string]any, key string) (*Origin, error) {
|
||||
if !IncludeOrigin {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
origin, err := deepCast[Origin](m[key])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
delete(m, key)
|
||||
return origin, nil
|
||||
}
|
||||
65
vendor/github.com/getkin/kin-openapi/openapi3/tag.go
generated
vendored
65
vendor/github.com/getkin/kin-openapi/openapi3/tag.go
generated
vendored
|
|
@ -2,9 +2,8 @@ package openapi3
|
|||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/getkin/kin-openapi/jsoninfo"
|
||||
)
|
||||
|
||||
// Tags is specified by OpenAPI/Swagger 3.0 standard.
|
||||
|
|
@ -19,7 +18,10 @@ func (tags Tags) Get(name string) *Tag {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (tags Tags) Validate(ctx context.Context) error {
|
||||
// Validate returns an error if Tags does not comply with the OpenAPI spec.
|
||||
func (tags Tags) Validate(ctx context.Context, opts ...ValidationOption) error {
|
||||
ctx = WithValidationOptions(ctx, opts...)
|
||||
|
||||
for _, v := range tags {
|
||||
if err := v.Validate(ctx); err != nil {
|
||||
return err
|
||||
|
|
@ -29,28 +31,71 @@ func (tags Tags) Validate(ctx context.Context) error {
|
|||
}
|
||||
|
||||
// Tag is specified by OpenAPI/Swagger 3.0 standard.
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#tagObject
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#tag-object
|
||||
type Tag struct {
|
||||
ExtensionProps
|
||||
Extensions map[string]any `json:"-" yaml:"-"`
|
||||
Origin *Origin `json:"__origin__,omitempty" yaml:"__origin__,omitempty"`
|
||||
|
||||
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
||||
Description string `json:"description,omitempty" yaml:"description,omitempty"`
|
||||
ExternalDocs *ExternalDocs `json:"externalDocs,omitempty" yaml:"externalDocs,omitempty"`
|
||||
}
|
||||
|
||||
func (t *Tag) MarshalJSON() ([]byte, error) {
|
||||
return jsoninfo.MarshalStrictStruct(t)
|
||||
// MarshalJSON returns the JSON encoding of Tag.
|
||||
func (t Tag) MarshalJSON() ([]byte, error) {
|
||||
x, err := t.MarshalYAML()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return json.Marshal(x)
|
||||
}
|
||||
|
||||
// MarshalYAML returns the YAML encoding of Tag.
|
||||
func (t Tag) MarshalYAML() (any, error) {
|
||||
m := make(map[string]any, 3+len(t.Extensions))
|
||||
for k, v := range t.Extensions {
|
||||
m[k] = v
|
||||
}
|
||||
if x := t.Name; x != "" {
|
||||
m["name"] = x
|
||||
}
|
||||
if x := t.Description; x != "" {
|
||||
m["description"] = x
|
||||
}
|
||||
if x := t.ExternalDocs; x != nil {
|
||||
m["externalDocs"] = x
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON sets Tag to a copy of data.
|
||||
func (t *Tag) UnmarshalJSON(data []byte) error {
|
||||
return jsoninfo.UnmarshalStrictStruct(data, t)
|
||||
type TagBis Tag
|
||||
var x TagBis
|
||||
if err := json.Unmarshal(data, &x); err != nil {
|
||||
return unmarshalError(err)
|
||||
}
|
||||
_ = json.Unmarshal(data, &x.Extensions)
|
||||
delete(x.Extensions, originKey)
|
||||
delete(x.Extensions, "name")
|
||||
delete(x.Extensions, "description")
|
||||
delete(x.Extensions, "externalDocs")
|
||||
if len(x.Extensions) == 0 {
|
||||
x.Extensions = nil
|
||||
}
|
||||
*t = Tag(x)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *Tag) Validate(ctx context.Context) error {
|
||||
// Validate returns an error if Tag does not comply with the OpenAPI spec.
|
||||
func (t *Tag) Validate(ctx context.Context, opts ...ValidationOption) error {
|
||||
ctx = WithValidationOptions(ctx, opts...)
|
||||
|
||||
if v := t.ExternalDocs; v != nil {
|
||||
if err := v.Validate(ctx); err != nil {
|
||||
return fmt.Errorf("invalid external docs: %w", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
||||
return validateExtensions(ctx, t.Extensions)
|
||||
}
|
||||
|
|
|
|||
142
vendor/github.com/getkin/kin-openapi/openapi3/validation_options.go
generated
vendored
Normal file
142
vendor/github.com/getkin/kin-openapi/openapi3/validation_options.go
generated
vendored
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
package openapi3
|
||||
|
||||
import "context"
|
||||
|
||||
// ValidationOption allows the modification of how the OpenAPI document is validated.
|
||||
type ValidationOption func(options *ValidationOptions)
|
||||
|
||||
// ValidationOptions provides configuration for validating OpenAPI documents.
|
||||
type ValidationOptions struct {
|
||||
examplesValidationAsReq, examplesValidationAsRes bool
|
||||
examplesValidationDisabled bool
|
||||
schemaDefaultsValidationDisabled bool
|
||||
schemaFormatValidationEnabled bool
|
||||
schemaPatternValidationDisabled bool
|
||||
schemaExtensionsInRefProhibited bool
|
||||
regexCompilerFunc RegexCompilerFunc
|
||||
extraSiblingFieldsAllowed map[string]struct{}
|
||||
}
|
||||
|
||||
type validationOptionsKey struct{}
|
||||
|
||||
// AllowExtraSiblingFields called as AllowExtraSiblingFields("description") makes Validate not return an error when said field appears next to a $ref.
|
||||
func AllowExtraSiblingFields(fields ...string) ValidationOption {
|
||||
return func(options *ValidationOptions) {
|
||||
if options.extraSiblingFieldsAllowed == nil && len(fields) != 0 {
|
||||
options.extraSiblingFieldsAllowed = make(map[string]struct{}, len(fields))
|
||||
}
|
||||
for _, field := range fields {
|
||||
options.extraSiblingFieldsAllowed[field] = struct{}{}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// EnableSchemaFormatValidation makes Validate not return an error when validating documents that mention schema formats that are not defined by the OpenAPIv3 specification.
|
||||
// By default, schema format validation is disabled.
|
||||
func EnableSchemaFormatValidation() ValidationOption {
|
||||
return func(options *ValidationOptions) {
|
||||
options.schemaFormatValidationEnabled = true
|
||||
}
|
||||
}
|
||||
|
||||
// DisableSchemaFormatValidation does the opposite of EnableSchemaFormatValidation.
|
||||
// By default, schema format validation is disabled.
|
||||
func DisableSchemaFormatValidation() ValidationOption {
|
||||
return func(options *ValidationOptions) {
|
||||
options.schemaFormatValidationEnabled = false
|
||||
}
|
||||
}
|
||||
|
||||
// EnableSchemaPatternValidation does the opposite of DisableSchemaPatternValidation.
|
||||
// By default, schema pattern validation is enabled.
|
||||
func EnableSchemaPatternValidation() ValidationOption {
|
||||
return func(options *ValidationOptions) {
|
||||
options.schemaPatternValidationDisabled = false
|
||||
}
|
||||
}
|
||||
|
||||
// DisableSchemaPatternValidation makes Validate not return an error when validating patterns that are not supported by the Go regexp engine.
|
||||
func DisableSchemaPatternValidation() ValidationOption {
|
||||
return func(options *ValidationOptions) {
|
||||
options.schemaPatternValidationDisabled = true
|
||||
}
|
||||
}
|
||||
|
||||
// EnableSchemaDefaultsValidation does the opposite of DisableSchemaDefaultsValidation.
|
||||
// By default, schema default values are validated against their schema.
|
||||
func EnableSchemaDefaultsValidation() ValidationOption {
|
||||
return func(options *ValidationOptions) {
|
||||
options.schemaDefaultsValidationDisabled = false
|
||||
}
|
||||
}
|
||||
|
||||
// DisableSchemaDefaultsValidation disables schemas' default field validation.
|
||||
// By default, schema default values are validated against their schema.
|
||||
func DisableSchemaDefaultsValidation() ValidationOption {
|
||||
return func(options *ValidationOptions) {
|
||||
options.schemaDefaultsValidationDisabled = true
|
||||
}
|
||||
}
|
||||
|
||||
// EnableExamplesValidation does the opposite of DisableExamplesValidation.
|
||||
// By default, all schema examples are validated.
|
||||
func EnableExamplesValidation() ValidationOption {
|
||||
return func(options *ValidationOptions) {
|
||||
options.examplesValidationDisabled = false
|
||||
}
|
||||
}
|
||||
|
||||
// DisableExamplesValidation disables all example schema validation.
|
||||
// By default, all schema examples are validated.
|
||||
func DisableExamplesValidation() ValidationOption {
|
||||
return func(options *ValidationOptions) {
|
||||
options.examplesValidationDisabled = true
|
||||
}
|
||||
}
|
||||
|
||||
// AllowExtensionsWithRef allows extensions (fields starting with 'x-')
|
||||
// as siblings for $ref fields. This is the default.
|
||||
// Non-extension fields are prohibited unless allowed explicitly with the
|
||||
// AllowExtraSiblingFields option.
|
||||
func AllowExtensionsWithRef() ValidationOption {
|
||||
return func(options *ValidationOptions) {
|
||||
options.schemaExtensionsInRefProhibited = false
|
||||
}
|
||||
}
|
||||
|
||||
// ProhibitExtensionsWithRef causes the validation to return an
|
||||
// error if extensions (fields starting with 'x-') are found as
|
||||
// siblings for $ref fields. Non-extension fields are prohibited
|
||||
// unless allowed explicitly with the AllowExtraSiblingFields option.
|
||||
func ProhibitExtensionsWithRef() ValidationOption {
|
||||
return func(options *ValidationOptions) {
|
||||
options.schemaExtensionsInRefProhibited = true
|
||||
}
|
||||
}
|
||||
|
||||
// SetRegexCompiler allows to override the regex implementation used to validate
|
||||
// field "pattern".
|
||||
func SetRegexCompiler(c RegexCompilerFunc) ValidationOption {
|
||||
return func(options *ValidationOptions) {
|
||||
options.regexCompilerFunc = c
|
||||
}
|
||||
}
|
||||
|
||||
// WithValidationOptions allows adding validation options to a context object that can be used when validating any OpenAPI type.
|
||||
func WithValidationOptions(ctx context.Context, opts ...ValidationOption) context.Context {
|
||||
if len(opts) == 0 {
|
||||
return ctx
|
||||
}
|
||||
options := &ValidationOptions{}
|
||||
for _, opt := range opts {
|
||||
opt(options)
|
||||
}
|
||||
return context.WithValue(ctx, validationOptionsKey{}, options)
|
||||
}
|
||||
|
||||
func getValidationOptions(ctx context.Context) *ValidationOptions {
|
||||
if options, ok := ctx.Value(validationOptionsKey{}).(*ValidationOptions); ok {
|
||||
return options
|
||||
}
|
||||
return &ValidationOptions{}
|
||||
}
|
||||
41
vendor/github.com/getkin/kin-openapi/openapi3/visited.go
generated
vendored
Normal file
41
vendor/github.com/getkin/kin-openapi/openapi3/visited.go
generated
vendored
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
package openapi3
|
||||
|
||||
func newVisited() visitedComponent {
|
||||
return visitedComponent{
|
||||
header: make(map[*Header]struct{}),
|
||||
schema: make(map[*Schema]struct{}),
|
||||
}
|
||||
}
|
||||
|
||||
type visitedComponent struct {
|
||||
header map[*Header]struct{}
|
||||
schema map[*Schema]struct{}
|
||||
}
|
||||
|
||||
// resetVisited clears visitedComponent map
|
||||
// should be called before recursion over doc *T
|
||||
func (doc *T) resetVisited() {
|
||||
doc.visited = newVisited()
|
||||
}
|
||||
|
||||
// isVisitedHeader returns `true` if the *Header pointer was already visited
|
||||
// otherwise it returns `false`
|
||||
func (doc *T) isVisitedHeader(h *Header) bool {
|
||||
if _, ok := doc.visited.header[h]; ok {
|
||||
return true
|
||||
}
|
||||
|
||||
doc.visited.header[h] = struct{}{}
|
||||
return false
|
||||
}
|
||||
|
||||
// isVisitedHeader returns `true` if the *Schema pointer was already visited
|
||||
// otherwise it returns `false`
|
||||
func (doc *T) isVisitedSchema(s *Schema) bool {
|
||||
if _, ok := doc.visited.schema[s]; ok {
|
||||
return true
|
||||
}
|
||||
|
||||
doc.visited.schema[s] = struct{}{}
|
||||
return false
|
||||
}
|
||||
69
vendor/github.com/getkin/kin-openapi/openapi3/xml.go
generated
vendored
69
vendor/github.com/getkin/kin-openapi/openapi3/xml.go
generated
vendored
|
|
@ -2,14 +2,14 @@ package openapi3
|
|||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/getkin/kin-openapi/jsoninfo"
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
// XML is specified by OpenAPI/Swagger standard version 3.
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#xmlObject
|
||||
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#xml-object
|
||||
type XML struct {
|
||||
ExtensionProps
|
||||
Extensions map[string]any `json:"-" yaml:"-"`
|
||||
Origin *Origin `json:"__origin__,omitempty" yaml:"__origin__,omitempty"`
|
||||
|
||||
Name string `json:"name,omitempty" yaml:"name,omitempty"`
|
||||
Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"`
|
||||
|
|
@ -18,14 +18,63 @@ type XML struct {
|
|||
Wrapped bool `json:"wrapped,omitempty" yaml:"wrapped,omitempty"`
|
||||
}
|
||||
|
||||
func (value *XML) MarshalJSON() ([]byte, error) {
|
||||
return jsoninfo.MarshalStrictStruct(value)
|
||||
// MarshalJSON returns the JSON encoding of XML.
|
||||
func (xml XML) MarshalJSON() ([]byte, error) {
|
||||
x, err := xml.MarshalYAML()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return json.Marshal(x)
|
||||
}
|
||||
|
||||
func (value *XML) UnmarshalJSON(data []byte) error {
|
||||
return jsoninfo.UnmarshalStrictStruct(data, value)
|
||||
// MarshalYAML returns the YAML encoding of XML.
|
||||
func (xml XML) MarshalYAML() (any, error) {
|
||||
m := make(map[string]any, 5+len(xml.Extensions))
|
||||
for k, v := range xml.Extensions {
|
||||
m[k] = v
|
||||
}
|
||||
if x := xml.Name; x != "" {
|
||||
m["name"] = x
|
||||
}
|
||||
if x := xml.Namespace; x != "" {
|
||||
m["namespace"] = x
|
||||
}
|
||||
if x := xml.Prefix; x != "" {
|
||||
m["prefix"] = x
|
||||
}
|
||||
if x := xml.Attribute; x {
|
||||
m["attribute"] = x
|
||||
}
|
||||
if x := xml.Wrapped; x {
|
||||
m["wrapped"] = x
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func (value *XML) Validate(ctx context.Context) error {
|
||||
return nil // TODO
|
||||
// UnmarshalJSON sets XML to a copy of data.
|
||||
func (xml *XML) UnmarshalJSON(data []byte) error {
|
||||
type XMLBis XML
|
||||
var x XMLBis
|
||||
if err := json.Unmarshal(data, &x); err != nil {
|
||||
return unmarshalError(err)
|
||||
}
|
||||
_ = json.Unmarshal(data, &x.Extensions)
|
||||
delete(x.Extensions, originKey)
|
||||
delete(x.Extensions, "name")
|
||||
delete(x.Extensions, "namespace")
|
||||
delete(x.Extensions, "prefix")
|
||||
delete(x.Extensions, "attribute")
|
||||
delete(x.Extensions, "wrapped")
|
||||
if len(x.Extensions) == 0 {
|
||||
x.Extensions = nil
|
||||
}
|
||||
*xml = XML(x)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Validate returns an error if XML does not comply with the OpenAPI spec.
|
||||
func (xml *XML) Validate(ctx context.Context, opts ...ValidationOption) error {
|
||||
ctx = WithValidationOptions(ctx, opts...)
|
||||
|
||||
return validateExtensions(ctx, xml.Extensions)
|
||||
}
|
||||
|
|
|
|||
19
vendor/github.com/getkin/kin-openapi/openapi3filter/errors.go
generated
vendored
19
vendor/github.com/getkin/kin-openapi/openapi3filter/errors.go
generated
vendored
|
|
@ -1,6 +1,7 @@
|
|||
package openapi3filter
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
|
||||
"github.com/getkin/kin-openapi/openapi3"
|
||||
|
|
@ -22,7 +23,7 @@ var _ interface{ Unwrap() error } = RequestError{}
|
|||
func (err *RequestError) Error() string {
|
||||
reason := err.Reason
|
||||
if e := err.Err; e != nil {
|
||||
if len(reason) == 0 {
|
||||
if len(reason) == 0 || reason == e.Error() {
|
||||
reason = e.Error()
|
||||
} else {
|
||||
reason += ": " + e.Error()
|
||||
|
|
@ -78,5 +79,19 @@ type SecurityRequirementsError struct {
|
|||
}
|
||||
|
||||
func (err *SecurityRequirementsError) Error() string {
|
||||
return "Security requirements failed"
|
||||
buff := bytes.NewBufferString("security requirements failed: ")
|
||||
for i, e := range err.Errors {
|
||||
buff.WriteString(e.Error())
|
||||
if i != len(err.Errors)-1 {
|
||||
buff.WriteString(" | ")
|
||||
}
|
||||
}
|
||||
|
||||
return buff.String()
|
||||
}
|
||||
|
||||
var _ interface{ Unwrap() []error } = SecurityRequirementsError{}
|
||||
|
||||
func (err SecurityRequirementsError) Unwrap() []error {
|
||||
return err.Errors
|
||||
}
|
||||
|
|
|
|||
2
vendor/github.com/getkin/kin-openapi/openapi3filter/internal.go
generated
vendored
2
vendor/github.com/getkin/kin-openapi/openapi3filter/internal.go
generated
vendored
|
|
@ -13,7 +13,7 @@ func parseMediaType(contentType string) string {
|
|||
return contentType[:i]
|
||||
}
|
||||
|
||||
func isNilValue(value interface{}) bool {
|
||||
func isNilValue(value any) bool {
|
||||
if value == nil {
|
||||
return true
|
||||
}
|
||||
|
|
|
|||
43
vendor/github.com/getkin/kin-openapi/openapi3filter/middleware.go
generated
vendored
43
vendor/github.com/getkin/kin-openapi/openapi3filter/middleware.go
generated
vendored
|
|
@ -2,8 +2,8 @@ package openapi3filter
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
|
|
@ -16,13 +16,14 @@ type Validator struct {
|
|||
errFunc ErrFunc
|
||||
logFunc LogFunc
|
||||
strict bool
|
||||
options Options
|
||||
}
|
||||
|
||||
// ErrFunc handles errors that may occur during validation.
|
||||
type ErrFunc func(w http.ResponseWriter, status int, code ErrCode, err error)
|
||||
type ErrFunc func(ctx context.Context, w http.ResponseWriter, status int, code ErrCode, err error)
|
||||
|
||||
// LogFunc handles log messages that may occur during validation.
|
||||
type LogFunc func(message string, err error)
|
||||
type LogFunc func(ctx context.Context, message string, err error)
|
||||
|
||||
// ErrCode is used for classification of different types of errors that may
|
||||
// occur during validation. These may be used to write an appropriate response
|
||||
|
|
@ -56,15 +57,15 @@ func (e ErrCode) responseText() string {
|
|||
}
|
||||
}
|
||||
|
||||
// NewValidator returns a new response validation middlware, using the given
|
||||
// NewValidator returns a new response validation middleware, using the given
|
||||
// routes from an OpenAPI 3 specification.
|
||||
func NewValidator(router routers.Router, options ...ValidatorOption) *Validator {
|
||||
v := &Validator{
|
||||
router: router,
|
||||
errFunc: func(w http.ResponseWriter, status int, code ErrCode, _ error) {
|
||||
errFunc: func(_ context.Context, w http.ResponseWriter, status int, code ErrCode, _ error) {
|
||||
http.Error(w, code.responseText(), status)
|
||||
},
|
||||
logFunc: func(message string, err error) {
|
||||
logFunc: func(_ context.Context, message string, err error) {
|
||||
log.Printf("%s: %v", message, err)
|
||||
},
|
||||
}
|
||||
|
|
@ -106,24 +107,33 @@ func Strict(strict bool) ValidatorOption {
|
|||
}
|
||||
}
|
||||
|
||||
// ValidationOptions sets request/response validation options on the validator.
|
||||
func ValidationOptions(options Options) ValidatorOption {
|
||||
return func(v *Validator) {
|
||||
v.options = options
|
||||
}
|
||||
}
|
||||
|
||||
// Middleware returns an http.Handler which wraps the given handler with
|
||||
// request and response validation.
|
||||
func (v *Validator) Middleware(h http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
route, pathParams, err := v.router.FindRoute(r)
|
||||
if err != nil {
|
||||
v.logFunc("validation error: failed to find route for "+r.URL.String(), err)
|
||||
v.errFunc(w, http.StatusNotFound, ErrCodeCannotFindRoute, err)
|
||||
v.logFunc(ctx, "validation error: failed to find route for "+r.URL.String(), err)
|
||||
v.errFunc(ctx, w, http.StatusNotFound, ErrCodeCannotFindRoute, err)
|
||||
return
|
||||
}
|
||||
requestValidationInput := &RequestValidationInput{
|
||||
Request: r,
|
||||
PathParams: pathParams,
|
||||
Route: route,
|
||||
Options: &v.options,
|
||||
}
|
||||
if err = ValidateRequest(r.Context(), requestValidationInput); err != nil {
|
||||
v.logFunc("invalid request", err)
|
||||
v.errFunc(w, http.StatusBadRequest, ErrCodeRequestInvalid, err)
|
||||
if err = ValidateRequest(ctx, requestValidationInput); err != nil {
|
||||
v.logFunc(ctx, "invalid request", err)
|
||||
v.errFunc(ctx, w, http.StatusBadRequest, ErrCodeRequestInvalid, err)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -136,21 +146,22 @@ func (v *Validator) Middleware(h http.Handler) http.Handler {
|
|||
|
||||
h.ServeHTTP(wr, r)
|
||||
|
||||
if err = ValidateResponse(r.Context(), &ResponseValidationInput{
|
||||
if err = ValidateResponse(ctx, &ResponseValidationInput{
|
||||
RequestValidationInput: requestValidationInput,
|
||||
Status: wr.statusCode(),
|
||||
Header: wr.Header(),
|
||||
Body: ioutil.NopCloser(bytes.NewBuffer(wr.bodyContents())),
|
||||
Body: io.NopCloser(bytes.NewBuffer(wr.bodyContents())),
|
||||
Options: &v.options,
|
||||
}); err != nil {
|
||||
v.logFunc("invalid response", err)
|
||||
v.logFunc(ctx, "invalid response", err)
|
||||
if v.strict {
|
||||
v.errFunc(w, http.StatusInternalServerError, ErrCodeResponseInvalid, err)
|
||||
v.errFunc(ctx, w, http.StatusInternalServerError, ErrCodeResponseInvalid, err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if err = wr.flushBodyContents(); err != nil {
|
||||
v.logFunc("failed to write response", err)
|
||||
v.logFunc(ctx, "failed to write response", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
|||
34
vendor/github.com/getkin/kin-openapi/openapi3filter/options.go
generated
vendored
34
vendor/github.com/getkin/kin-openapi/openapi3filter/options.go
generated
vendored
|
|
@ -1,24 +1,50 @@
|
|||
package openapi3filter
|
||||
|
||||
// DefaultOptions do not set an AuthenticationFunc.
|
||||
// A spec with security schemes defined will not pass validation
|
||||
// unless an AuthenticationFunc is defined.
|
||||
var DefaultOptions = &Options{}
|
||||
import "github.com/getkin/kin-openapi/openapi3"
|
||||
|
||||
// Options used by ValidateRequest and ValidateResponse
|
||||
type Options struct {
|
||||
// Set ExcludeRequestBody so ValidateRequest skips request body validation
|
||||
ExcludeRequestBody bool
|
||||
|
||||
// Set ExcludeRequestQueryParams so ValidateRequest skips request query params validation
|
||||
ExcludeRequestQueryParams bool
|
||||
|
||||
// Set ExcludeResponseBody so ValidateResponse skips response body validation
|
||||
ExcludeResponseBody bool
|
||||
|
||||
// Set ExcludeReadOnlyValidations so ValidateRequest skips read-only validations
|
||||
ExcludeReadOnlyValidations bool
|
||||
|
||||
// Set ExcludeWriteOnlyValidations so ValidateResponse skips write-only validations
|
||||
ExcludeWriteOnlyValidations bool
|
||||
|
||||
// Set IncludeResponseStatus so ValidateResponse fails on response
|
||||
// status not defined in OpenAPI spec
|
||||
IncludeResponseStatus bool
|
||||
|
||||
MultiError bool
|
||||
|
||||
// Set RegexCompiler to override the regex implementation
|
||||
RegexCompiler openapi3.RegexCompilerFunc
|
||||
|
||||
// A document with security schemes defined will not pass validation
|
||||
// unless an AuthenticationFunc is defined.
|
||||
// See NoopAuthenticationFunc
|
||||
AuthenticationFunc AuthenticationFunc
|
||||
|
||||
// Indicates whether default values are set in the
|
||||
// request. If true, then they are not set
|
||||
SkipSettingDefaults bool
|
||||
|
||||
customSchemaErrorFunc CustomSchemaErrorFunc
|
||||
}
|
||||
|
||||
// CustomSchemaErrorFunc allows for custom the schema error message.
|
||||
type CustomSchemaErrorFunc func(err *openapi3.SchemaError) string
|
||||
|
||||
// WithCustomSchemaErrorFunc sets a function to override the schema error message.
|
||||
// If the passed function returns an empty string, it returns to the previous Error() implementation.
|
||||
func (o *Options) WithCustomSchemaErrorFunc(f CustomSchemaErrorFunc) {
|
||||
o.customSchemaErrorFunc = f
|
||||
}
|
||||
|
|
|
|||
834
vendor/github.com/getkin/kin-openapi/openapi3filter/req_resp_decoder.go
generated
vendored
834
vendor/github.com/getkin/kin-openapi/openapi3filter/req_resp_decoder.go
generated
vendored
File diff suppressed because it is too large
Load diff
58
vendor/github.com/getkin/kin-openapi/openapi3filter/req_resp_encoder.go
generated
vendored
Normal file
58
vendor/github.com/getkin/kin-openapi/openapi3filter/req_resp_encoder.go
generated
vendored
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
package openapi3filter
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"sync"
|
||||
)
|
||||
|
||||
func encodeBody(body any, mediaType string) ([]byte, error) {
|
||||
if encoder := RegisteredBodyEncoder(mediaType); encoder != nil {
|
||||
return encoder(body)
|
||||
}
|
||||
return nil, &ParseError{
|
||||
Kind: KindUnsupportedFormat,
|
||||
Reason: fmt.Sprintf("%s %q", prefixUnsupportedCT, mediaType),
|
||||
}
|
||||
}
|
||||
|
||||
// BodyEncoder really is an (encoding/json).Marshaler
|
||||
type BodyEncoder func(body any) ([]byte, error)
|
||||
|
||||
var bodyEncodersM sync.RWMutex
|
||||
var bodyEncoders = map[string]BodyEncoder{
|
||||
"application/json": json.Marshal,
|
||||
}
|
||||
|
||||
// RegisterBodyEncoder enables package-wide decoding of contentType values
|
||||
func RegisterBodyEncoder(contentType string, encoder BodyEncoder) {
|
||||
if contentType == "" {
|
||||
panic("contentType is empty")
|
||||
}
|
||||
if encoder == nil {
|
||||
panic("encoder is not defined")
|
||||
}
|
||||
bodyEncodersM.Lock()
|
||||
bodyEncoders[contentType] = encoder
|
||||
bodyEncodersM.Unlock()
|
||||
}
|
||||
|
||||
// UnregisterBodyEncoder disables package-wide decoding of contentType values
|
||||
func UnregisterBodyEncoder(contentType string) {
|
||||
if contentType == "" {
|
||||
panic("contentType is empty")
|
||||
}
|
||||
bodyEncodersM.Lock()
|
||||
delete(bodyEncoders, contentType)
|
||||
bodyEncodersM.Unlock()
|
||||
}
|
||||
|
||||
// RegisteredBodyEncoder returns the registered body encoder for the given content type.
|
||||
//
|
||||
// If no encoder was registered for the given content type, nil is returned.
|
||||
func RegisteredBodyEncoder(contentType string) BodyEncoder {
|
||||
bodyEncodersM.RLock()
|
||||
mayBE := bodyEncoders[contentType]
|
||||
bodyEncodersM.RUnlock()
|
||||
return mayBE
|
||||
}
|
||||
190
vendor/github.com/getkin/kin-openapi/openapi3filter/validate_request.go
generated
vendored
190
vendor/github.com/getkin/kin-openapi/openapi3filter/validate_request.go
generated
vendored
|
|
@ -5,9 +5,11 @@ import (
|
|||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/getkin/kin-openapi/openapi3"
|
||||
)
|
||||
|
|
@ -29,14 +31,11 @@ var ErrInvalidEmptyValue = errors.New("empty value is not allowed")
|
|||
// Note: One can tune the behavior of uniqueItems: true verification
|
||||
// by registering a custom function with openapi3.RegisterArrayUniqueItemsChecker
|
||||
func ValidateRequest(ctx context.Context, input *RequestValidationInput) error {
|
||||
var (
|
||||
err error
|
||||
me openapi3.MultiError
|
||||
)
|
||||
var me openapi3.MultiError
|
||||
|
||||
options := input.Options
|
||||
if options == nil {
|
||||
options = DefaultOptions
|
||||
options = &Options{}
|
||||
}
|
||||
route := input.Route
|
||||
operation := route.Operation
|
||||
|
|
@ -51,11 +50,10 @@ func ValidateRequest(ctx context.Context, input *RequestValidationInput) error {
|
|||
security = &route.Spec.Security
|
||||
}
|
||||
if security != nil {
|
||||
if err = ValidateSecurityRequirements(ctx, input, *security); err != nil && !options.MultiError {
|
||||
return err
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
if err := ValidateSecurityRequirements(ctx, input, *security); err != nil {
|
||||
if !options.MultiError {
|
||||
return err
|
||||
}
|
||||
me = append(me, err)
|
||||
}
|
||||
}
|
||||
|
|
@ -69,22 +67,23 @@ func ValidateRequest(ctx context.Context, input *RequestValidationInput) error {
|
|||
}
|
||||
}
|
||||
|
||||
if err = ValidateParameter(ctx, input, parameter); err != nil && !options.MultiError {
|
||||
return err
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
if err := ValidateParameter(ctx, input, parameter); err != nil {
|
||||
if !options.MultiError {
|
||||
return err
|
||||
}
|
||||
me = append(me, err)
|
||||
}
|
||||
}
|
||||
|
||||
// For each parameter of the Operation
|
||||
for _, parameter := range operationParameters {
|
||||
if err = ValidateParameter(ctx, input, parameter.Value); err != nil && !options.MultiError {
|
||||
return err
|
||||
if options.ExcludeRequestQueryParams && parameter.Value.In == openapi3.ParameterInQuery {
|
||||
continue
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
if err := ValidateParameter(ctx, input, parameter.Value); err != nil {
|
||||
if !options.MultiError {
|
||||
return err
|
||||
}
|
||||
me = append(me, err)
|
||||
}
|
||||
}
|
||||
|
|
@ -92,11 +91,10 @@ func ValidateRequest(ctx context.Context, input *RequestValidationInput) error {
|
|||
// RequestBody
|
||||
requestBody := operation.RequestBody
|
||||
if requestBody != nil && !options.ExcludeRequestBody {
|
||||
if err = ValidateRequestBody(ctx, input, requestBody.Value); err != nil && !options.MultiError {
|
||||
return err
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
if err := ValidateRequestBody(ctx, input, requestBody.Value); err != nil {
|
||||
if !options.MultiError {
|
||||
return err
|
||||
}
|
||||
me = append(me, err)
|
||||
}
|
||||
}
|
||||
|
|
@ -104,10 +102,38 @@ func ValidateRequest(ctx context.Context, input *RequestValidationInput) error {
|
|||
if len(me) > 0 {
|
||||
return me
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// appendToQueryValues adds to query parameters each value in the provided slice
|
||||
func appendToQueryValues[T any](q url.Values, parameterName string, v []T) {
|
||||
for _, i := range v {
|
||||
q.Add(parameterName, fmt.Sprintf("%v", i))
|
||||
}
|
||||
}
|
||||
|
||||
func joinValues(values []any, sep string) string {
|
||||
strValues := make([]string, 0, len(values))
|
||||
for _, v := range values {
|
||||
strValues = append(strValues, fmt.Sprintf("%v", v))
|
||||
}
|
||||
return strings.Join(strValues, sep)
|
||||
}
|
||||
|
||||
// populateDefaultQueryParameters populates default values inside query parameters, while ensuring types are respected
|
||||
func populateDefaultQueryParameters(q url.Values, parameterName string, value any, explode bool) {
|
||||
switch t := value.(type) {
|
||||
case []any:
|
||||
if explode {
|
||||
appendToQueryValues(q, parameterName, t)
|
||||
} else {
|
||||
q.Add(parameterName, joinValues(t, ","))
|
||||
}
|
||||
default:
|
||||
q.Add(parameterName, fmt.Sprintf("%v", value))
|
||||
}
|
||||
}
|
||||
|
||||
// ValidateParameter validates a parameter's value by JSON schema.
|
||||
// The function returns RequestError with a ParseError cause when unable to parse a value.
|
||||
// The function returns RequestError with ErrInvalidRequired cause when a value of a required parameter is not defined.
|
||||
|
|
@ -123,10 +149,10 @@ func ValidateParameter(ctx context.Context, input *RequestValidationInput, param
|
|||
|
||||
options := input.Options
|
||||
if options == nil {
|
||||
options = DefaultOptions
|
||||
options = &Options{}
|
||||
}
|
||||
|
||||
var value interface{}
|
||||
var value any
|
||||
var err error
|
||||
var found bool
|
||||
var schema *openapi3.Schema
|
||||
|
|
@ -142,6 +168,39 @@ func ValidateParameter(ctx context.Context, input *RequestValidationInput, param
|
|||
}
|
||||
schema = parameter.Schema.Value
|
||||
}
|
||||
|
||||
// Set default value if needed
|
||||
if !options.SkipSettingDefaults && value == nil && schema != nil {
|
||||
value = schema.Default
|
||||
for _, subSchema := range schema.AllOf {
|
||||
if subSchema.Value.Default != nil {
|
||||
value = subSchema.Value.Default
|
||||
break // This is not a validation of the schema itself, so use the first default value.
|
||||
}
|
||||
}
|
||||
|
||||
if value != nil {
|
||||
req := input.Request
|
||||
switch parameter.In {
|
||||
case openapi3.ParameterInPath:
|
||||
// Path parameters are required.
|
||||
// Next check `parameter.Required && !found` will catch this.
|
||||
case openapi3.ParameterInQuery:
|
||||
q := req.URL.Query()
|
||||
explode := parameter.Explode != nil && *parameter.Explode
|
||||
populateDefaultQueryParameters(q, parameter.Name, value, explode)
|
||||
req.URL.RawQuery = q.Encode()
|
||||
case openapi3.ParameterInHeader:
|
||||
req.Header.Add(parameter.Name, fmt.Sprintf("%v", value))
|
||||
case openapi3.ParameterInCookie:
|
||||
req.AddCookie(&http.Cookie{
|
||||
Name: parameter.Name,
|
||||
Value: fmt.Sprintf("%v", value),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Validate a parameter's value and presence.
|
||||
if parameter.Required && !found {
|
||||
return &RequestError{Input: input, Parameter: parameter, Reason: ErrInvalidRequired.Error(), Err: ErrInvalidRequired}
|
||||
|
|
@ -163,6 +222,9 @@ func ValidateParameter(ctx context.Context, input *RequestValidationInput, param
|
|||
opts = make([]openapi3.SchemaValidationOption, 0, 1)
|
||||
opts = append(opts, openapi3.MultiErrors())
|
||||
}
|
||||
if options.customSchemaErrorFunc != nil {
|
||||
opts = append(opts, openapi3.SetSchemaErrorMessageCustomizer(options.customSchemaErrorFunc))
|
||||
}
|
||||
if err = schema.VisitJSON(value, opts...); err != nil {
|
||||
return &RequestError{Input: input, Parameter: parameter, Err: err}
|
||||
}
|
||||
|
|
@ -183,13 +245,13 @@ func ValidateRequestBody(ctx context.Context, input *RequestValidationInput, req
|
|||
|
||||
options := input.Options
|
||||
if options == nil {
|
||||
options = DefaultOptions
|
||||
options = &Options{}
|
||||
}
|
||||
|
||||
if req.Body != http.NoBody && req.Body != nil {
|
||||
defer req.Body.Close()
|
||||
var err error
|
||||
if data, err = ioutil.ReadAll(req.Body); err != nil {
|
||||
if data, err = io.ReadAll(req.Body); err != nil {
|
||||
return &RequestError{
|
||||
Input: input,
|
||||
RequestBody: requestBody,
|
||||
|
|
@ -198,7 +260,19 @@ func ValidateRequestBody(ctx context.Context, input *RequestValidationInput, req
|
|||
}
|
||||
}
|
||||
// Put the data back into the input
|
||||
req.Body = ioutil.NopCloser(bytes.NewReader(data))
|
||||
req.Body = nil
|
||||
if req.GetBody != nil {
|
||||
if req.Body, err = req.GetBody(); err != nil {
|
||||
req.Body = nil
|
||||
}
|
||||
}
|
||||
if req.Body == nil {
|
||||
req.ContentLength = int64(len(data))
|
||||
req.GetBody = func() (io.ReadCloser, error) {
|
||||
return io.NopCloser(bytes.NewReader(data)), nil
|
||||
}
|
||||
req.Body, _ = req.GetBody() // no error return
|
||||
}
|
||||
}
|
||||
|
||||
if len(data) == 0 {
|
||||
|
|
@ -230,7 +304,7 @@ func ValidateRequestBody(ctx context.Context, input *RequestValidationInput, req
|
|||
}
|
||||
|
||||
encFn := func(name string) *openapi3.Encoding { return contentType.Encoding[name] }
|
||||
value, err := decodeBody(bytes.NewReader(data), req.Header, contentType.Schema, encFn)
|
||||
mediaType, value, err := decodeBody(bytes.NewReader(data), req.Header, contentType.Schema, encFn)
|
||||
if err != nil {
|
||||
return &RequestError{
|
||||
Input: input,
|
||||
|
|
@ -240,21 +314,58 @@ func ValidateRequestBody(ctx context.Context, input *RequestValidationInput, req
|
|||
}
|
||||
}
|
||||
|
||||
opts := make([]openapi3.SchemaValidationOption, 0, 2) // 2 potential opts here
|
||||
defaultsSet := false
|
||||
opts := make([]openapi3.SchemaValidationOption, 0, 4) // 4 potential opts here
|
||||
opts = append(opts, openapi3.VisitAsRequest())
|
||||
if !options.SkipSettingDefaults {
|
||||
opts = append(opts, openapi3.DefaultsSet(func() { defaultsSet = true }))
|
||||
}
|
||||
if options.MultiError {
|
||||
opts = append(opts, openapi3.MultiErrors())
|
||||
}
|
||||
if options.customSchemaErrorFunc != nil {
|
||||
opts = append(opts, openapi3.SetSchemaErrorMessageCustomizer(options.customSchemaErrorFunc))
|
||||
}
|
||||
if options.ExcludeReadOnlyValidations {
|
||||
opts = append(opts, openapi3.DisableReadOnlyValidation())
|
||||
}
|
||||
if options.RegexCompiler != nil {
|
||||
opts = append(opts, openapi3.SetSchemaRegexCompiler(options.RegexCompiler))
|
||||
}
|
||||
|
||||
// Validate JSON with the schema
|
||||
if err := contentType.Schema.Value.VisitJSON(value, opts...); err != nil {
|
||||
schemaId := getSchemaIdentifier(contentType.Schema)
|
||||
schemaId = prependSpaceIfNeeded(schemaId)
|
||||
return &RequestError{
|
||||
Input: input,
|
||||
RequestBody: requestBody,
|
||||
Reason: "doesn't match the schema",
|
||||
Reason: fmt.Sprintf("doesn't match schema%s", schemaId),
|
||||
Err: err,
|
||||
}
|
||||
}
|
||||
|
||||
if defaultsSet {
|
||||
var err error
|
||||
if data, err = encodeBody(value, mediaType); err != nil {
|
||||
return &RequestError{
|
||||
Input: input,
|
||||
RequestBody: requestBody,
|
||||
Reason: "rewriting failed",
|
||||
Err: err,
|
||||
}
|
||||
}
|
||||
// Put the data back into the input
|
||||
if req.Body != nil {
|
||||
req.Body.Close()
|
||||
}
|
||||
req.ContentLength = int64(len(data))
|
||||
req.GetBody = func() (io.ReadCloser, error) {
|
||||
return io.NopCloser(bytes.NewReader(data)), nil
|
||||
}
|
||||
req.Body, _ = req.GetBody() // no error return
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -284,10 +395,6 @@ func ValidateSecurityRequirements(ctx context.Context, input *RequestValidationI
|
|||
|
||||
// validateSecurityRequirement validates a single OpenAPI 3 security requirement
|
||||
func validateSecurityRequirement(ctx context.Context, input *RequestValidationInput, securityRequirement openapi3.SecurityRequirement) error {
|
||||
doc := input.Route.Spec
|
||||
securitySchemes := doc.Components.SecuritySchemes
|
||||
|
||||
// Ensure deterministic order
|
||||
names := make([]string, 0, len(securityRequirement))
|
||||
for name := range securityRequirement {
|
||||
names = append(names, name)
|
||||
|
|
@ -297,13 +404,18 @@ func validateSecurityRequirement(ctx context.Context, input *RequestValidationIn
|
|||
// Get authentication function
|
||||
options := input.Options
|
||||
if options == nil {
|
||||
options = DefaultOptions
|
||||
options = &Options{}
|
||||
}
|
||||
f := options.AuthenticationFunc
|
||||
if f == nil {
|
||||
return ErrAuthenticationServiceMissing
|
||||
}
|
||||
|
||||
var securitySchemes openapi3.SecuritySchemes
|
||||
if components := input.Route.Spec.Components; components != nil {
|
||||
securitySchemes = components.SecuritySchemes
|
||||
}
|
||||
|
||||
// For each scheme for the requirement
|
||||
for _, name := range names {
|
||||
var securityScheme *openapi3.SecurityScheme
|
||||
|
|
|
|||
2
vendor/github.com/getkin/kin-openapi/openapi3filter/validate_request_input.go
generated
vendored
2
vendor/github.com/getkin/kin-openapi/openapi3filter/validate_request_input.go
generated
vendored
|
|
@ -17,7 +17,7 @@ import (
|
|||
// If a query parameter appears multiple times, values[] will have more
|
||||
// than one value, but for all other parameter types it should have just
|
||||
// one.
|
||||
type ContentParameterDecoder func(param *openapi3.Parameter, values []string) (interface{}, *openapi3.Schema, error)
|
||||
type ContentParameterDecoder func(param *openapi3.Parameter, values []string) (any, *openapi3.Schema, error)
|
||||
|
||||
type RequestValidationInput struct {
|
||||
Request *http.Request
|
||||
|
|
|
|||
118
vendor/github.com/getkin/kin-openapi/openapi3filter/validate_response.go
generated
vendored
118
vendor/github.com/getkin/kin-openapi/openapi3filter/validate_response.go
generated
vendored
|
|
@ -5,8 +5,10 @@ import (
|
|||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"net/http"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/getkin/kin-openapi/openapi3"
|
||||
)
|
||||
|
|
@ -37,15 +39,15 @@ func ValidateResponse(ctx context.Context, input *ResponseValidationInput) error
|
|||
route := input.RequestValidationInput.Route
|
||||
options := input.Options
|
||||
if options == nil {
|
||||
options = DefaultOptions
|
||||
options = &Options{}
|
||||
}
|
||||
|
||||
// Find input for the current status
|
||||
responses := route.Operation.Responses
|
||||
if len(responses) == 0 {
|
||||
if responses.Len() == 0 {
|
||||
return nil
|
||||
}
|
||||
responseRef := responses.Get(status) // Response
|
||||
responseRef := responses.Status(status) // Response
|
||||
if responseRef == nil {
|
||||
responseRef = responses.Default() // Default input
|
||||
}
|
||||
|
|
@ -61,13 +63,38 @@ func ValidateResponse(ctx context.Context, input *ResponseValidationInput) error
|
|||
return &ResponseError{Input: input, Reason: "response has not been resolved"}
|
||||
}
|
||||
|
||||
opts := make([]openapi3.SchemaValidationOption, 0, 3) // 3 potential options here
|
||||
if options.MultiError {
|
||||
opts = append(opts, openapi3.MultiErrors())
|
||||
}
|
||||
if options.customSchemaErrorFunc != nil {
|
||||
opts = append(opts, openapi3.SetSchemaErrorMessageCustomizer(options.customSchemaErrorFunc))
|
||||
}
|
||||
if options.ExcludeWriteOnlyValidations {
|
||||
opts = append(opts, openapi3.DisableWriteOnlyValidation())
|
||||
}
|
||||
|
||||
headers := make([]string, 0, len(response.Headers))
|
||||
for k := range response.Headers {
|
||||
if k != headerCT {
|
||||
headers = append(headers, k)
|
||||
}
|
||||
}
|
||||
sort.Strings(headers)
|
||||
for _, headerName := range headers {
|
||||
headerRef := response.Headers[headerName]
|
||||
if err := validateResponseHeader(headerName, headerRef, input, opts); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if options.ExcludeResponseBody {
|
||||
// A user turned off validation of a response's body.
|
||||
return nil
|
||||
}
|
||||
|
||||
content := response.Content
|
||||
if len(content) == 0 || options.ExcludeResponseBody {
|
||||
if len(content) == 0 {
|
||||
// An operation does not contains a validation schema for responses with this status code.
|
||||
return nil
|
||||
}
|
||||
|
|
@ -77,7 +104,7 @@ func ValidateResponse(ctx context.Context, input *ResponseValidationInput) error
|
|||
if contentType == nil {
|
||||
return &ResponseError{
|
||||
Input: input,
|
||||
Reason: fmt.Sprintf("response header Content-Type has unexpected value: %q", inputMIME),
|
||||
Reason: fmt.Sprintf("response %s: %q", prefixInvalidCT, inputMIME),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -98,7 +125,7 @@ func ValidateResponse(ctx context.Context, input *ResponseValidationInput) error
|
|||
defer body.Close()
|
||||
|
||||
// Read all
|
||||
data, err := ioutil.ReadAll(body)
|
||||
data, err := io.ReadAll(body)
|
||||
if err != nil {
|
||||
return &ResponseError{
|
||||
Input: input,
|
||||
|
|
@ -111,7 +138,7 @@ func ValidateResponse(ctx context.Context, input *ResponseValidationInput) error
|
|||
input.SetBodyBytes(data)
|
||||
|
||||
encFn := func(name string) *openapi3.Encoding { return contentType.Encoding[name] }
|
||||
value, err := decodeBody(bytes.NewBuffer(data), input.Header, contentType.Schema, encFn)
|
||||
_, value, err := decodeBody(bytes.NewBuffer(data), input.Header, contentType.Schema, encFn)
|
||||
if err != nil {
|
||||
return &ResponseError{
|
||||
Input: input,
|
||||
|
|
@ -120,19 +147,78 @@ func ValidateResponse(ctx context.Context, input *ResponseValidationInput) error
|
|||
}
|
||||
}
|
||||
|
||||
opts := make([]openapi3.SchemaValidationOption, 0, 2) // 2 potential opts here
|
||||
opts = append(opts, openapi3.VisitAsRequest())
|
||||
if options.MultiError {
|
||||
opts = append(opts, openapi3.MultiErrors())
|
||||
}
|
||||
|
||||
// Validate data with the schema.
|
||||
if err := contentType.Schema.Value.VisitJSON(value, opts...); err != nil {
|
||||
if err := contentType.Schema.Value.VisitJSON(value, append(opts, openapi3.VisitAsResponse())...); err != nil {
|
||||
schemaId := getSchemaIdentifier(contentType.Schema)
|
||||
schemaId = prependSpaceIfNeeded(schemaId)
|
||||
return &ResponseError{
|
||||
Input: input,
|
||||
Reason: "response body doesn't match the schema",
|
||||
Reason: fmt.Sprintf("response body doesn't match schema%s", schemaId),
|
||||
Err: err,
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateResponseHeader(headerName string, headerRef *openapi3.HeaderRef, input *ResponseValidationInput, opts []openapi3.SchemaValidationOption) error {
|
||||
var err error
|
||||
var decodedValue any
|
||||
var found bool
|
||||
var sm *openapi3.SerializationMethod
|
||||
dec := &headerParamDecoder{header: input.Header}
|
||||
|
||||
if sm, err = headerRef.Value.SerializationMethod(); err != nil {
|
||||
return &ResponseError{
|
||||
Input: input,
|
||||
Reason: fmt.Sprintf("unable to get header %q serialization method", headerName),
|
||||
Err: err,
|
||||
}
|
||||
}
|
||||
|
||||
if decodedValue, found, err = decodeValue(dec, headerName, sm, headerRef.Value.Schema, headerRef.Value.Required); err != nil {
|
||||
return &ResponseError{
|
||||
Input: input,
|
||||
Reason: fmt.Sprintf("unable to decode header %q value", headerName),
|
||||
Err: err,
|
||||
}
|
||||
}
|
||||
|
||||
if found {
|
||||
if err = headerRef.Value.Schema.Value.VisitJSON(decodedValue, opts...); err != nil {
|
||||
return &ResponseError{
|
||||
Input: input,
|
||||
Reason: fmt.Sprintf("response header %q doesn't match schema", headerName),
|
||||
Err: err,
|
||||
}
|
||||
}
|
||||
} else if headerRef.Value.Required {
|
||||
return &ResponseError{
|
||||
Input: input,
|
||||
Reason: fmt.Sprintf("response header %q missing", headerName),
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// getSchemaIdentifier gets something by which a schema could be identified.
|
||||
// A schema by itself doesn't have a true identity field. This function makes
|
||||
// a best effort to get a value that can fill that void.
|
||||
func getSchemaIdentifier(schema *openapi3.SchemaRef) string {
|
||||
var id string
|
||||
|
||||
if schema != nil {
|
||||
id = strings.TrimSpace(schema.Ref)
|
||||
}
|
||||
if id == "" && schema.Value != nil {
|
||||
id = strings.TrimSpace(schema.Value.Title)
|
||||
}
|
||||
|
||||
return id
|
||||
}
|
||||
|
||||
func prependSpaceIfNeeded(value string) string {
|
||||
if len(value) > 0 {
|
||||
value = " " + value
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
|
|
|||
3
vendor/github.com/getkin/kin-openapi/openapi3filter/validate_response_input.go
generated
vendored
3
vendor/github.com/getkin/kin-openapi/openapi3filter/validate_response_input.go
generated
vendored
|
|
@ -3,7 +3,6 @@ package openapi3filter
|
|||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
|
|
@ -16,7 +15,7 @@ type ResponseValidationInput struct {
|
|||
}
|
||||
|
||||
func (input *ResponseValidationInput) SetBodyBytes(value []byte) *ResponseValidationInput {
|
||||
input.Body = ioutil.NopCloser(bytes.NewReader(value))
|
||||
input.Body = io.NopCloser(bytes.NewReader(value))
|
||||
return input
|
||||
}
|
||||
|
||||
|
|
|
|||
3
vendor/github.com/getkin/kin-openapi/openapi3filter/validation_error.go
generated
vendored
3
vendor/github.com/getkin/kin-openapi/openapi3filter/validation_error.go
generated
vendored
|
|
@ -35,8 +35,7 @@ var _ error = &ValidationError{}
|
|||
|
||||
// Error implements the error interface.
|
||||
func (e *ValidationError) Error() string {
|
||||
b := new(bytes.Buffer)
|
||||
b.WriteString("[")
|
||||
b := bytes.NewBufferString("[")
|
||||
if e.Status != 0 {
|
||||
b.WriteString(strconv.Itoa(e.Status))
|
||||
}
|
||||
|
|
|
|||
17
vendor/github.com/getkin/kin-openapi/openapi3filter/validation_error_encoder.go
generated
vendored
17
vendor/github.com/getkin/kin-openapi/openapi3filter/validation_error_encoder.go
generated
vendored
|
|
@ -17,16 +17,18 @@ type ValidationErrorEncoder struct {
|
|||
|
||||
// Encode implements the ErrorEncoder interface for encoding ValidationErrors
|
||||
func (enc *ValidationErrorEncoder) Encode(ctx context.Context, err error, w http.ResponseWriter) {
|
||||
enc.Encoder(ctx, ConvertErrors(err), w)
|
||||
}
|
||||
|
||||
// ConvertErrors converts all errors to the appropriate error format.
|
||||
func ConvertErrors(err error) error {
|
||||
if e, ok := err.(*routers.RouteError); ok {
|
||||
cErr := convertRouteError(e)
|
||||
enc.Encoder(ctx, cErr, w)
|
||||
return
|
||||
return convertRouteError(e)
|
||||
}
|
||||
|
||||
e, ok := err.(*RequestError)
|
||||
if !ok {
|
||||
enc.Encoder(ctx, err, w)
|
||||
return
|
||||
return err
|
||||
}
|
||||
|
||||
var cErr *ValidationError
|
||||
|
|
@ -43,10 +45,9 @@ func (enc *ValidationErrorEncoder) Encode(ctx context.Context, err error, w http
|
|||
}
|
||||
|
||||
if cErr != nil {
|
||||
enc.Encoder(ctx, cErr, w)
|
||||
return
|
||||
return cErr
|
||||
}
|
||||
enc.Encoder(ctx, err, w)
|
||||
return err
|
||||
}
|
||||
|
||||
func convertRouteError(e *routers.RouteError) *ValidationError {
|
||||
|
|
|
|||
4
vendor/github.com/getkin/kin-openapi/openapi3filter/validation_handler.go
generated
vendored
4
vendor/github.com/getkin/kin-openapi/openapi3filter/validation_handler.go
generated
vendored
|
|
@ -9,8 +9,12 @@ import (
|
|||
legacyrouter "github.com/getkin/kin-openapi/routers/legacy"
|
||||
)
|
||||
|
||||
// AuthenticationFunc allows for custom security requirement validation.
|
||||
// A non-nil error fails authentication according to https://spec.openapis.org/oas/v3.1.0#security-requirement-object
|
||||
// See ValidateSecurityRequirements
|
||||
type AuthenticationFunc func(context.Context, *AuthenticationInput) error
|
||||
|
||||
// NoopAuthenticationFunc is an AuthenticationFunc
|
||||
func NoopAuthenticationFunc(context.Context, *AuthenticationInput) error { return nil }
|
||||
|
||||
var _ AuthenticationFunc = NoopAuthenticationFunc
|
||||
|
|
|
|||
20
vendor/github.com/getkin/kin-openapi/routers/legacy/pathpattern/node.go
generated
vendored
20
vendor/github.com/getkin/kin-openapi/routers/legacy/pathpattern/node.go
generated
vendored
|
|
@ -1,11 +1,11 @@
|
|||
// Package pathpattern implements path matching.
|
||||
//
|
||||
// Examples of supported patterns:
|
||||
// * "/"
|
||||
// * "/abc""
|
||||
// * "/abc/{variable}" (matches until next '/' or end-of-string)
|
||||
// * "/abc/{variable*}" (matches everything, including "/abc" if "/abc" has noot)
|
||||
// * "/abc/{ variable | prefix_(.*}_suffix }" (matches regular expressions)
|
||||
// - "/"
|
||||
// - "/abc""
|
||||
// - "/abc/{variable}" (matches until next '/' or end-of-string)
|
||||
// - "/abc/{variable*}" (matches everything, including "/abc" if "/abc" has root)
|
||||
// - "/abc/{ variable | prefix_(.*}_suffix }" (matches regular expressions)
|
||||
package pathpattern
|
||||
|
||||
import (
|
||||
|
|
@ -28,8 +28,8 @@ type Options struct {
|
|||
// PathFromHost converts a host pattern to a path pattern.
|
||||
//
|
||||
// Examples:
|
||||
// * PathFromHost("some-subdomain.domain.com", false) -> "com/./domain/./some-subdomain"
|
||||
// * PathFromHost("some-subdomain.domain.com", true) -> "com/./domain/./subdomain/-/some"
|
||||
// - PathFromHost("some-subdomain.domain.com", false) -> "com/./domain/./some-subdomain"
|
||||
// - PathFromHost("some-subdomain.domain.com", true) -> "com/./domain/./subdomain/-/some"
|
||||
func PathFromHost(host string, specialDashes bool) string {
|
||||
buf := make([]byte, 0, len(host))
|
||||
end := len(host)
|
||||
|
|
@ -55,7 +55,7 @@ func PathFromHost(host string, specialDashes bool) string {
|
|||
|
||||
type Node struct {
|
||||
VariableNames []string
|
||||
Value interface{}
|
||||
Value any
|
||||
Suffixes SuffixList
|
||||
}
|
||||
|
||||
|
|
@ -153,7 +153,7 @@ func (list SuffixList) Swap(i, j int) {
|
|||
list[i], list[j] = b, a
|
||||
}
|
||||
|
||||
func (currentNode *Node) MustAdd(path string, value interface{}, options *Options) {
|
||||
func (currentNode *Node) MustAdd(path string, value any, options *Options) {
|
||||
node, err := currentNode.CreateNode(path, options)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
|
@ -161,7 +161,7 @@ func (currentNode *Node) MustAdd(path string, value interface{}, options *Option
|
|||
node.Value = value
|
||||
}
|
||||
|
||||
func (currentNode *Node) Add(path string, value interface{}, options *Options) error {
|
||||
func (currentNode *Node) Add(path string, value any, options *Options) error {
|
||||
node, err := currentNode.CreateNode(path, options)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
|||
17
vendor/github.com/getkin/kin-openapi/routers/legacy/router.go
generated
vendored
17
vendor/github.com/getkin/kin-openapi/routers/legacy/router.go
generated
vendored
|
|
@ -58,13 +58,13 @@ type Router struct {
|
|||
//
|
||||
// If the given OpenAPIv3 document has servers, router will use them.
|
||||
// All operations of the document will be added to the router.
|
||||
func NewRouter(doc *openapi3.T) (routers.Router, error) {
|
||||
if err := doc.Validate(context.Background()); err != nil {
|
||||
return nil, fmt.Errorf("validating OpenAPI failed: %v", err)
|
||||
func NewRouter(doc *openapi3.T, opts ...openapi3.ValidationOption) (routers.Router, error) {
|
||||
if err := doc.Validate(context.Background(), opts...); err != nil {
|
||||
return nil, fmt.Errorf("validating OpenAPI failed: %w", err)
|
||||
}
|
||||
router := &Router{doc: doc}
|
||||
root := router.node()
|
||||
for path, pathItem := range doc.Paths {
|
||||
for path, pathItem := range doc.Paths.Map() {
|
||||
for method, operation := range pathItem.Operations() {
|
||||
method = strings.ToUpper(method)
|
||||
if err := root.Add(method+" "+path, &routers.Route{
|
||||
|
|
@ -124,7 +124,7 @@ func (router *Router) FindRoute(req *http.Request) (*routers.Route, map[string]s
|
|||
Reason: routers.ErrPathNotFound.Error(),
|
||||
}
|
||||
}
|
||||
pathParams = make(map[string]string, 8)
|
||||
pathParams = make(map[string]string)
|
||||
paramNames, err := server.ParameterNames()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
|
|
@ -143,7 +143,7 @@ func (router *Router) FindRoute(req *http.Request) (*routers.Route, map[string]s
|
|||
route, _ = node.Value.(*routers.Route)
|
||||
}
|
||||
if route == nil {
|
||||
pathItem := doc.Paths[remainingPath]
|
||||
pathItem := doc.Paths.Value(remainingPath)
|
||||
if pathItem == nil {
|
||||
return nil, nil, &routers.RouteError{Reason: routers.ErrPathNotFound.Error()}
|
||||
}
|
||||
|
|
@ -157,10 +157,7 @@ func (router *Router) FindRoute(req *http.Request) (*routers.Route, map[string]s
|
|||
}
|
||||
paramKeys := node.VariableNames
|
||||
for i, value := range paramValues {
|
||||
key := paramKeys[i]
|
||||
if strings.HasSuffix(key, "*") {
|
||||
key = key[:len(key)-1]
|
||||
}
|
||||
key := strings.TrimSuffix(paramKeys[i], "*")
|
||||
pathParams[key] = value
|
||||
}
|
||||
return route, pathParams, nil
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue