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