func opResponsesSetter(op *spec.Operation) func(*spec.Response, map[int]spec.Response) { return func(def *spec.Response, scr map[int]spec.Response) { if op.Responses == nil { op.Responses = new(spec.Responses) } op.Responses.Default = def op.Responses.StatusCodeResponses = scr } }
func (pp *paramStructParser) parseStructType(gofile *ast.File, operation *spec.Operation, tpe *ast.StructType, seenPreviously map[string]spec.Parameter) error { if tpe.Fields != nil { pt := seenPreviously for _, fld := range tpe.Fields.List { if len(fld.Names) == 0 { // when the embedded struct is annotated with swagger:allOf it will be used as allOf property // otherwise the fields will just be included as normal properties if err := pp.parseEmbeddedStruct(gofile, operation, fld.Type, pt); err != nil { return err } } } for _, fld := range tpe.Fields.List { var nm, gnm string if len(fld.Names) > 0 && fld.Names[0] != nil && fld.Names[0].IsExported() { nm = fld.Names[0].Name gnm = nm if fld.Tag != nil && len(strings.TrimSpace(fld.Tag.Value)) > 0 { tv, err := strconv.Unquote(fld.Tag.Value) if err != nil { return err } if strings.TrimSpace(tv) != "" { st := reflect.StructTag(tv) jsonTag := st.Get("json") if jsonTag == "-" { continue } if jsonTag != "" { nm = strings.Split(jsonTag, ",")[0] } } } in := "query" // scan for param location first, this changes some behavior down the line if fld.Doc != nil { for _, cmt := range fld.Doc.List { for _, line := range strings.Split(cmt.Text, "\n") { matches := rxIn.FindStringSubmatch(line) if len(matches) > 0 && len(strings.TrimSpace(matches[1])) > 0 { in = strings.TrimSpace(matches[1]) } } } } ps := pt[nm] ps.In = in var pty swaggerTypable = paramTypable{&ps} if in == "body" { pty = schemaTypable{pty.Schema(), 0} } if in == "formData" && fld.Doc != nil && fileParam(fld.Doc) { pty.Typed("file", "") } else { if err := parseProperty(pp.scp, gofile, fld.Type, pty); err != nil { return err } } sp := new(sectionedParser) sp.setDescription = func(lines []string) { ps.Description = joinDropLast(lines) } if ps.Ref.String() == "" { sp.taggers = []tagParser{ newSingleLineTagParser("maximum", &setMaximum{paramValidations{&ps}, rxf(rxMaximumFmt, "")}), newSingleLineTagParser("minimum", &setMinimum{paramValidations{&ps}, rxf(rxMinimumFmt, "")}), newSingleLineTagParser("multipleOf", &setMultipleOf{paramValidations{&ps}, rxf(rxMultipleOfFmt, "")}), newSingleLineTagParser("minLength", &setMinLength{paramValidations{&ps}, rxf(rxMinLengthFmt, "")}), newSingleLineTagParser("maxLength", &setMaxLength{paramValidations{&ps}, rxf(rxMaxLengthFmt, "")}), newSingleLineTagParser("pattern", &setPattern{paramValidations{&ps}, rxf(rxPatternFmt, "")}), newSingleLineTagParser("collectionFormat", &setCollectionFormat{paramValidations{&ps}, rxf(rxCollectionFormatFmt, "")}), newSingleLineTagParser("minItems", &setMinItems{paramValidations{&ps}, rxf(rxMinItemsFmt, "")}), newSingleLineTagParser("maxItems", &setMaxItems{paramValidations{&ps}, rxf(rxMaxItemsFmt, "")}), newSingleLineTagParser("unique", &setUnique{paramValidations{&ps}, rxf(rxUniqueFmt, "")}), newSingleLineTagParser("required", &setRequiredParam{&ps}), newSingleLineTagParser("in", &matchOnlyParam{&ps, rxIn}), } itemsTaggers := func(items *spec.Items, level int) []tagParser { // the expression is 1-index based not 0-index itemsPrefix := fmt.Sprintf(rxItemsPrefixFmt, level+1) return []tagParser{ newSingleLineTagParser(fmt.Sprintf("items%dMaximum", level), &setMaximum{itemsValidations{items}, rxf(rxMaximumFmt, itemsPrefix)}), newSingleLineTagParser(fmt.Sprintf("items%dMinimum", level), &setMinimum{itemsValidations{items}, rxf(rxMinimumFmt, itemsPrefix)}), newSingleLineTagParser(fmt.Sprintf("items%dMultipleOf", level), &setMultipleOf{itemsValidations{items}, rxf(rxMultipleOfFmt, itemsPrefix)}), newSingleLineTagParser(fmt.Sprintf("items%dMinLength", level), &setMinLength{itemsValidations{items}, rxf(rxMinLengthFmt, itemsPrefix)}), newSingleLineTagParser(fmt.Sprintf("items%dMaxLength", level), &setMaxLength{itemsValidations{items}, rxf(rxMaxLengthFmt, itemsPrefix)}), newSingleLineTagParser(fmt.Sprintf("items%dPattern", level), &setPattern{itemsValidations{items}, rxf(rxPatternFmt, itemsPrefix)}), newSingleLineTagParser(fmt.Sprintf("items%dCollectionFormat", level), &setCollectionFormat{itemsValidations{items}, rxf(rxCollectionFormatFmt, itemsPrefix)}), newSingleLineTagParser(fmt.Sprintf("items%dMinItems", level), &setMinItems{itemsValidations{items}, rxf(rxMinItemsFmt, itemsPrefix)}), newSingleLineTagParser(fmt.Sprintf("items%dMaxItems", level), &setMaxItems{itemsValidations{items}, rxf(rxMaxItemsFmt, itemsPrefix)}), newSingleLineTagParser(fmt.Sprintf("items%dUnique", level), &setUnique{itemsValidations{items}, rxf(rxUniqueFmt, itemsPrefix)}), } } // check if this is a primitive, if so parse the validations from the // doc comments of the slice declaration. if ftped, ok := fld.Type.(*ast.ArrayType); ok { ftpe := ftped items, level := ps.Items, 0 for items != nil { switch iftpe := ftpe.Elt.(type) { case *ast.ArrayType: eleTaggers := itemsTaggers(items, level) sp.taggers = append(eleTaggers, sp.taggers...) ftpe = iftpe case *ast.Ident: if iftpe.Obj == nil { sp.taggers = append(itemsTaggers(items, level), sp.taggers...) } break default: return fmt.Errorf("unknown field type ele for %q", nm) } items = items.Items level = level + 1 } } } else { sp.taggers = []tagParser{ newSingleLineTagParser("required", &matchOnlyParam{&ps, rxRequired}), newSingleLineTagParser("in", &matchOnlyParam{&ps, rxIn}), } } if err := sp.Parse(fld.Doc); err != nil { return err } if ps.Name == "" { ps.Name = nm } if nm != gnm { ps.AddExtension("x-go-name", gnm) } pt[nm] = ps } } for k, p := range pt { for i, v := range operation.Parameters { if v.Name == k { operation.Parameters = append(operation.Parameters[:i], operation.Parameters[i+1:]...) break } } operation.Parameters = append(operation.Parameters, p) } } return nil }
func (g *swaggerGenerator) generateSwaggerOperation(test IApiTest, defs spec.Definitions) (spec.Operation, error) { op := spec.Operation{} op.Responses = &spec.Responses{} op.Responses.StatusCodeResponses = map[int]spec.Response{} var description string processedQueryParams := map[string]interface{}{} processedPathParams := map[string]interface{}{} processedHeaderParams := map[string]interface{}{} for _, testCase := range test.TestCases() { // parameter definitions are collected from 2xx tests only if testCase.ExpectedHttpCode >= 200 && testCase.ExpectedHttpCode < 300 { description = testCase.Description for key, param := range testCase.Headers { if _, ok := processedHeaderParams[key]; ok { continue } specParam, err := generateSwaggerSpecParam(key, param, "header") if err != nil { return op, err } processedHeaderParams[key] = nil op.Parameters = append(op.Parameters, specParam) } for key, param := range testCase.PathParams { if _, ok := processedPathParams[key]; ok { continue } param.Required = true // path parameters are always required specParam, err := generateSwaggerSpecParam(key, param, "path") if err != nil { return op, err } processedPathParams[key] = nil op.Parameters = append(op.Parameters, specParam) } for key, param := range testCase.QueryParams { if _, ok := processedQueryParams[key]; ok { continue } specParam, err := generateSwaggerSpecParam(key, param, "query") if err != nil { return op, err } processedQueryParams[key] = nil op.Parameters = append(op.Parameters, specParam) } if testCase.RequestBody != nil { specParam := spec.Parameter{} specParam.Name = "body" specParam.In = "body" specParam.Required = true // TODO: right now it supports json, but should support marshaller depending on MIME type if content, err := json.MarshalIndent(testCase.RequestBody, "", " "); err == nil { specParam.Description = string(content) } specParam.Schema = generateSpecSchema(testCase.RequestBody, defs) op.Parameters = append(op.Parameters, specParam) } } response := spec.Response{} response.Description = testCase.Description if testCase.ExpectedData != nil { response.Schema = generateSpecSchema(testCase.ExpectedData, defs) response.Examples = map[string]interface{}{ "application/json": testCase.ExpectedData, } } op.Responses.StatusCodeResponses[testCase.ExpectedHttpCode] = response } op.Summary = description if taggable, ok := test.(ITaggable); ok { op.Tags = []string{taggable.Tag()} } return op, nil }
func opSecurityDefsSetter(op *spec.Operation) func([]map[string][]string) { return func(securityDefs []map[string][]string) { op.Security = securityDefs } }
func opSchemeSetter(op *spec.Operation) func([]string) { return func(schemes []string) { op.Schemes = schemes } }
func opProducesSetter(op *spec.Operation) func([]string) { return func(produces []string) { op.Produces = produces } }
func opConsumesSetter(op *spec.Operation) func([]string) { return func(consumes []string) { op.Consumes = consumes } }