1// RequestEditorFn  is the function signature for the RequestEditor callback function
2type RequestEditorFn func(ctx context.Context, req *http.Request) error
3
4// Doer performs HTTP requests.
5//
6// The standard http.Client implements this interface.
7type HttpRequestDoer interface {
8	Do(req *http.Request) (*http.Response, error)
9}
10
11// Client which conforms to the OpenAPI3 specification for this service.
12type Client struct {
13	// The endpoint of the server conforming to this interface, with scheme,
14	// https://api.deepmap.com for example. This can contain a path relative
15	// to the server, such as https://api.deepmap.com/dev-test, and all the
16	// paths in the swagger spec will be appended to the server.
17	Server string
18
19	// Doer for performing requests, typically a *http.Client with any
20	// customized settings, such as certificate chains.
21	Client HttpRequestDoer
22
23	// A list of callbacks for modifying requests which are generated before sending over
24	// the network.
25	RequestEditors []RequestEditorFn
26}
27
28// ClientOption allows setting custom parameters during construction
29type ClientOption func(*Client) error
30
31// Creates a new Client, with reasonable defaults
32func NewClient(server string, opts ...ClientOption) (*Client, error) {
33    // create a client with sane default values
34    client := Client{
35        Server: server,
36    }
37    // mutate client and add all optional params
38    for _, o := range opts {
39        if err := o(&client); err != nil {
40            return nil, err
41        }
42    }
43    // ensure the server URL always has a trailing slash
44    if !strings.HasSuffix(client.Server, "/") {
45        client.Server += "/"
46    }
47    // create httpClient, if not already present
48    if client.Client == nil {
49        client.Client = &http.Client{}
50    }
51    return &client, nil
52}
53
54// WithHTTPClient allows overriding the default Doer, which is
55// automatically created using http.Client. This is useful for tests.
56func WithHTTPClient(doer HttpRequestDoer) ClientOption {
57	return func(c *Client) error {
58		c.Client = doer
59		return nil
60	}
61}
62
63// WithRequestEditorFn allows setting up a callback function, which will be
64// called right before sending the request. This can be used to mutate the request.
65func WithRequestEditorFn(fn RequestEditorFn) ClientOption {
66	return func(c *Client) error {
67		c.RequestEditors = append(c.RequestEditors, fn)
68		return nil
69	}
70}
71
72// The interface specification for the client above.
73type ClientInterface interface {
74{{range . -}}
75{{$hasParams := .RequiresParamObject -}}
76{{$pathParams := .PathParams -}}
77{{$opid := .OperationId -}}
78    // {{$opid}} request{{if .HasBody}} with any body{{end}}
79    {{$opid}}{{if .HasBody}}WithBody{{end}}(ctx context.Context{{genParamArgs $pathParams}}{{if $hasParams}}, params *{{$opid}}Params{{end}}{{if .HasBody}}, contentType string, body io.Reader{{end}}, reqEditors... RequestEditorFn) (*http.Response, error)
80{{range .Bodies}}
81    {{$opid}}{{.Suffix}}(ctx context.Context{{genParamArgs $pathParams}}{{if $hasParams}}, params *{{$opid}}Params{{end}}, body {{$opid}}{{.NameTag}}RequestBody, reqEditors... RequestEditorFn) (*http.Response, error)
82{{end}}{{/* range .Bodies */}}
83{{end}}{{/* range . $opid := .OperationId */}}
84}
85
86
87{{/* Generate client methods */}}
88{{range . -}}
89{{$hasParams := .RequiresParamObject -}}
90{{$pathParams := .PathParams -}}
91{{$opid := .OperationId -}}
92
93func (c *Client) {{$opid}}{{if .HasBody}}WithBody{{end}}(ctx context.Context{{genParamArgs $pathParams}}{{if $hasParams}}, params *{{$opid}}Params{{end}}{{if .HasBody}}, contentType string, body io.Reader{{end}}, reqEditors... RequestEditorFn) (*http.Response, error) {
94    req, err := New{{$opid}}Request{{if .HasBody}}WithBody{{end}}(c.Server{{genParamNames .PathParams}}{{if $hasParams}}, params{{end}}{{if .HasBody}}, contentType, body{{end}})
95    if err != nil {
96        return nil, err
97    }
98    req = req.WithContext(ctx)
99    if err := c.applyEditors(ctx, req, reqEditors); err != nil {
100        return nil, err
101    }
102    return c.Client.Do(req)
103}
104
105{{range .Bodies}}
106func (c *Client) {{$opid}}{{.Suffix}}(ctx context.Context{{genParamArgs $pathParams}}{{if $hasParams}}, params *{{$opid}}Params{{end}}, body {{$opid}}{{.NameTag}}RequestBody, reqEditors... RequestEditorFn) (*http.Response, error) {
107    req, err := New{{$opid}}{{.Suffix}}Request(c.Server{{genParamNames $pathParams}}{{if $hasParams}}, params{{end}}, body)
108    if err != nil {
109        return nil, err
110    }
111    req = req.WithContext(ctx)
112    if err := c.applyEditors(ctx, req, reqEditors); err != nil {
113        return nil, err
114    }
115    return c.Client.Do(req)
116}
117{{end}}{{/* range .Bodies */}}
118{{end}}
119
120{{/* Generate request builders */}}
121{{range .}}
122{{$hasParams := .RequiresParamObject -}}
123{{$pathParams := .PathParams -}}
124{{$bodyRequired := .BodyRequired -}}
125{{$opid := .OperationId -}}
126
127{{range .Bodies}}
128// New{{$opid}}Request{{.Suffix}} calls the generic {{$opid}} builder with {{.ContentType}} body
129func New{{$opid}}Request{{.Suffix}}(server string{{genParamArgs $pathParams}}{{if $hasParams}}, params *{{$opid}}Params{{end}}, body {{$opid}}{{.NameTag}}RequestBody) (*http.Request, error) {
130    var bodyReader io.Reader
131    buf, err := json.Marshal(body)
132    if err != nil {
133        return nil, err
134    }
135    bodyReader = bytes.NewReader(buf)
136    return New{{$opid}}RequestWithBody(server{{genParamNames $pathParams}}{{if $hasParams}}, params{{end}}, "{{.ContentType}}", bodyReader)
137}
138{{end}}
139
140// New{{$opid}}Request{{if .HasBody}}WithBody{{end}} generates requests for {{$opid}}{{if .HasBody}} with any type of body{{end}}
141func New{{$opid}}Request{{if .HasBody}}WithBody{{end}}(server string{{genParamArgs $pathParams}}{{if $hasParams}}, params *{{$opid}}Params{{end}}{{if .HasBody}}, contentType string, body io.Reader{{end}}) (*http.Request, error) {
142    var err error
143{{range $paramIdx, $param := .PathParams}}
144    var pathParam{{$paramIdx}} string
145    {{if .IsPassThrough}}
146    pathParam{{$paramIdx}} = {{.GoVariableName}}
147    {{end}}
148    {{if .IsJson}}
149    var pathParamBuf{{$paramIdx}} []byte
150    pathParamBuf{{$paramIdx}}, err = json.Marshal({{.GoVariableName}})
151    if err != nil {
152        return nil, err
153    }
154    pathParam{{$paramIdx}} = string(pathParamBuf{{$paramIdx}})
155    {{end}}
156    {{if .IsStyled}}
157    pathParam{{$paramIdx}}, err = runtime.StyleParamWithLocation("{{.Style}}", {{.Explode}}, "{{.ParamName}}", runtime.ParamLocationPath, {{.GoVariableName}})
158    if err != nil {
159        return nil, err
160    }
161    {{end}}
162{{end}}
163    serverURL, err := url.Parse(server)
164    if err != nil {
165        return nil, err
166    }
167
168    operationPath := fmt.Sprintf("{{genParamFmtString .Path}}"{{range $paramIdx, $param := .PathParams}}, pathParam{{$paramIdx}}{{end}})
169    if operationPath[0] == '/' {
170        operationPath = "." + operationPath
171    }
172
173    queryURL, err := serverURL.Parse(operationPath)
174    if err != nil {
175        return nil, err
176    }
177
178{{if .QueryParams}}
179    queryValues := queryURL.Query()
180{{range $paramIdx, $param := .QueryParams}}
181    {{if not .Required}} if params.{{.GoName}} != nil { {{end}}
182    {{if .IsPassThrough}}
183    queryValues.Add("{{.ParamName}}", {{if not .Required}}*{{end}}params.{{.GoName}})
184    {{end}}
185    {{if .IsJson}}
186    if queryParamBuf, err := json.Marshal({{if not .Required}}*{{end}}params.{{.GoName}}); err != nil {
187        return nil, err
188    } else {
189        queryValues.Add("{{.ParamName}}", string(queryParamBuf))
190    }
191
192    {{end}}
193    {{if .IsStyled}}
194    if queryFrag, err := runtime.StyleParamWithLocation("{{.Style}}", {{.Explode}}, "{{.ParamName}}", runtime.ParamLocationQuery, {{if not .Required}}*{{end}}params.{{.GoName}}); err != nil {
195        return nil, err
196    } else if parsed, err := url.ParseQuery(queryFrag); err != nil {
197       return nil, err
198    } else {
199       for k, v := range parsed {
200           for _, v2 := range v {
201               queryValues.Add(k, v2)
202           }
203       }
204    }
205    {{end}}
206    {{if not .Required}}}{{end}}
207{{end}}
208    queryURL.RawQuery = queryValues.Encode()
209{{end}}{{/* if .QueryParams */}}
210    req, err := http.NewRequest("{{.Method}}", queryURL.String(), {{if .HasBody}}body{{else}}nil{{end}})
211    if err != nil {
212        return nil, err
213    }
214
215    {{if .HasBody}}req.Header.Add("Content-Type", contentType){{end}}
216{{range $paramIdx, $param := .HeaderParams}}
217    {{if not .Required}} if params.{{.GoName}} != nil { {{end}}
218    var headerParam{{$paramIdx}} string
219    {{if .IsPassThrough}}
220    headerParam{{$paramIdx}} = {{if not .Required}}*{{end}}params.{{.GoName}}
221    {{end}}
222    {{if .IsJson}}
223    var headerParamBuf{{$paramIdx}} []byte
224    headerParamBuf{{$paramIdx}}, err = json.Marshal({{if not .Required}}*{{end}}params.{{.GoName}})
225    if err != nil {
226        return nil, err
227    }
228    headerParam{{$paramIdx}} = string(headerParamBuf{{$paramIdx}})
229    {{end}}
230    {{if .IsStyled}}
231    headerParam{{$paramIdx}}, err = runtime.StyleParamWithLocation("{{.Style}}", {{.Explode}}, "{{.ParamName}}", runtime.ParamLocationHeader, {{if not .Required}}*{{end}}params.{{.GoName}})
232    if err != nil {
233        return nil, err
234    }
235    {{end}}
236    req.Header.Set("{{.ParamName}}", headerParam{{$paramIdx}})
237    {{if not .Required}}}{{end}}
238{{end}}
239
240{{range $paramIdx, $param := .CookieParams}}
241    {{if not .Required}} if params.{{.GoName}} != nil { {{end}}
242    var cookieParam{{$paramIdx}} string
243    {{if .IsPassThrough}}
244    cookieParam{{$paramIdx}} = {{if not .Required}}*{{end}}params.{{.GoName}}
245    {{end}}
246    {{if .IsJson}}
247    var cookieParamBuf{{$paramIdx}} []byte
248    cookieParamBuf{{$paramIdx}}, err = json.Marshal({{if not .Required}}*{{end}}params.{{.GoName}})
249    if err != nil {
250        return nil, err
251    }
252    cookieParam{{$paramIdx}} = url.QueryEscape(string(cookieParamBuf{{$paramIdx}}))
253    {{end}}
254    {{if .IsStyled}}
255    cookieParam{{$paramIdx}}, err = runtime.StyleParamWithLocation("simple", {{.Explode}}, "{{.ParamName}}", runtime.ParamLocationCookie, {{if not .Required}}*{{end}}params.{{.GoName}})
256    if err != nil {
257        return nil, err
258    }
259    {{end}}
260    cookie{{$paramIdx}} := &http.Cookie{
261        Name:"{{.ParamName}}",
262        Value:cookieParam{{$paramIdx}},
263    }
264    req.AddCookie(cookie{{$paramIdx}})
265    {{if not .Required}}}{{end}}
266{{end}}
267    return req, nil
268}
269
270{{end}}{{/* Range */}}
271
272func (c *Client) applyEditors(ctx context.Context, req *http.Request, additionalEditors []RequestEditorFn) error {
273    for _, r := range c.RequestEditors {
274        if err := r(ctx, req); err != nil {
275            return err
276        }
277    }
278    for _, r := range additionalEditors {
279        if err := r(ctx, req); err != nil {
280            return err
281        }
282    }
283    return nil
284}
285