224 lines
7.2 KiB
Go
224 lines
7.2 KiB
Go
package openapi3
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
|
|
"github.com/getkin/kin-openapi/jsoninfo"
|
|
)
|
|
|
|
// Parameters is specified by OpenAPI/Swagger 3.0 standard.
|
|
type Parameters []*ParameterRef
|
|
|
|
func NewParameters() Parameters {
|
|
return make(Parameters, 0, 4)
|
|
}
|
|
|
|
func (parameters Parameters) GetByInAndName(in string, name string) *Parameter {
|
|
for _, item := range parameters {
|
|
if v := item.Value; v != nil {
|
|
if v.Name == name && v.In == in {
|
|
return v
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (parameters Parameters) Validate(c context.Context) error {
|
|
dupes := make(map[string]struct{})
|
|
for _, item := range parameters {
|
|
if v := item.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)
|
|
}
|
|
dupes[key] = struct{}{}
|
|
}
|
|
|
|
if err := item.Validate(c); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Parameter is specified by OpenAPI/Swagger 3.0 standard.
|
|
type Parameter struct {
|
|
ExtensionProps
|
|
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 map[string]*ExampleRef `json:"examples,omitempty" yaml:"examples,omitempty"`
|
|
Content Content `json:"content,omitempty" yaml:"content,omitempty"`
|
|
}
|
|
|
|
const (
|
|
ParameterInPath = "path"
|
|
ParameterInQuery = "query"
|
|
ParameterInHeader = "header"
|
|
ParameterInCookie = "cookie"
|
|
)
|
|
|
|
func NewPathParameter(name string) *Parameter {
|
|
return &Parameter{
|
|
Name: name,
|
|
In: ParameterInPath,
|
|
Required: true,
|
|
}
|
|
}
|
|
|
|
func NewQueryParameter(name string) *Parameter {
|
|
return &Parameter{
|
|
Name: name,
|
|
In: ParameterInQuery,
|
|
}
|
|
}
|
|
|
|
func NewHeaderParameter(name string) *Parameter {
|
|
return &Parameter{
|
|
Name: name,
|
|
In: ParameterInHeader,
|
|
}
|
|
}
|
|
|
|
func NewCookieParameter(name string) *Parameter {
|
|
return &Parameter{
|
|
Name: name,
|
|
In: ParameterInCookie,
|
|
}
|
|
}
|
|
|
|
func (parameter *Parameter) WithDescription(value string) *Parameter {
|
|
parameter.Description = value
|
|
return parameter
|
|
}
|
|
|
|
func (parameter *Parameter) WithRequired(value bool) *Parameter {
|
|
parameter.Required = value
|
|
return parameter
|
|
}
|
|
|
|
func (parameter *Parameter) WithSchema(value *Schema) *Parameter {
|
|
if value == nil {
|
|
parameter.Schema = nil
|
|
} else {
|
|
parameter.Schema = &SchemaRef{
|
|
Value: value,
|
|
}
|
|
}
|
|
return parameter
|
|
}
|
|
|
|
func (parameter *Parameter) MarshalJSON() ([]byte, error) {
|
|
return jsoninfo.MarshalStrictStruct(parameter)
|
|
}
|
|
|
|
func (parameter *Parameter) UnmarshalJSON(data []byte) error {
|
|
return jsoninfo.UnmarshalStrictStruct(data, parameter)
|
|
}
|
|
|
|
// SerializationMethod returns a parameter's serialization method.
|
|
// When a parameter's serialization method is not defined the method returns
|
|
// the default serialization method corresponding to a parameter's location.
|
|
func (parameter *Parameter) SerializationMethod() (*SerializationMethod, error) {
|
|
switch parameter.In {
|
|
case ParameterInPath, ParameterInHeader:
|
|
style := parameter.Style
|
|
if style == "" {
|
|
style = SerializationSimple
|
|
}
|
|
explode := false
|
|
if parameter.Explode != nil {
|
|
explode = *parameter.Explode
|
|
}
|
|
return &SerializationMethod{Style: style, Explode: explode}, nil
|
|
case ParameterInQuery, ParameterInCookie:
|
|
style := parameter.Style
|
|
if style == "" {
|
|
style = SerializationForm
|
|
}
|
|
explode := true
|
|
if parameter.Explode != nil {
|
|
explode = *parameter.Explode
|
|
}
|
|
return &SerializationMethod{Style: style, Explode: explode}, nil
|
|
default:
|
|
return nil, fmt.Errorf("unexpected parameter's 'in': %q", parameter.In)
|
|
}
|
|
}
|
|
|
|
func (parameter *Parameter) Validate(c context.Context) error {
|
|
if parameter.Name == "" {
|
|
return errors.New("parameter name can't be blank")
|
|
}
|
|
in := parameter.In
|
|
switch in {
|
|
case
|
|
ParameterInPath,
|
|
ParameterInQuery,
|
|
ParameterInHeader,
|
|
ParameterInCookie:
|
|
default:
|
|
return fmt.Errorf("parameter can't have 'in' value %q", parameter.In)
|
|
}
|
|
|
|
// Validate a parameter's serialization method.
|
|
sm, err := parameter.SerializationMethod()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
var smSupported bool
|
|
switch {
|
|
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,
|
|
|
|
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,
|
|
|
|
parameter.In == ParameterInHeader && sm.Style == SerializationSimple && !sm.Explode,
|
|
parameter.In == ParameterInHeader && sm.Style == SerializationSimple && 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", parameter.Name, e)
|
|
}
|
|
|
|
if (parameter.Schema == nil) == (parameter.Content == nil) {
|
|
e := errors.New("parameter must contain exactly one of content and schema")
|
|
return fmt.Errorf("parameter %q schema is invalid: %v", parameter.Name, e)
|
|
}
|
|
if schema := parameter.Schema; schema != nil {
|
|
if err := schema.Validate(c); err != nil {
|
|
return fmt.Errorf("parameter %q schema is invalid: %v", parameter.Name, err)
|
|
}
|
|
}
|
|
if content := parameter.Content; content != nil {
|
|
if err := content.Validate(c); err != nil {
|
|
return fmt.Errorf("parameter %q content is invalid: %v", parameter.Name, err)
|
|
}
|
|
}
|
|
return nil
|
|
}
|