Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
351 changes: 26 additions & 325 deletions config/clients/go/template/api.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,10 @@ package {{packageName}}

{{#operations}}
import (
"bytes"
"context"
"errors"
"io"
"log"
"net/http"
"net/url"
"time"
{{#imports}} "{{import}}"
{{/imports}}

"{{gitHost}}/{{gitUserId}}/{{gitRepoId}}/internal/utils/retryutils"
"{{gitHost}}/{{gitUserId}}/{{gitRepoId}}/telemetry"
)

// Linger please
Expand Down Expand Up @@ -105,343 +96,53 @@ func (a *{{{classname}}}Service) {{{nickname}}}(ctx context.Context{{#pathParams
* @return {{{.}}}{{/returnType}}
*/
func (a *{{{classname}}}Service) {{nickname}}Execute(r {{#structPrefix}}{{&classname}}{{/structPrefix}}Api{{operationId}}Request) ({{#returnType}}{{{.}}}, {{/returnType}}*http.Response, error) {
const (
operationName = "{{operationId}}"
httpMethod = http.Method{{httpMethod}}
)
var (
requestStarted = time.Now()
requestBody interface{}
{{#returnType}}
returnValue {{{.}}}
{{/returnType}}
)

path := "{{{path}}}"{{#pathParams}}
if r.{{paramName}} == "" {
return {{#returnType}}returnValue, {{/returnType}}nil, reportError("{{paramName}} is required and must be specified")
{{#returnType}}
var returnValue {{{.}}}
{{/returnType}}
{{#pathParams}}
if err := validatePathParameter("{{paramName}}", r.{{paramName}}); err != nil {
return {{#returnType}}returnValue, {{/returnType}}nil, err
}

path = strings.ReplaceAll(path, "{"+"{{baseName}}"+"}", url.PathEscape(parameterToString(r.{{paramName}}, "{{#collectionFormat}}{{collectionFormat}}{{/collectionFormat}}"))){{/pathParams}}

localVarHeaderParams := make(map[string]string)
localVarQueryParams := url.Values{}
{{/pathParams}}
{{#allParams}}
{{#required}}
{{^isPathParam}}
if r.{{paramName}} == nil {
return {{#returnType}}returnValue, {{/returnType}}nil, reportError("{{paramName}} is required and must be specified")
if err := validateParameter("{{paramName}}", r.{{paramName}}); err != nil {
return {{#returnType}}returnValue, {{/returnType}}nil, err
}
{{/isPathParam}}
{{#minItems}}
if len({{^isPathParam}}*{{/isPathParam}}r.{{paramName}}) < {{minItems}} {
return {{#returnType}}returnValue, {{/returnType}}nil, reportError("{{paramName}} must have at least {{minItems}} elements")
}
{{/minItems}}
{{#maxItems}}
if len({{^isPathParam}}*{{/isPathParam}}r.{{paramName}}) > {{maxItems}} {
return {{#returnType}}returnValue, {{/returnType}}nil, reportError("{{paramName}} must have less than {{maxItems}} elements")
}
{{/maxItems}}
{{#minLength}}
if strlen({{^isPathParam}}*{{/isPathParam}}r.{{paramName}}) < {{minLength}} {
return {{#returnType}}returnValue, {{/returnType}}nil, reportError("{{paramName}} must have at least {{minLength}} elements")
}
{{/minLength}}
{{#maxLength}}
if strlen({{^isPathParam}}*{{/isPathParam}}r.{{paramName}}) > {{maxLength}} {
return {{#returnType}}returnValue, {{/returnType}}nil, reportError("{{paramName}} must have less than {{maxLength}} elements")
}
{{/maxLength}}
{{#minimum}}
{{#isString}}
{{paramName}}Txt, err := atoi({{^isPathParam}}*{{/isPathParam}}r.{{paramName}})
if {{paramName}}Txt < {{minimum}} {
{{/isString}}
{{^isString}}
if {{^isPathParam}}*{{/isPathParam}}r.{{paramName}} < {{minimum}} {
{{/isString}}
return {{#returnType}}returnValue, {{/returnType}}nil, reportError("{{paramName}} must be greater than {{minimum}}")
}
{{/minimum}}
{{#maximum}}
{{#isString}}
{{paramName}}Txt, err := atoi({{^isPathParam}}*{{/isPathParam}}r.{{paramName}})
if {{paramName}}Txt > {{maximum}} {
{{/isString}}
{{^isString}}
if {{^isPathParam}}*{{/isPathParam}}r.{{paramName}} > {{maximum}} {
{{/isString}}
return {{#returnType}}returnValue, {{/returnType}}nil, reportError("{{paramName}} must be less than {{maximum}}")
}
{{/maximum}}
{{/required}}
{{/allParams}}

executor := a.client.GetAPIExecutor()
{{#queryParams.0}}

queryParams := url.Values{}
{{#queryParams}}
{{#required}}
{{#isCollectionFormatMulti}}
{
t := *r.{{paramName}}
if reflect.TypeOf(t).Kind() == reflect.Slice {
s := reflect.ValueOf(t)
for i := 0; i < s.Len(); i++ {
localVarQueryParams.Add("{{baseName}}", parameterToString(s.Index(i), "{{#collectionFormat}}{{collectionFormat}}{{/collectionFormat}}"))
}
} else {
localVarQueryParams.Add("{{baseName}}", parameterToString(t, "{{#collectionFormat}}{{collectionFormat}}{{/collectionFormat}}"))
}
}
{{/isCollectionFormatMulti}}
{{^isCollectionFormatMulti}}
localVarQueryParams.Add("{{baseName}}", parameterToString(*r.{{paramName}}, "{{#collectionFormat}}{{collectionFormat}}{{/collectionFormat}}"))
{{/isCollectionFormatMulti}}
queryParams.Add("{{baseName}}", parameterToString(*r.{{paramName}}, "{{#collectionFormat}}{{collectionFormat}}{{/collectionFormat}}"))
{{/required}}
{{^required}}
if r.{{paramName}} != nil {
{{#isCollectionFormatMulti}}
t := *r.{{paramName}}
if reflect.TypeOf(t).Kind() == reflect.Slice {
s := reflect.ValueOf(t)
for i := 0; i < s.Len(); i++ {
localVarQueryParams.Add("{{baseName}}", parameterToString(s.Index(i), "{{#collectionFormat}}{{collectionFormat}}{{/collectionFormat}}"))
}
} else {
localVarQueryParams.Add("{{baseName}}", parameterToString(t, "{{#collectionFormat}}{{collectionFormat}}{{/collectionFormat}}"))
}
{{/isCollectionFormatMulti}}
{{^isCollectionFormatMulti}}
localVarQueryParams.Add("{{baseName}}", parameterToString(*r.{{paramName}}, "{{#collectionFormat}}{{collectionFormat}}{{/collectionFormat}}"))
{{/isCollectionFormatMulti}}
queryParams.Add("{{baseName}}", parameterToString(*r.{{paramName}}, "{{#collectionFormat}}{{collectionFormat}}{{/collectionFormat}}"))
}
{{/required}}
{{/queryParams}}
// to determine the Content-Type header
{{=<% %>=}}
localVarHTTPContentTypes := []string{<%#consumes%>"<%&mediaType%>"<%^-last%>, <%/-last%><%/consumes%>}
<%={{ }}=%>

// set Content-Type header
localVarHTTPContentType := selectHeaderContentType(localVarHTTPContentTypes)
if localVarHTTPContentType != "" {
localVarHeaderParams["Content-Type"] = localVarHTTPContentType
}
{{/queryParams.0}}

// to determine the Accept header
{{=<% %>=}}
localVarHTTPHeaderAccepts := []string{<%#produces%>"<%&mediaType%>"<%^-last%>, <%/-last%><%/produces%>}
<%={{ }}=%>
request := NewAPIExecutorRequestBuilder("{{operationId}}", http.Method{{httpMethod}}, "{{{path}}}").{{#pathParams}}
WithPathParameter("{{baseName}}", r.{{paramName}}).{{/pathParams}}{{#queryParams.0}}
WithQueryParameters(queryParams).{{/queryParams.0}}{{#bodyParams}}
WithBody(r.{{paramName}}).{{/bodyParams}}
WithHeaders(r.options.Headers).
Build()
response, err := executor.{{#returnType}}ExecuteWithDecode{{/returnType}}{{^returnType}}Execute{{/returnType}}(r.ctx, request{{#returnType}}, &returnValue{{/returnType}})

// set Accept header
localVarHTTPHeaderAccept := selectHeaderAccept(localVarHTTPHeaderAccepts)
if localVarHTTPHeaderAccept != "" {
localVarHeaderParams["Accept"] = localVarHTTPHeaderAccept
}
{{#headerParams}}
{{#required}}
localVarHeaderParams["{{baseName}}"] = parameterToString(*r.{{paramName}}, "{{#collectionFormat}}{{collectionFormat}}{{/collectionFormat}}")
{{/required}}
{{^required}}
if r.{{paramName}} != nil {
localVarHeaderParams["{{baseName}}"] = parameterToString(*r.{{paramName}}, "{{#collectionFormat}}{{collectionFormat}}{{/collectionFormat}}")
}
{{/required}}
{{/headerParams}}
{{#formParams}}
{{#isFile}}
localVarFormFileName = "{{baseName}}"
{{#required}}
localVarFile := *r.{{paramName}}
{{/required}}
{{^required}}
var localVarFile {{dataType}}
if r.{{paramName}} != nil {
localVarFile = *r.{{paramName}}
}
{{/required}}
if localVarFile != nil {
fbs, _ := io.ReadAll(localVarFile)
localVarFileBytes = fbs
localVarFileName = localVarFile.Name()
localVarFile.Close()
}
{{/isFile}}
{{^isFile}}
{{#required}}
localVarFormParams.Add("{{baseName}}", parameterToString(*r.{{paramName}}, "{{#collectionFormat}}{{collectionFormat}}{{/collectionFormat}}"))
{{/required}}
{{^required}}
{{#isModel}}
if r.{{paramName}} != nil {
paramJson, err := parameterToJson(*r.{{paramName}})
if err != nil {
return {{#returnType}}returnValue, {{/returnType}}nil, err
}
localVarFormParams.Add("{{baseName}}", paramJson)
}
{{/isModel}}
{{^isModel}}
if r.{{paramName}} != nil {
localVarFormParams.Add("{{baseName}}", parameterToString(*r.{{paramName}}, "{{#collectionFormat}}{{collectionFormat}}{{/collectionFormat}}"))
}
{{/isModel}}
{{/required}}
{{/isFile}}
{{/formParams}}
{{#bodyParams}}
// body params
requestBody = r.{{paramName}}
{{/bodyParams}}

{{#authMethods}}
{{#isApiKey}}
{{^isKeyInCookie}}
if r.ctx != nil {
// API Key Authentication
if auth, ok := r.ctx.Value(ContextAPIKeys).(map[string]APIKey); ok {
{{#vendorExtensions.x-auth-id-alias}}
if apiKey, ok := auth["{{.}}"]; ok {
var key string
if prefix, ok := auth["{{name}}"]; ok && prefix.Prefix != "" {
key = prefix.Prefix + " " + apiKey.Key
} else {
key = apiKey.Key
}
{{/vendorExtensions.x-auth-id-alias}}
{{^vendorExtensions.x-auth-id-alias}}
if apiKey, ok := auth["{{name}}"]; ok {
var key string
if apiKey.Prefix != "" {
key = apiKey.Prefix + " " + apiKey.Key
} else {
key = apiKey.Key
}
{{/vendorExtensions.x-auth-id-alias}}
{{#isKeyInHeader}}
localVarHeaderParams["{{keyParamName}}"] = key
{{/isKeyInHeader}}
{{#isKeyInQuery}}
localVarQueryParams.Add("{{keyParamName}}", key)
{{/isKeyInQuery}}
}
}
}
{{/isKeyInCookie}}
{{/isApiKey}}
{{/authMethods}}

// if any override headers were in the options, set them now
for header, val := range r.options.Headers {
localVarHeaderParams[header] = val
}

retryParams := a.client.cfg.RetryParams
for i := 0; i < retryParams.MaxRetry+1; i++ {
req, err := a.client.prepareRequest(r.ctx, path, httpMethod, requestBody, localVarHeaderParams, localVarQueryParams)
if err != nil {
return {{#returnType}}returnValue, {{/returnType}}nil, err
}

httpResponse, err := a.client.callAPI(req)
if err != nil || httpResponse == nil {
if i < retryParams.MaxRetry {
timeToWait := retryutils.GetTimeToWait(i, retryParams.MaxRetry, retryParams.MinWaitInMs, http.Header{}, operationName)
if timeToWait > 0 {
if a.client.cfg.Debug {
log.Printf("\nWaiting %v to retry %v (%v %v) due to network error (error=%v) on attempt %v. Request body: %v\n", timeToWait, operationName, req.Method, req.URL, err, i, requestBody)
}
time.Sleep(timeToWait)
continue
}
}
return {{#returnType}}returnValue, {{/returnType}}httpResponse, err
}

responseBody, err := io.ReadAll(httpResponse.Body)
_ = httpResponse.Body.Close()
httpResponse.Body = io.NopCloser(bytes.NewBuffer(responseBody))
if err != nil {
if i < retryParams.MaxRetry {
timeToWait := retryutils.GetTimeToWait(i, retryParams.MaxRetry, retryParams.MinWaitInMs, httpResponse.Header, operationName)
if timeToWait > 0 {
if a.client.cfg.Debug {
log.Printf("\nWaiting %v to retry %v (%v %v) due to error parsing response body (err=%v) on attempt %v. Request body: %v\n", timeToWait, operationName, req.Method, req.URL, err, i, requestBody)
}
time.Sleep(timeToWait)
continue
}
}
return {{#returnType}}returnValue, {{/returnType}}httpResponse, err
}

if httpResponse.StatusCode >= http.StatusMultipleChoices {
err := a.client.handleAPIError(httpResponse, responseBody, requestBody, operationName, {{#pathParams.0}}r.storeId{{/pathParams.0}}{{^pathParams.0}}""{{/pathParams.0}})
if err != nil && i < retryParams.MaxRetry {
timeToWait := time.Duration(0)
var fgaApiRateLimitExceededError FgaApiRateLimitExceededError
var fgaApiInternalError FgaApiInternalError
switch {
case errors.As(err, &fgaApiRateLimitExceededError):
timeToWait = err.(FgaApiRateLimitExceededError).GetTimeToWait(i, *retryParams)
case errors.As(err, &fgaApiInternalError):
timeToWait = err.(FgaApiInternalError).GetTimeToWait(i, *retryParams)
}

if timeToWait > 0 {
if a.client.cfg.Debug {
log.Printf("\nWaiting %v to retry %v (%v %v) due to api retryable error (status code %v, error=%v) on attempt %v. Request body: %v\n", timeToWait, operationName, req.Method, req.URL, httpResponse.StatusCode, err, i, requestBody)
}
time.Sleep(timeToWait)
continue
}
}

return {{#returnType}}returnValue, {{/returnType}}httpResponse, err
if response != nil {
return {{#returnType}}returnValue, {{/returnType}}response.HTTPResponse, err
}

{{#returnType}}
err = a.client.decode(&returnValue, responseBody, httpResponse.Header.Get("Content-Type"))
if err != nil {
newErr := GenericOpenAPIError{
body: responseBody,
error: err.Error(),
}
return {{#returnType}}returnValue, {{/returnType}}httpResponse, newErr
}

{{/returnType}}
metrics := telemetry.GetMetrics(telemetry.TelemetryFactoryParameters{Configuration: a.client.cfg.Telemetry})

var attrs, queryDuration, requestDuration, _ = metrics.BuildTelemetryAttributes(
operationName,
map[string]interface{}{ {{#pathParams.0}}
"storeId": r.storeId,{{/pathParams.0}}
"body": requestBody,
},
req,
httpResponse,
requestStarted,
i,
)

if requestDuration > 0 {
_, _ = metrics.RequestDuration(requestDuration, attrs)
}

if queryDuration > 0 {
_, _ = metrics.QueryDuration(queryDuration, attrs)
}

return {{#returnType}}returnValue, {{/returnType}}httpResponse, nil
}

// should never have reached this
{{#returnType}}
return returnValue, nil, reportError("Error not handled properly")
{{/returnType}}
{{^returnType}}
return nil, reportError("Error not handled properly")
{{/returnType}}
return {{#returnType}}returnValue, {{/returnType}}nil, err
}
{{/operation}}
{{/operations}}
Loading