Skip to content

Commit

Permalink
Merge pull request #49 from mxenabled/mc/update_mustache_template
Browse files Browse the repository at this point in the history
Update mustache template
  • Loading branch information
nickitza authored Feb 8, 2024
2 parents 9443f30 + 9bf777d commit e72b499
Showing 1 changed file with 174 additions and 37 deletions.
211 changes: 174 additions & 37 deletions openapi/templates/client.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import (
"errors"
"fmt"
"io"
"io/ioutil"
"log"
"mime/multipart"
"net" // Required for MX custom tls
Expand All @@ -26,16 +25,20 @@ import (
"time"
"unicode/utf8"

{{#hasOAuthMethods}}
"golang.org/x/oauth2"
{{/hasOAuthMethods}}
{{#withAWSV4Signature}}
awsv4 "github.com/aws/aws-sdk-go/aws/signer/v4"
awscredentials "github.com/aws/aws-sdk-go/aws/credentials"
{{/withAWSV4Signature}}
)

var (
jsonCheck = regexp.MustCompile(`(?i:(?:application|text)/(?:vnd\.[^;]+\+)?json)`)
xmlCheck = regexp.MustCompile(`(?i:(?:application|text)/xml)`)
JsonCheck = regexp.MustCompile(`(?i:(?:application|text)/(?:[^;]+\+)?json)`)
XmlCheck = regexp.MustCompile(`(?i:(?:application|text)/(?:[^;]+\+)?xml)`)
queryParamSplit = regexp.MustCompile(`(^|&)([^&]+)`)
queryDescape = strings.NewReplacer( "%5B", "[", "%5D", "]" )
)

// APIClient manages communication with the {{appName}} API v{{version}}
Expand Down Expand Up @@ -128,7 +131,7 @@ func selectHeaderAccept(accepts []string) string {
// contains is a case insensitive match, finding needle in a haystack
func contains(haystack []string, needle string) bool {
for _, a := range haystack {
if strings.ToLower(a) == strings.ToLower(needle) {
if strings.EqualFold(a, needle) {
return true
}
}
Expand All @@ -144,33 +147,111 @@ func typeCheckParameter(obj interface{}, expected string, name string) error {

// Check the type is as expected.
if reflect.TypeOf(obj).String() != expected {
return fmt.Errorf("Expected %s to be of type %s but received %s.", name, expected, reflect.TypeOf(obj).String())
return fmt.Errorf("expected %s to be of type %s but received %s", name, expected, reflect.TypeOf(obj).String())
}
return nil
}

// parameterToString convert interface{} parameters to string, using a delimiter if format is provided.
func parameterToString(obj interface{}, collectionFormat string) string {
var delimiter string
switch collectionFormat {
case "pipes":
delimiter = "|"
case "ssv":
delimiter = " "
case "tsv":
delimiter = "\t"
case "csv":
delimiter = ","
}
func parameterValueToString( obj interface{}, key string ) string {
if reflect.TypeOf(obj).Kind() != reflect.Ptr {
return fmt.Sprintf("%v", obj)
}
var param,ok = obj.(MappedNullable)
if !ok {
return ""
}
dataMap,err := param.ToMap()
if err != nil {
return ""
}
return fmt.Sprintf("%v", dataMap[key])
}

if reflect.TypeOf(obj).Kind() == reflect.Slice {
return strings.Trim(strings.Replace(fmt.Sprint(obj), " ", delimiter, -1), "[]")
} else if t, ok := obj.(time.Time); ok {
return t.Format(time.RFC3339)
}
// parameterAddToHeaderOrQuery adds the provided object to the request header or url query
// supporting deep object syntax
func parameterAddToHeaderOrQuery(headerOrQueryParams interface{}, keyPrefix string, obj interface{}, collectionType string) {
var v = reflect.ValueOf(obj)
var value = ""
if v == reflect.ValueOf(nil) {
value = "null"
} else {
switch v.Kind() {
case reflect.Invalid:
value = "invalid"
case reflect.Struct:
if t,ok := obj.(MappedNullable); ok {
dataMap,err := t.ToMap()
if err != nil {
return
}
parameterAddToHeaderOrQuery(headerOrQueryParams, keyPrefix, dataMap, collectionType)
return
}
if t, ok := obj.(time.Time); ok {
parameterAddToHeaderOrQuery(headerOrQueryParams, keyPrefix, t.Format(time.RFC3339), collectionType)
return
}
value = v.Type().String() + " value"
case reflect.Slice:
var indValue = reflect.ValueOf(obj)
if indValue == reflect.ValueOf(nil) {
return
}
var lenIndValue = indValue.Len()
for i:=0;i<lenIndValue;i++ {
var arrayValue = indValue.Index(i)
parameterAddToHeaderOrQuery(headerOrQueryParams, keyPrefix, arrayValue.Interface(), collectionType)
}
return

return fmt.Sprintf("%v", obj)
case reflect.Map:
var indValue = reflect.ValueOf(obj)
if indValue == reflect.ValueOf(nil) {
return
}
iter := indValue.MapRange()
for iter.Next() {
k,v := iter.Key(), iter.Value()
parameterAddToHeaderOrQuery(headerOrQueryParams, fmt.Sprintf("%s[%s]", keyPrefix, k.String()), v.Interface(), collectionType)
}
return

case reflect.Interface:
fallthrough
case reflect.Ptr:
parameterAddToHeaderOrQuery(headerOrQueryParams, keyPrefix, v.Elem().Interface(), collectionType)
return

case reflect.Int, reflect.Int8, reflect.Int16,
reflect.Int32, reflect.Int64:
value = strconv.FormatInt(v.Int(), 10)
case reflect.Uint, reflect.Uint8, reflect.Uint16,
reflect.Uint32, reflect.Uint64, reflect.Uintptr:
value = strconv.FormatUint(v.Uint(), 10)
case reflect.Float32, reflect.Float64:
value = strconv.FormatFloat(v.Float(), 'g', -1, 32)
case reflect.Bool:
value = strconv.FormatBool(v.Bool())
case reflect.String:
value = v.String()
default:
value = v.Type().String() + " value"
}
}

switch valuesMap := headerOrQueryParams.(type) {
case url.Values:
if collectionType == "csv" && valuesMap.Get(keyPrefix) != "" {
valuesMap.Set(keyPrefix, valuesMap.Get(keyPrefix) + "," + value)
} else {
valuesMap.Add(keyPrefix, value)
}
break
case map[string]string:
valuesMap[keyPrefix] = value
break
}
}

// helper for converting interface{} parameters to json strings
Expand Down Expand Up @@ -322,7 +403,11 @@ func (c *APIClient) prepareRequest(
}
// Encode the parameters.
url.RawQuery = query.Encode()
url.RawQuery = queryParamSplit.ReplaceAllStringFunc(query.Encode(), func(s string) string {
pieces := strings.Split(s, "=")
pieces[0] = queryDescape.Replace(pieces[0])
return strings.Join(pieces, "=")
})
// Generate a new request
if body != nil {
Expand Down Expand Up @@ -352,6 +437,7 @@ func (c *APIClient) prepareRequest(
// Walk through any authentication.
{{#hasOAuthMethods}}
// OAuth2 authentication
if tok, ok := ctx.Value(ContextOAuth2).(oauth2.TokenSource); ok {
// We were able to grab an oauth2 token from the context
Expand All @@ -363,16 +449,21 @@ func (c *APIClient) prepareRequest(
latestToken.SetAuthHeader(localVarRequest)
}
{{/hasOAuthMethods}}
{{#hasHttpBasicMethods}}
// Basic HTTP Authentication
if auth, ok := ctx.Value(ContextBasicAuth).(BasicAuth); ok {
localVarRequest.SetBasicAuth(auth.UserName, auth.Password)
}
{{/hasHttpBasicMethods}}
{{#hasHttpBearerMethods}}
// AccessToken Authentication
if auth, ok := ctx.Value(ContextAccessToken).(string); ok {
localVarRequest.Header.Add("Authorization", "Bearer "+auth)
}
{{/hasHttpBearerMethods}}
{{#withAWSV4Signature}}
// AWS Signature v4 Authentication
if auth, ok := ctx.Value(ContextAWSv4).(AWSv4); ok {
Expand Down Expand Up @@ -413,6 +504,13 @@ func (c *APIClient) prepareRequest(
c.cfg.Middleware(localVarRequest)
}
if c.cfg.MiddlewareWithError != nil {
err = c.cfg.MiddlewareWithError(localVarRequest)
if err != nil {
return nil, err
}
}
{{/withCustomMiddlewareFunction}}
{{#hasHttpSignatureMethods}}
if ctx != nil {
Expand All @@ -437,8 +535,20 @@ func (c *APIClient) decode(v interface{}, b []byte, contentType string) (err err
*s = string(b)
return nil
}
if f, ok := v.(*os.File); ok {
f, err = os.CreateTemp("", "HttpClientFile")
if err != nil {
return
}
_, err = f.Write(b)
if err != nil {
return
}
_, err = f.Seek(0, io.SeekStart)
return
}
if f, ok := v.(**os.File); ok {
*f, err = ioutil.TempFile("", "HttpClientFile")
*f, err = os.CreateTemp("", "HttpClientFile")
if err != nil {
return
}
Expand All @@ -449,13 +559,13 @@ func (c *APIClient) decode(v interface{}, b []byte, contentType string) (err err
_, err = (*f).Seek(0, io.SeekStart)
return
}
if xmlCheck.MatchString(contentType) {
if XmlCheck.MatchString(contentType) {
if err = xml.Unmarshal(b, v); err != nil {
return err
}
return nil
}
if jsonCheck.MatchString(contentType) {
if JsonCheck.MatchString(contentType) {
if actualObj, ok := v.(interface{ GetActualInstance() interface{} }); ok { // oneOf, anyOf schemas
if unmarshalObj, ok := actualObj.(interface{ UnmarshalJSON([]byte) error }); ok { // make sure it has UnmarshalJSON defined
if err = unmarshalObj.UnmarshalJSON(b); err != nil {
Expand All @@ -474,11 +584,14 @@ func (c *APIClient) decode(v interface{}, b []byte, contentType string) (err err

// Add a file to the multipart request
func addFile(w *multipart.Writer, fieldName, path string) error {
file, err := os.Open(path)
file, err := os.Open(filepath.Clean(path))
if err != nil {
return err
}
err = file.Close()
if err != nil {
return err
}
defer file.Close()
part, err := w.CreateFormFile(fieldName, filepath.Base(path))
if err != nil {
Expand Down Expand Up @@ -509,26 +622,30 @@ func setBody(body interface{}, contentType string) (bodyBuf *bytes.Buffer, err e
if reader, ok := body.(io.Reader); ok {
_, err = bodyBuf.ReadFrom(reader)
} else if fp, ok := body.(**os.File); ok {
_, err = bodyBuf.ReadFrom(*fp)
} else if fp, ok := body.(*os.File); ok {
_, err = bodyBuf.ReadFrom(fp)
} else if b, ok := body.([]byte); ok {
_, err = bodyBuf.Write(b)
} else if s, ok := body.(string); ok {
_, err = bodyBuf.WriteString(s)
} else if s, ok := body.(*string); ok {
_, err = bodyBuf.WriteString(*s)
} else if jsonCheck.MatchString(contentType) {
} else if JsonCheck.MatchString(contentType) {
err = json.NewEncoder(bodyBuf).Encode(body)
} else if xmlCheck.MatchString(contentType) {
err = xml.NewEncoder(bodyBuf).Encode(body)
} else if XmlCheck.MatchString(contentType) {
var bs []byte
bs, err = xml.Marshal(body)
if err == nil {
bodyBuf.Write(bs)
}
}
if err != nil {
return nil, err
}
if bodyBuf.Len() == 0 {
err = fmt.Errorf("Invalid body type %s\n", contentType)
err = fmt.Errorf("invalid body type %s\n", contentType)
return nil, err
}
return bodyBuf, nil
Expand Down Expand Up @@ -630,3 +747,23 @@ func (e GenericOpenAPIError) Body() []byte {
func (e GenericOpenAPIError) Model() interface{} {
return e.model
}

// format error message using title and detail when model implements rfc7807
func formatErrorMessage(status string, v interface{}) string {
str := ""
metaValue := reflect.ValueOf(v).Elem()
if metaValue.Kind() == reflect.Struct {
field := metaValue.FieldByName("Title")
if field != (reflect.Value{}) {
str = fmt.Sprintf("%s", field.Interface())
}
field = metaValue.FieldByName("Detail")
if field != (reflect.Value{}) {
str = fmt.Sprintf("%s (%s)", str, field.Interface())
}
}
return strings.TrimSpace(fmt.Sprintf("%s %s", status, str))
}

0 comments on commit e72b499

Please sign in to comment.