From 5d074b181af761fcfc55fae6982dbf6b004fc371 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thilo=20Karra=C3=9F?= Date: Wed, 14 Oct 2020 11:43:12 +0200 Subject: [PATCH] Implement func rendering --- encode/api.go | 25 ++++++++++++++- encode/func.go | 79 ++++++++++++++++++++++++++++++++++++++++++---- openapi/openapi.go | 2 +- 3 files changed, 97 insertions(+), 9 deletions(-) diff --git a/encode/api.go b/encode/api.go index 2bbcb31..575ae61 100644 --- a/encode/api.go +++ b/encode/api.go @@ -10,7 +10,30 @@ func (e Encoder) Api(server openapi.Server) string { tBuf := bytes.Buffer{} tBuf.WriteString(fmt.Sprintf("package %v\n\n", e.Package)) tBuf.WriteString(e.GeneratedHeader()) + tBuf.WriteString("import (\n \"fmt\"\n \"reflect\"\n \"strings\"\n)\n\n") tBuf.WriteString(Comment(server.Description, 0)) - tBuf.WriteString(fmt.Sprintf("const %v_OPENAPI_BASE string = \"%v\"", strings.ToUpper(e.Package), server.Url)) + tBuf.WriteString(fmt.Sprintf("const %v_OPENAPI_BASE string = \"%v\"\n\n", strings.ToUpper(e.Package), server.Url)) + // replace func: + tBuf.WriteString("func replacePathParam(path *string, param string, value interface{}) {\n") + tBuf.WriteString(" *path = strings.ReplaceAll(*path, \"{\" + param + \"}\", fmt.Sprintf(\"%v\", value))\n") + tBuf.WriteString("}\n\n") + tBuf.WriteString(`// Join anything into a string +func joinIfArray(v interface{}) string { + tBuf := &strings.Builder{} + switch reflect.TypeOf(v).Kind() { + case reflect.Slice, reflect.Array: + s := reflect.ValueOf(v) + for i:=0;i 0 { + tBuf.WriteString(",") + } + tBuf.WriteString(fmt.Sprintf("%v", s.Index(i))) + } + default: + tBuf.WriteString(fmt.Sprintf("%v", v)) + } + return tBuf.String() +} +`) return tBuf.String() } diff --git a/encode/func.go b/encode/func.go index ae3acd8..833eba5 100644 --- a/encode/func.go +++ b/encode/func.go @@ -24,7 +24,7 @@ func (s simpleparamslice) Less(i, j int) bool { switch s { case "path": return 0 - case "head": + case "header": return 1 case "query": return 2 @@ -116,7 +116,7 @@ func (e Encoder) Funcs(tag string, operations []*openapi.Operation) string { tResponses = append(tResponses, &simpleparam{ Name: k, Type: v.Schema.TypeOrReference(), - In: "head", + In: "header", }) } if len(tResponseType.Content) > 0 { @@ -174,11 +174,76 @@ func (e Encoder) Funcs(tag string, operations []*openapi.Operation) string { tBuf.WriteString(fmt.Sprintf("func (p %v) %v(%v) %v {\n", tFuncPrefix, NormalizeName(op.OperationId), tParamStr, tResponseStr)) - // add header parameters - // insert path parameters - // add query parameters - // post/put params ("body") tBuf.WriteString(fmt.Sprintf(" // [%v]%v operation here \n", op.Method(), op.Path().Name)) + // assemble request + // insert path parameters + tBuf.WriteString(fmt.Sprintf(" tPath := p.base+\"%v\"\n", op.Path().Name)) + for _, p := range tParams { + if p.In == "path" { + tBuf.WriteString(fmt.Sprintf(" replacePathParam(&tPath, \"%v\", %v)\n", p.Name, NormalizeName(p.Name))) + } + } + + // post/put params ("body") + tBuf.WriteString(" var tBuf *bytes.Buffer = nil\n") + if op.RequestBody != nil { + tBuf.WriteString(" var tData []byte = nil\n") + tBuf.WriteString(" tData, err = json.Marshal(data)\n") + tBuf.WriteString(" if err != nil {\n") + tBuf.WriteString(" return\n") + tBuf.WriteString(" }\n") + tBuf.WriteString(" tBuf = bytes.NewBuffer(tData)\n") + } + + tBuf.WriteString(fmt.Sprintf(" req, _ := http.NewRequest(\"%v\", tPath, tBuf)\n", op.Method())) + // add header parameters + for _, p := range tParams { + if p.In == "header" { + tBuf.WriteString(fmt.Sprintf(" req.Header.Add(\"%v\", \"%v\")\n", p.Name, NormalizeName(p.Name))) + } + } + + // add query parameters + tQBuf := &strings.Builder{} + tQBufHasData := false + tQBuf.WriteString(" q := req.URL.Query()\n") + for _, p := range tParams { + if p.In == "query" { + tQBuf.WriteString(fmt.Sprintf(" q.Add(\"%v\", joinIfArray(%v))\n", p.Name, NormalizeName(p.Name))) + tQBufHasData = true + } + } + tQBuf.WriteString(" req.URL.RawQuery = q.Encode()\n\n") + if tQBufHasData { + tBuf.WriteString(tQBuf.String()) + } + + tBuf.WriteString(" resp, err := p.client.Do(req)\n") + tBuf.WriteString(" if err != nil {\n return\n }\n") + tBuf.WriteString(" defer resp.Body.Close()\n") + tBuf.WriteString(" if resp.StatusCode / 100 != 2 {\n err = errors.New(resp.Status)\n return\n }\n") + // parse response + for _, r := range tResponses { + if r.In == "header" { + tBuf.WriteString(fmt.Sprintf(" %v = resp.Header.Get(\"%v\")\n", NormalizeName(r.Name), r.Name)) + } + } + for _, r := range tResponses { + if r.In == "body" { + tType := r.Type + if strings.HasPrefix(tType, "*") { + tType = "&" + strings.TrimPrefix(tType, "*") + } + tBuf.WriteString(" tResponseData, err := ioutil.ReadAll(resp.Body)\n") + tBuf.WriteString(" if err != nil {\n") + tBuf.WriteString(" return\n") + tBuf.WriteString(" }\n") + tBuf.WriteString(fmt.Sprintf(" ret = %v{}\n", tType)) + tBuf.WriteString(" err = json.Unmarshal(tResponseData, ret)\n") + break // there can be only one + } + } + tBuf.WriteString(fmt.Sprintf(" return\n}\n\n")) } @@ -190,7 +255,7 @@ func (e Encoder) Funcs(tag string, operations []*openapi.Operation) string { func (e Encoder) tagType(tag string) string { tNorm := NormalizeName(tag) tBuf := bytes.Buffer{} - tBuf.WriteString("import \"net/http\"\n\n") + tBuf.WriteString("import (\n \"bytes\"\n \"encoding/json\"\n \"errors\"\n \"io/ioutil\"\n \"net/http\"\n)\n") tBuf.WriteString(Comment(e.getTagDescription(tag), 0)) tBuf.WriteString(fmt.Sprintf("type p%v struct {\n", tNorm)) tBuf.WriteString(" client *http.Client\n") diff --git a/openapi/openapi.go b/openapi/openapi.go index af64601..ee86a60 100644 --- a/openapi/openapi.go +++ b/openapi/openapi.go @@ -202,7 +202,7 @@ func (o Operation) Path() *PathItem { } func (o Operation) Method() string { - return o.method + return strings.ToUpper(o.method) } type RequestBodyObject struct {