Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support accept Header & Use RequestBody #1541

Merged
merged 3 commits into from
Apr 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
186 changes: 152 additions & 34 deletions operationv3.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"strconv"
"strings"

"github.com/pkg/errors"
"github.com/sv-tools/openapi/spec"
"gopkg.in/yaml.v2"
)
Expand Down Expand Up @@ -145,16 +146,49 @@ func (o *OperationV3) ParseTagsComment(commentLine string) {
func (o *OperationV3) ParseAcceptComment(commentLine string) error {
const errMessage = "could not parse accept comment"

// TODO this must be moved into another comment
// return parseMimeTypeList(commentLine, &o.RequestBody.Spec.Spec.Content, )
// result, err := parseMimeTypeListV3(commentLine, "%v accept type can't be accepted")
// if err != nil {
// return errors.Wrap(err, errMessage)
// }
validTypes, err := parseMimeTypeListV3(commentLine, "%v accept type can't be accepted")
if err != nil {
return errors.Wrap(err, errMessage)
}

// for _, value := range result {
// o.RequestBody.Spec.Spec.Content[value] = spec.NewMediaType()
// }
if o.RequestBody == nil {
o.RequestBody = spec.NewRequestBodySpec()
}

if o.RequestBody.Spec.Spec.Content == nil {
o.RequestBody.Spec.Spec.Content = make(map[string]*spec.Extendable[spec.MediaType], len(validTypes))
}

for _, value := range validTypes {
// skip correctly setup types like application/json
if o.RequestBody.Spec.Spec.Content[value] != nil {
continue
}

mediaType := spec.NewMediaType()
schema := spec.NewSchemaSpec()

switch value {
case "application/json", "multipart/form-data", "text/xml":
schema.Spec.Type = spec.NewSingleOrArray(OBJECT)
case "image/png",
"image/jpeg",
"image/gif",
"application/octet-stream",
"application/pdf",
"application/msexcel",
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
"application/vnd.openxmlformats-officedocument.presentationml.presentation":
schema.Spec.Type = spec.NewSingleOrArray(STRING)
schema.Spec.Format = "binary"
default:
schema.Spec.Type = spec.NewSingleOrArray(STRING)
}

mediaType.Spec.Schema = schema
o.RequestBody.Spec.Spec.Content[value] = mediaType
}

return nil
}
Expand Down Expand Up @@ -316,15 +350,33 @@ func (o *OperationV3) ParseParamComment(commentLine string, astFile *ast.File) e
}
case "body":
if objectType == PRIMITIVE {
param.Schema = PrimitiveSchemaV3(refType)
} else {
schema, err := o.parseAPIObjectSchema(commentLine, objectType, refType, astFile)
schema := PrimitiveSchemaV3(refType)

err := o.parseParamAttributeForBody(commentLine, objectType, refType, schema.Spec)
if err != nil {
return err
}

param.Schema = schema
o.fillRequestBody(schema, required, description, true)

return nil

}

schema, err := o.parseAPIObjectSchema(commentLine, objectType, refType, astFile)
if err != nil {
return err
}

err = o.parseParamAttributeForBody(commentLine, objectType, refType, schema.Spec)
if err != nil {
return err
}

o.fillRequestBody(schema, required, description, false)

return nil

default:
return fmt.Errorf("%s is not supported paramType", paramType)
}
Expand All @@ -343,7 +395,74 @@ func (o *OperationV3) ParseParamComment(commentLine string, astFile *ast.File) e
return nil
}

func (o *OperationV3) fillRequestBody(schema *spec.RefOrSpec[spec.Schema], required bool, description string, primitive bool) {
if o.RequestBody == nil {
o.RequestBody = spec.NewRequestBodySpec()
o.RequestBody.Spec.Spec.Content = make(map[string]*spec.Extendable[spec.MediaType])

if primitive {
o.RequestBody.Spec.Spec.Content["text/plain"] = spec.NewMediaType()
} else {
o.RequestBody.Spec.Spec.Content["application/json"] = spec.NewMediaType()
}
}

o.RequestBody.Spec.Spec.Description = description
o.RequestBody.Spec.Spec.Required = required

for _, value := range o.RequestBody.Spec.Spec.Content {
value.Spec.Schema = schema
}
}

func (o *OperationV3) parseParamAttribute(comment, objectType, schemaType string, param *spec.Parameter) error {
if param == nil {
return fmt.Errorf("cannot parse empty parameter for comment: %s", comment)
}

schemaType = TransToValidSchemeType(schemaType)

for attrKey, re := range regexAttributes {
attr, err := findAttr(re, comment)
if err != nil {
continue
}

switch attrKey {
case enumsTag:
err = setEnumParamV3(param.Schema.Spec, attr, objectType, schemaType)
case minimumTag, maximumTag:
err = setNumberParamV3(param.Schema.Spec, attrKey, schemaType, attr, comment)
case defaultTag:
err = setDefaultV3(param.Schema.Spec, schemaType, attr)
case minLengthTag, maxLengthTag:
err = setStringParamV3(param.Schema.Spec, attrKey, schemaType, attr, comment)
case formatTag:
param.Schema.Spec.Format = attr
case exampleTag:
val, err := defineType(schemaType, attr)
if err != nil {
continue // Don't set a example value if it's not valid
}

param.Example = val
case schemaExampleTag:
err = setSchemaExampleV3(param.Schema.Spec, schemaType, attr)
case extensionsTag:
param.Schema.Spec.Extensions = setExtensionParam(attr)
case collectionFormatTag:
err = setCollectionFormatParamV3(param, attrKey, objectType, attr, comment)
}

if err != nil {
return err
}
}

return nil
}

