-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathopenapi_gen.go
126 lines (116 loc) · 3.63 KB
/
openapi_gen.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
package api2
import (
"encoding/json"
"io"
"os"
"path/filepath"
"reflect"
spec "github.com/getkin/kin-openapi/openapi3"
"github.com/starius/api2/typegen"
)
func GenerateOpenApiSpec(options *TypesGenConfig) {
_ = os.RemoveAll(filepath.Join(options.OutDir, "openapi.json"))
err := os.MkdirAll(options.OutDir, os.ModePerm)
panicIf(err)
typesFile, err := os.OpenFile(filepath.Join(options.OutDir, "openapi.json"), os.O_WRONLY|os.O_CREATE, 0755)
panicIf(err)
parser := typegen.NewParser()
parser.CustomParse = CustomParse
allRoutes := []Route{}
for _, getRoutes := range options.Routes {
genValue := reflect.ValueOf(getRoutes)
serviceArg := reflect.New(genValue.Type().In(0)).Elem()
routesValues := genValue.Call([]reflect.Value{serviceArg})
routes := routesValues[0].Interface().([]Route)
allRoutes = append(allRoutes, routes...)
}
parser.ParseRaw(options.Types...)
swag := spec.T{
OpenAPI: "3.0.0",
Info: &spec.Info{
Version: "3.0.0",
},
Paths: spec.NewPaths(),
Components: &spec.Components{
RequestBodies: spec.RequestBodies{},
},
}
genOpenApiRoutes(typesFile, allRoutes, parser, options, &swag)
typegen.PrintSwagger(parser, &swag)
content, err := json.MarshalIndent(swag, "", " ")
panicIf(err)
_, err = typesFile.Write(content)
panicIf(err)
}
func genOpenApiRoutes(w io.Writer, routes []Route, p *typegen.Parser, options *TypesGenConfig, swagger *spec.T) {
type routeDef struct {
Method string
Path string
ReqType string
ResType string
Handler interface{}
FnInfo FnInfo
TypeInfoReq string
TypeInfoRes string
}
m := map[string]map[string][]routeDef{}
OUTER:
for _, route := range routes {
handler := route.Handler
if f, ok := handler.(funcer); ok {
handler = f.Func()
}
handlerVal := reflect.ValueOf(handler)
handlerType := handlerVal.Type()
req := reflect.TypeOf(reflect.New(handlerType.In(1)).Elem().Interface()).Elem()
response := reflect.TypeOf(reflect.New(handlerType.Out(0)).Elem().Interface()).Elem()
fnInfo := GetFnInfo(route.Handler)
for _, v := range options.Blacklist {
if Matches(&v, fnInfo.PkgName, fnInfo.StructName, fnInfo.Method) {
continue OUTER
}
}
p.Parse(req, response)
TypeInfoReq, err := serializeTypeInfo(prepare(req))
panicIf(err)
TypeInfoRes, err := serializeTypeInfo(prepare(response))
panicIf(err)
r := routeDef{
ReqType: req.String(),
ResType: response.String(),
Method: route.Method,
Path: route.Path,
Handler: route.Handler,
FnInfo: fnInfo,
TypeInfoReq: string(TypeInfoReq),
TypeInfoRes: string(TypeInfoRes),
}
if _, ok := m[fnInfo.PkgName]; !ok {
m[fnInfo.PkgName] = make(map[string][]routeDef)
}
m[fnInfo.PkgName][fnInfo.StructName] = append(m[fnInfo.PkgName][fnInfo.StructName], r)
p := swagger.Paths.Find(r.Path)
op := spec.NewOperation()
op.RequestBody = &spec.RequestBodyRef{
Ref: typegen.RefReqPrefix + r.ReqType,
}
if op.Responses == nil {
op.Responses = spec.NewResponses()
}
resp := spec.NewResponse()
description := "info"
resp.Description = &description
resp.Content = spec.NewContentWithSchemaRef(spec.NewSchemaRef(typegen.RefSchemaPrefix+r.ResType, nil), []string{"application/json"})
op.AddResponse(200, resp)
swagger.Components.RequestBodies[r.ReqType] = &spec.RequestBodyRef{
Value: spec.NewRequestBody().WithContent(spec.NewContentWithSchemaRef(spec.NewSchemaRef(typegen.RefSchemaPrefix+r.ReqType, nil), []string{"application/json"})),
}
if p == nil {
pi := &spec.PathItem{}
swagger.Paths.Set(r.Path, pi)
p = pi
}
op.Tags = append(op.Tags, r.FnInfo.PkgName)
p.SetOperation(r.Method, op)
}
}