282 lines
8.1 KiB
Go
282 lines
8.1 KiB
Go
package encode // import "udico.de/uditaren/opier/encode"
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"sort"
|
|
"strconv"
|
|
"strings"
|
|
"udico.de/opier/openapi"
|
|
)
|
|
|
|
type simpleparam struct {
|
|
Name string
|
|
Type string
|
|
In string
|
|
}
|
|
|
|
// implement sort interface on simpleparam
|
|
type simpleparamslice []*simpleparam
|
|
|
|
func (s simpleparamslice) Len() int { return len(s) }
|
|
func (s simpleparamslice) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
|
func (s simpleparamslice) Less(i, j int) bool {
|
|
val := func(s string) int {
|
|
switch s {
|
|
case "path":
|
|
return 0
|
|
case "header":
|
|
return 1
|
|
case "query":
|
|
return 2
|
|
}
|
|
return 99
|
|
}
|
|
iVal := val(s[i].In)
|
|
jVal := val(s[j].In)
|
|
iStr := s[i].Name
|
|
jStr := s[j].Name
|
|
if iVal == jVal {
|
|
return strings.Compare(iStr, jStr) < 0
|
|
}
|
|
return iVal < jVal
|
|
}
|
|
|
|
// Funcs generates all functions for a given tag
|
|
//
|
|
// tag is a
|
|
// tag name
|
|
func (e Encoder) Funcs(tag string, operations []*openapi.Operation) string {
|
|
|
|
tBuf := bytes.Buffer{}
|
|
tBuf.WriteString(fmt.Sprintf("package %v\n\n", e.Package))
|
|
tBuf.WriteString(e.GeneratedHeader())
|
|
tBuf.WriteString(e.tagType(tag))
|
|
|
|
tFuncPrefix := "p" + NormalizeName(tag)
|
|
|
|
for _, op := range operations {
|
|
// name -> type
|
|
tParams := make([]*simpleparam, 0, 5)
|
|
|
|
if op.Description != "" {
|
|
tDesc := strings.Split(strings.TrimSpace(op.Description), "\n")
|
|
for _, tLine := range tDesc {
|
|
tBuf.WriteString(fmt.Sprintf("// %v\n", tLine))
|
|
}
|
|
}
|
|
for _, params := range op.Path().Parameters {
|
|
tBuf.WriteString("// param [PATH] ")
|
|
if params.Ref != "" {
|
|
// ref param
|
|
tRefParam := e.api.ResolveParameter(params.Ref)
|
|
tBuf.WriteString(fmt.Sprintf("REF: %v\n", params.Ref))
|
|
tBuf.WriteString(Comment(tRefParam.Name, 2))
|
|
tParams = append(tParams, &simpleparam{
|
|
Name: tRefParam.Name,
|
|
Type: tRefParam.Schema.GoType(),
|
|
In: "path",
|
|
})
|
|
} else {
|
|
tBuf.WriteString(fmt.Sprintf("TYPE: %v\n", params.Schema.Type))
|
|
tParams = append(tParams, &simpleparam{
|
|
Name: params.Name,
|
|
Type: params.Schema.GoType(),
|
|
In: "path",
|
|
})
|
|
}
|
|
}
|
|
for _, params := range op.Parameters {
|
|
//tBuf.WriteString("// param ")
|
|
tBuf.WriteString(Comment(fmt.Sprintf("param [%v] %v: %v\n", params.In, params.Name, params.Description), 0))
|
|
tParams = append(tParams, &simpleparam{
|
|
Name: params.Name,
|
|
Type: params.Schema.GoType(),
|
|
In: string(params.In),
|
|
})
|
|
}
|
|
if op.RequestBody != nil {
|
|
tBuf.WriteString(fmt.Sprintf("// body: %v\n", op.RequestBody.Description))
|
|
for k, v := range op.RequestBody.Content {
|
|
tBuf.WriteString(fmt.Sprintf("// [%v]: %v\n", k, v.Schema.Ref))
|
|
}
|
|
}
|
|
|
|
var tResponseType *openapi.ResponseObject = nil
|
|
for tCode, tResponse := range op.Responses {
|
|
tBuf.WriteString(Comment(fmt.Sprintf("response [%v]: %v\n", tCode, tResponse.Description), 0))
|
|
tCodeVal, _ := strconv.Atoi(tCode)
|
|
if tCodeVal/100 == 2 {
|
|
tResponseType = tResponse
|
|
}
|
|
}
|
|
tResponses := make([]*simpleparam, 0, 2)
|
|
if tResponseType != nil {
|
|
for k, v := range tResponseType.Headers {
|
|
// each given responseheader is a return parameter
|
|
tResponses = append(tResponses, &simpleparam{
|
|
Name: k,
|
|
Type: v.Schema.TypeOrReference(),
|
|
In: "header",
|
|
})
|
|
}
|
|
if len(tResponseType.Content) > 0 {
|
|
tSchema := tResponseType.Content["application/json"].Schema
|
|
tResponses = append(tResponses, &simpleparam{
|
|
Name: "ret",
|
|
Type: tSchema.GoType(),
|
|
In: "body",
|
|
})
|
|
}
|
|
}
|
|
|
|
sort.Sort(simpleparamslice(tParams))
|
|
sort.Sort(simpleparamslice(tResponses))
|
|
|
|
// parameter list:
|
|
tResponses = append(tResponses, &simpleparam{
|
|
Name: "err",
|
|
Type: "error",
|
|
})
|
|
tParamBuf := &strings.Builder{}
|
|
for i, tParam := range tParams {
|
|
if i > 0 {
|
|
tParamBuf.WriteString(", ")
|
|
}
|
|
tParamBuf.WriteString(NormalizeName(tParam.Name))
|
|
tParamBuf.WriteString(" " + tParam.Type)
|
|
}
|
|
|
|
// body parameter:
|
|
if op.RequestBody != nil {
|
|
ref := op.RequestBody.Content["application/json"].Schema.Ref
|
|
if ref != "" {
|
|
if tParamBuf.Len() > 0 {
|
|
tParamBuf.WriteString(", ")
|
|
}
|
|
tParamBuf.WriteString(fmt.Sprintf("data *%v", e.api.ResolveSchema(ref).Name()))
|
|
} else {
|
|
tParamBuf.WriteString(" /* IMPLEMENT BODY SCHEMA which is not $ref */")
|
|
}
|
|
}
|
|
tParamStr := tParamBuf.String()
|
|
|
|
tResponseBuf := &strings.Builder{}
|
|
tResponseBuf.WriteString("(")
|
|
for i, tResponse := range tResponses {
|
|
if i > 0 {
|
|
tResponseBuf.WriteString(", ")
|
|
}
|
|
tResponseBuf.WriteString(tResponse.Name + " ")
|
|
tResponseBuf.WriteString(tResponse.Type)
|
|
}
|
|
tResponseBuf.WriteString(")")
|
|
tResponseStr := tResponseBuf.String()
|
|
|
|
tBuf.WriteString(fmt.Sprintf("func (p %v) %v(%v) %v {\n", tFuncPrefix, NormalizeName(op.OperationId), tParamStr, tResponseStr))
|
|
|
|
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")
|
|
tBufBody := "nil"
|
|
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")
|
|
tBufBody = "tBuf"
|
|
}
|
|
|
|
tBuf.WriteString(fmt.Sprintf(" req, _ := http.NewRequest(\"%v\", tPath, %v)\n", op.Method(), tBufBody))
|
|
// 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(" addQueryParameter(&q, \"%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"))
|
|
}
|
|
|
|
|
|
|
|
return tBuf.String()
|
|
}
|
|
|
|
func (e Encoder) tagType(tag string) string {
|
|
tNorm := NormalizeName(tag)
|
|
tBuf := bytes.Buffer{}
|
|
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")
|
|
tBuf.WriteString(" base string\n")
|
|
tBuf.WriteString("}\n\n")
|
|
tBuf.WriteString(fmt.Sprintf("func %v(aClient *http.Client, aBase string) p%v {\n", NormalizeName("new-"+tag), tNorm))
|
|
tBuf.WriteString(fmt.Sprintf(" return p%v{\n", tNorm))
|
|
tBuf.WriteString(" client: aClient,\n")
|
|
tBuf.WriteString(" base: aBase,\n")
|
|
tBuf.WriteString(" }\n")
|
|
tBuf.WriteString("}\n\n")
|
|
return tBuf.String()
|
|
}
|
|
|
|
func (e Encoder) getTagDescription(tag string) string {
|
|
for _, v := range e.api.Tags {
|
|
if v.Name == tag {
|
|
return v.Description
|
|
}
|
|
}
|
|
return ""
|
|
}
|