feat(client): 160,000 -> 85,000 LOC improvement for query-param heavy openapi specs
Unable at the moment to submit a PR, but we've pulled in client.tmpl locally as of commit d232e9efa9f54ee20ca60df885595bd23dc86759, and have applied the following patch of changes to the client.tmpl template.
diff --git a/templates/client.tmpl b/templates/client.tmpl
index 10ee564..54da21f 100644
--- a/templates/client.tmpl
+++ b/templates/client.tmpl
@@ -123,6 +123,26 @@ func (c *{{ $clientTypeName }}) {{$opid}}{{.Suffix}}(ctx context.Context{{genPar
{{end}}{{/* range .Bodies */}}
{{end}}
+func addParamToQuery(values url.Values, style string, explode bool, paramName string, value any) error {
+ queryFrag, err := runtime.StyleParamWithLocation(style, explode, paramName, runtime.ParamLocationQuery, value)
+ if err != nil {
+ return err
+ }
+
+ parsed, err := url.ParseQuery(queryFrag)
+ if err != nil {
+ return err
+ }
+
+ for k, v := range parsed {
+ for _, v2 := range v {
+ values.Add(k, v2)
+ }
+ }
+
+ return nil
+}
+
{{/* Generate request builders */}}
{{range .}}
{{$hasParams := .RequiresParamObject -}}
@@ -196,32 +216,23 @@ func New{{$opid}}Request{{if .HasBody}}WithBody{{end}}(server string{{genParamAr
{{if .QueryParams}}
if params != nil {
queryValues := queryURL.Query()
- {{range $paramIdx, $param := .QueryParams}}
+ {{range $paramIdx, $param := .QueryParams -}}
{{if not .Required}} if params.{{.GoName}} != nil { {{end}}
- {{if .IsPassThrough}}
+ {{- if .IsPassThrough}}
queryValues.Add("{{.ParamName}}", {{if not .Required}}*{{end}}params.{{.GoName}})
- {{end}}
- {{if .IsJson}}
+ {{- end}}
+ {{- if .IsJson}}
if queryParamBuf, err := json.Marshal({{if not .Required}}*{{end}}params.{{.GoName}}); err != nil {
return nil, err
} else {
queryValues.Add("{{.ParamName}}", string(queryParamBuf))
}
-
- {{end}}
- {{if .IsStyled}}
- if queryFrag, err := runtime.StyleParamWithLocation("{{.Style}}", {{.Explode}}, "{{.ParamName}}", runtime.ParamLocationQuery, {{if not .Required}}*{{end}}params.{{.GoName}}); err != nil {
+ {{- end}}
+ {{- if .IsStyled}}
+ if err := addParamToQuery(queryValues, "{{.Style}}", {{.Explode}}, "{{.ParamName}}", {{if not .Required}}*{{end}}params.{{.GoName}}); err != nil {
return nil, err
- } else if parsed, err := url.ParseQuery(queryFrag); err != nil {
- return nil, err
- } else {
- for k, v := range parsed {
- for _, v2 := range v {
- queryValues.Add(k, v2)
- }
- }
}
- {{end}}
+ {{- end}}
{{if not .Required}}}{{end}}
{{end}}
queryURL.RawQuery = queryValues.Encode()
Could likely be further improved if this were further extracted into runtime.
In the case of our OpenAPI spec, which is very query-param heavy, it cuts the LOC for the generated code from ~160,000 to ~85,000. Without this, it would take Go over 10 seconds to even parse the AST/compile due to the amount of generated code. With this change, it's near instant again.
We generate query params to add various forms of filtering to our paginated endpoints, though most requests don't actually use most query parameters.