Skip to content

Commit

Permalink
Implementing OpenAPI 3.1.0 spec (#1513)
Browse files Browse the repository at this point in the history
* fix x-tagGroups

* fix module name

* change paths

* refactoring

* update dependencies

* stuff

* add log

* fix finding of main file

* fix broken type resolution

* fix bug

* clean deps

* fix tool after merging upstream

* use json-iterator to marshal json

* fix generating of json examples

* update config used by jsoniter

* bump version

* update dependencies

* resolve merge conflicts

* use newest go in docker

* yep

* fix gen

* fix gen

* update swag version

* yep

* fix parser

* fix some tests

* fix all tests

* parse most of general api description

* implement security scheme parsing

* parse oauth2 specs

* parse scopes and extensions in security schemes

* extend parsing security stuff

* process v3 routes

* meh

* find unimported types

* parse basic operation info

* parse primitive and object parameters

* generate openapi spec

* fix module name

* cleanup

* update version to 2.0

* fix issues that appread after merging

* cleanup after merge conflicts

* fix all tests

* add go 1.19 to workflows

* pin dockerfile to 1.19.7

* Set minimum supported Go version to 1.18.x

* parse response headers

* copy readme

* started to implement field parser

* Refactor: use RefOrSpec instead of Spec

* start to add tests for operationv3

* fix tests

* implement allOf with primitive types

* Add NestedPrimitiveArrayType test

* implement TestParseResponseCommentWithNestedFieldsV3

* add more tests

* parse arrays and maps

* fix implementation of map types

* implement more tests

* fix example docs

* adjust example

* fix example jsons

* support array types in Parameters

* implement more tests, implement correct collectionFormat handling

* finish implementation of operationv3 tests

* all tests green

* fix parsing of security definitions

* add test for generalAPI info

* end of day checkin

* Update example.json

* fix codeSamples from file and fix creation of operations

* fix resolving of schema ref errors

* fix tests that broke due to fixes on model parsing

* Fix creating schemes of array types of custom objects

* Fix resolution of refSchemas

* cleanup

* update dependencies

* cleanup

* Update README.md

reset readme.md

* Update README_zh-CN.md

reset readme_zh-CN

* update dependency

* reset test file

---------

Co-authored-by: Tobias Theel <[email protected]>
  • Loading branch information
2 people authored and ubogdan committed Apr 17, 2023
1 parent c85d570 commit e3bb142
Show file tree
Hide file tree
Showing 3 changed files with 204 additions and 1 deletion.
1 change: 1 addition & 0 deletions field_parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ const (
swaggerTypeTag = "swaggertype"
swaggerIgnoreTag = "swaggerignore"
)
var _ FieldParser = &tagBaseFieldParser{}

var _ FieldParser = &tagBaseFieldParser{}

Expand Down
202 changes: 202 additions & 0 deletions gen/genv3.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
package gen

import (
"bytes"
"fmt"
"io"
"os"
"path"
"path/filepath"
"strings"
"text/template"
"time"

"github.com/sv-tools/openapi/spec"
"github.com/swaggo/swag"
)

type openAPITypeWriter func(*Config, *spec.OpenAPI) error

func (g *Gen) writeDocOpenAPI(config *Config, openAPI *spec.OpenAPI) error {
var filename = "docs.go"

if config.InstanceName != swag.Name {
filename = config.InstanceName + "_" + filename
}

docFileName := path.Join(config.OutputDir, filename)

absOutputDir, err := filepath.Abs(config.OutputDir)
if err != nil {
return err
}

packageName := filepath.Base(absOutputDir)

docs, err := os.Create(docFileName)
if err != nil {
return err
}
defer docs.Close()

// Write doc
err = g.writeGoDocV3(packageName, docs, openAPI, config)
if err != nil {
return err
}

g.debug.Printf("create docs.go at %+v", docFileName)

return nil
}

func (g *Gen) writeJSONOpenAPI(config *Config, swagger *spec.OpenAPI) error {
var filename = "swagger.json"

if config.InstanceName != swag.Name {
filename = config.InstanceName + "_" + filename
}

jsonFileName := path.Join(config.OutputDir, filename)

b, err := g.jsonIndent(swagger)
if err != nil {
return err
}

err = g.writeFile(b, jsonFileName)
if err != nil {
return err
}

g.debug.Printf("create swagger.json at %+v", jsonFileName)

return nil
}

func (g *Gen) writeYAMLOpenAPI(config *Config, swagger *spec.OpenAPI) error {
var filename = "swagger.yaml"

if config.InstanceName != swag.Name {
filename = config.InstanceName + "_" + filename
}

yamlFileName := path.Join(config.OutputDir, filename)

b, err := g.json(swagger)
if err != nil {
return err
}

y, err := g.jsonToYAML(b)
if err != nil {
return fmt.Errorf("cannot covert json to yaml error: %s", err)
}

err = g.writeFile(y, yamlFileName)
if err != nil {
return err
}

g.debug.Printf("create swagger.yaml at %+v", yamlFileName)

return nil
}

func (g *Gen) writeGoDocV3(packageName string, output io.Writer, openAPI *spec.OpenAPI, config *Config) error {
generator, err := template.New("swagger_info").Funcs(template.FuncMap{
"printDoc": func(v string) string {
// Add schemes
v = "{\n \"schemes\": {{ marshal .Schemes }}," + v[1:]
// Sanitize backticks
return strings.Replace(v, "`", "`+\"`\"+`", -1)
},
}).Parse(packageTemplateV3)
if err != nil {
return err
}

openAPISpec := spec.OpenAPI{
Components: openAPI.Components,
OpenAPI: openAPI.OpenAPI,
Info: &spec.Extendable[spec.Info]{
Spec: &spec.Info{
Description: "{{escape .Description}}",
Title: "{{.Title}}",
Version: "{{.Version}}",
TermsOfService: openAPI.Info.Spec.TermsOfService,
Contact: openAPI.Info.Spec.Contact,
License: openAPI.Info.Spec.License,
Summary: openAPI.Info.Spec.Summary,
},
Extensions: openAPI.Info.Extensions,
},
ExternalDocs: openAPI.ExternalDocs,
Paths: openAPI.Paths,
WebHooks: openAPI.WebHooks,
JsonSchemaDialect: openAPI.JsonSchemaDialect,
Security: openAPI.Security,
Tags: openAPI.Tags,
Servers: openAPI.Servers,
}

// crafted docs.json
buf, err := g.jsonIndent(openAPISpec)
if err != nil {
return err
}

buffer := &bytes.Buffer{}

err = generator.Execute(buffer, struct {
Timestamp time.Time
Doc string
PackageName string
Title string
Description string
Version string
InstanceName string
GeneratedTime bool
}{
Timestamp: time.Now(),
GeneratedTime: config.GeneratedTime,
Doc: string(buf),
PackageName: packageName,
Title: openAPI.Info.Spec.Title,
Description: openAPI.Info.Spec.Description,
Version: openAPI.Info.Spec.Version,
InstanceName: config.InstanceName,
})
if err != nil {
return err
}

code := g.formatSource(buffer.Bytes())

// write
_, err = output.Write(code)

return err
}

var packageTemplateV3 = `// Code generated by swaggo/swag{{ if .GeneratedTime }} at {{ .Timestamp }}{{ end }}. DO NOT EDIT
package docs
import "github.com/swaggo/swag"
const docTemplate{{ if ne .InstanceName "swagger" }}{{ .InstanceName }} {{- end }} = ` + "`{{ printDoc .Doc}}`" + `
// SwaggerInfo{{ if ne .InstanceName "swagger" }}{{ .InstanceName }} {{- end }} holds exported Swagger Info so clients can modify it
var SwaggerInfo{{ if ne .InstanceName "swagger" }}{{ .InstanceName }} {{- end }} = &swag.Spec{
Version: {{ printf "%q" .Version}},
Title: {{ printf "%q" .Title}},
Description: {{ printf "%q" .Description}},
InfoInstanceName: {{ printf "%q" .InstanceName }},
SwaggerTemplate: docTemplate{{ if ne .InstanceName "swagger" }}{{ .InstanceName }} {{- end }},
}
func init() {
swag.Register(SwaggerInfo{{ if ne .InstanceName "swagger" }}{{ .InstanceName }} {{- end }}.InstanceName(), SwaggerInfo{{ if ne .InstanceName "swagger" }}{{ .InstanceName }} {{- end }})
}
`
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
module github.com/swaggo/swag/v2
module github.com/swaggo/swag

go 1.18

Expand Down

0 comments on commit e3bb142

Please sign in to comment.