func (o *OperationV3) parseParamAttributeForBody(comment, objectType, schemaType string, param *spec.Schema) error {
schemaType = TransToValidSchemeType(schemaType)

for attrKey, re := range regexAttributes {
Expand All @@ -362,15 +481,13 @@ func (o *OperationV3) parseParamAttribute(comment, objectType, schemaType string
case minLengthTag, maxLengthTag:
err = setStringParamV3(param, attrKey, schemaType, attr, comment)
case formatTag:
param.Schema.Spec.Format = attr
param.Format = attr
case exampleTag:
err = setExampleV3(param, schemaType, attr)
err = setSchemaExampleV3(param, schemaType, attr)
case schemaExampleTag:
err = setSchemaExampleV3(param, schemaType, attr)
case extensionsTag:
param.Schema.Spec.Extensions = setExtensionParam(attr)
case collectionFormatTag:
err = setCollectionFormatParamV3(param, attrKey, objectType, attr, comment)
param.Extensions = setExtensionParam(attr)
}

if err != nil {
Expand All @@ -390,28 +507,29 @@ func setCollectionFormatParamV3(param *spec.Parameter, name, schemaType, attr, c
return fmt.Errorf("%s is attribute to set to an array. comment=%s got=%s", name, commentLine, schemaType)
}

func setSchemaExampleV3(param *spec.Parameter, schemaType string, value string) error {
func setSchemaExampleV3(param *spec.Schema, schemaType string, value string) error {
val, err := defineType(schemaType, value)
if err != nil {
return nil // Don't set a example value if it's not valid
}

// skip schema
if param.Schema == nil {
if param == nil {
return nil
}

switch v := val.(type) {
case string:
// replaces \r \n \t in example string values.
param.Schema.Spec.Example = strings.NewReplacer(`\r`, "\r", `\n`, "\n", `\t`, "\t").Replace(v)
param.Example = strings.NewReplacer(`\r`, "\r", `\n`, "\n", `\t`, "\t").Replace(v)
default:
param.Schema.Spec.Example = val
param.Example = val
}

return nil
}

func setExampleV3(param *spec.Parameter, schemaType string, value string) error {
func setExampleParameterV3(param *spec.Parameter, schemaType string, value string) error {
val, err := defineType(schemaType, value)
if err != nil {
return nil // Don't set a example value if it's not valid
Expand All @@ -422,7 +540,7 @@ func setExampleV3(param *spec.Parameter, schemaType string, value string) error
return nil
}

func setStringParamV3(param *spec.Parameter, name, schemaType, attr, commentLine string) error {
func setStringParamV3(param *spec.Schema, name, schemaType, attr, commentLine string) error {
if schemaType != STRING {
return fmt.Errorf("%s is attribute to set to a number. comment=%s got=%s", name, commentLine, schemaType)
}
Expand All @@ -434,26 +552,26 @@ func setStringParamV3(param *spec.Parameter, name, schemaType, attr, commentLine

switch name {
case minLengthTag:
param.Schema.Spec.MinLength = &n
param.MinLength = &n
case maxLengthTag:
param.Schema.Spec.MaxLength = &n
param.MaxLength = &n
}

return nil
}

func setDefaultV3(param *spec.Parameter, schemaType string, value string) error {
func setDefaultV3(param *spec.Schema, schemaType string, value string) error {
val, err := defineType(schemaType, value)
if err != nil {
return nil // Don't set a default value if it's not valid
}

param.Schema.Spec.Default = val
param.Default = val

return nil
}

func setEnumParamV3(param *spec.Parameter, attr, objectType, schemaType string) error {
func setEnumParamV3(param *spec.Schema, attr, objectType, schemaType string) error {
for _, e := range strings.Split(attr, ",") {
e = strings.TrimSpace(e)

Expand All @@ -464,16 +582,16 @@ func setEnumParamV3(param *spec.Parameter, attr, objectType, schemaType string)

switch objectType {
case ARRAY:
param.Schema.Spec.Items.Schema.Spec.Enum = append(param.Schema.Spec.Items.Schema.Spec.Enum, value)
param.Items.Schema.Spec.Enum = append(param.Items.Schema.Spec.Enum, value)
default:
param.Schema.Spec.Enum = append(param.Schema.Spec.Enum, value)
param.Enum = append(param.Enum, value)
}
}

return nil
}

func setNumberParamV3(param *spec.Parameter, name, schemaType, attr, commentLine string) error {
func setNumberParamV3(param *spec.Schema, name, schemaType, attr, commentLine string) error {
switch schemaType {
case INTEGER, NUMBER:
n, err := strconv.Atoi(attr)
Expand All @@ -483,9 +601,9 @@ func setNumberParamV3(param *spec.Parameter, name, schemaType, attr, commentLine

switch name {
case minimumTag:
param.Schema.Spec.Minimum = &n
param.Minimum = &n
case maximumTag:
param.Schema.Spec.Maximum = &n
param.Maximum = &n
}

return nil
Expand Down
Loading