opier/encode/func.go
2020-10-14 09:03:51 +02:00

216 lines
5.8 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 "head":
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: "head",
})
}
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))
// 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))
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 \"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 ""
}