client.go raw
1 /*
2 Intelligent DNS API
3
4 No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
5
6 API version: 1.0.0
7 */
8
9 // Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT.
10
11 package idns
12
13 import (
14 "bytes"
15 "context"
16 "encoding/json"
17 "encoding/xml"
18 "errors"
19 "fmt"
20 "io"
21 "log"
22 "mime/multipart"
23 "net/http"
24 "net/http/httputil"
25 "net/url"
26 "os"
27 "path/filepath"
28 "reflect"
29 "regexp"
30 "strconv"
31 "strings"
32 "time"
33 "unicode/utf8"
34
35 )
36
37 var (
38 jsonCheck = regexp.MustCompile(`(?i:(?:application|text)/(?:vnd\.[^;]+\+)?json)`)
39 xmlCheck = regexp.MustCompile(`(?i:(?:application|text)/xml)`)
40 queryParamSplit = regexp.MustCompile(`(^|&)([^&]+)`)
41 queryDescape = strings.NewReplacer( "%5B", "[", "%5D", "]" )
42 )
43
44 // APIClient manages communication with the Intelligent DNS API API v1.0.0
45 // In most cases there should be only one, shared, APIClient.
46 type APIClient struct {
47 cfg *Configuration
48 common service // Reuse a single struct instead of allocating one for each service on the heap.
49
50 // API Services
51
52 DNSSECAPI *DNSSECAPIService
53
54 RecordsAPI *RecordsAPIService
55
56 ZonesAPI *ZonesAPIService
57 }
58
59 type service struct {
60 client *APIClient
61 }
62
63 // NewAPIClient creates a new API client. Requires a userAgent string describing your application.
64 // optionally a custom http.Client to allow for advanced features such as caching.
65 func NewAPIClient(cfg *Configuration) *APIClient {
66 if cfg.HTTPClient == nil {
67 cfg.HTTPClient = http.DefaultClient
68 }
69
70 c := &APIClient{}
71 c.cfg = cfg
72 c.common.client = c
73
74 // API Services
75 c.DNSSECAPI = (*DNSSECAPIService)(&c.common)
76 c.RecordsAPI = (*RecordsAPIService)(&c.common)
77 c.ZonesAPI = (*ZonesAPIService)(&c.common)
78
79 return c
80 }
81
82 func atoi(in string) (int, error) {
83 return strconv.Atoi(in)
84 }
85
86 // selectHeaderContentType select a content type from the available list.
87 func selectHeaderContentType(contentTypes []string) string {
88 if len(contentTypes) == 0 {
89 return ""
90 }
91 if contains(contentTypes, "application/json") {
92 return "application/json"
93 }
94 return contentTypes[0] // use the first content type specified in 'consumes'
95 }
96
97 // selectHeaderAccept join all accept types and return
98 func selectHeaderAccept(accepts []string) string {
99 if len(accepts) == 0 {
100 return ""
101 }
102
103 if contains(accepts, "application/json") {
104 return "application/json"
105 }
106
107 return strings.Join(accepts, ",")
108 }
109
110 // contains is a case insensitive match, finding needle in a haystack
111 func contains(haystack []string, needle string) bool {
112 for _, a := range haystack {
113 if strings.EqualFold(a, needle) {
114 return true
115 }
116 }
117 return false
118 }
119
120 // Verify optional parameters are of the correct type.
121 func typeCheckParameter(obj interface{}, expected string, name string) error {
122 // Make sure there is an object.
123 if obj == nil {
124 return nil
125 }
126
127 // Check the type is as expected.
128 if reflect.TypeOf(obj).String() != expected {
129 return fmt.Errorf("expected %s to be of type %s but received %s", name, expected, reflect.TypeOf(obj).String())
130 }
131 return nil
132 }
133
134 func parameterValueToString( obj interface{}, key string ) string {
135 if reflect.TypeOf(obj).Kind() != reflect.Ptr {
136 return fmt.Sprintf("%v", obj)
137 }
138 var param,ok = obj.(MappedNullable)
139 if !ok {
140 return ""
141 }
142 dataMap,err := param.ToMap()
143 if err != nil {
144 return ""
145 }
146 return fmt.Sprintf("%v", dataMap[key])
147 }
148
149 // parameterAddToHeaderOrQuery adds the provided object to the request header or url query
150 // supporting deep object syntax
151 func parameterAddToHeaderOrQuery(headerOrQueryParams interface{}, keyPrefix string, obj interface{}, collectionType string) {
152 var v = reflect.ValueOf(obj)
153 var value = ""
154 if v == reflect.ValueOf(nil) {
155 value = "null"
156 } else {
157 switch v.Kind() {
158 case reflect.Invalid:
159 value = "invalid"
160
161 case reflect.Struct:
162 if t,ok := obj.(MappedNullable); ok {
163 dataMap,err := t.ToMap()
164 if err != nil {
165 return
166 }
167 parameterAddToHeaderOrQuery(headerOrQueryParams, keyPrefix, dataMap, collectionType)
168 return
169 }
170 if t, ok := obj.(time.Time); ok {
171 parameterAddToHeaderOrQuery(headerOrQueryParams, keyPrefix, t.Format(time.RFC3339), collectionType)
172 return
173 }
174 value = v.Type().String() + " value"
175 case reflect.Slice:
176 var indValue = reflect.ValueOf(obj)
177 if indValue == reflect.ValueOf(nil) {
178 return
179 }
180 var lenIndValue = indValue.Len()
181 for i:=0;i<lenIndValue;i++ {
182 var arrayValue = indValue.Index(i)
183 parameterAddToHeaderOrQuery(headerOrQueryParams, keyPrefix, arrayValue.Interface(), collectionType)
184 }
185 return
186
187 case reflect.Map:
188 var indValue = reflect.ValueOf(obj)
189 if indValue == reflect.ValueOf(nil) {
190 return
191 }
192 iter := indValue.MapRange()
193 for iter.Next() {
194 k,v := iter.Key(), iter.Value()
195 parameterAddToHeaderOrQuery(headerOrQueryParams, fmt.Sprintf("%s[%s]", keyPrefix, k.String()), v.Interface(), collectionType)
196 }
197 return
198
199 case reflect.Interface:
200 fallthrough
201 case reflect.Ptr:
202 parameterAddToHeaderOrQuery(headerOrQueryParams, keyPrefix, v.Elem().Interface(), collectionType)
203 return
204
205 case reflect.Int, reflect.Int8, reflect.Int16,
206 reflect.Int32, reflect.Int64:
207 value = strconv.FormatInt(v.Int(), 10)
208 case reflect.Uint, reflect.Uint8, reflect.Uint16,
209 reflect.Uint32, reflect.Uint64, reflect.Uintptr:
210 value = strconv.FormatUint(v.Uint(), 10)
211 case reflect.Float32, reflect.Float64:
212 value = strconv.FormatFloat(v.Float(), 'g', -1, 32)
213 case reflect.Bool:
214 value = strconv.FormatBool(v.Bool())
215 case reflect.String:
216 value = v.String()
217 default:
218 value = v.Type().String() + " value"
219 }
220 }
221
222 switch valuesMap := headerOrQueryParams.(type) {
223 case url.Values:
224 if collectionType == "csv" && valuesMap.Get(keyPrefix) != "" {
225 valuesMap.Set(keyPrefix, valuesMap.Get(keyPrefix) + "," + value)
226 } else {
227 valuesMap.Add(keyPrefix, value)
228 }
229 break
230 case map[string]string:
231 valuesMap[keyPrefix] = value
232 break
233 }
234 }
235
236 // helper for converting interface{} parameters to json strings
237 func parameterToJson(obj interface{}) (string, error) {
238 jsonBuf, err := json.Marshal(obj)
239 if err != nil {
240 return "", err
241 }
242 return string(jsonBuf), err
243 }
244
245 // callAPI do the request.
246 func (c *APIClient) callAPI(request *http.Request) (*http.Response, error) {
247 if c.cfg.Debug {
248 dump, err := httputil.DumpRequestOut(request, true)
249 if err != nil {
250 return nil, err
251 }
252 log.Printf("\n%s\n", string(dump))
253 }
254
255 resp, err := c.cfg.HTTPClient.Do(request)
256 if err != nil {
257 return resp, err
258 }
259
260 if c.cfg.Debug {
261 dump, err := httputil.DumpResponse(resp, true)
262 if err != nil {
263 return resp, err
264 }
265 log.Printf("\n%s\n", string(dump))
266 }
267 return resp, err
268 }
269
270 // Allow modification of underlying config for alternate implementations and testing
271 // Caution: modifying the configuration while live can cause data races and potentially unwanted behavior
272 func (c *APIClient) GetConfig() *Configuration {
273 return c.cfg
274 }
275
276 type formFile struct {
277 fileBytes []byte
278 fileName string
279 formFileName string
280 }
281
282 // prepareRequest build the request
283 func (c *APIClient) prepareRequest(
284 ctx context.Context,
285 path string, method string,
286 postBody interface{},
287 headerParams map[string]string,
288 queryParams url.Values,
289 formParams url.Values,
290 formFiles []formFile) (localVarRequest *http.Request, err error) {
291
292 var body *bytes.Buffer
293
294 // Detect postBody type and post.
295 if postBody != nil {
296 contentType := headerParams["Content-Type"]
297 if contentType == "" {
298 contentType = detectContentType(postBody)
299 headerParams["Content-Type"] = contentType
300 }
301
302 body, err = setBody(postBody, contentType)
303 if err != nil {
304 return nil, err
305 }
306 }
307
308 // add form parameters and file if available.
309 if strings.HasPrefix(headerParams["Content-Type"], "multipart/form-data") && len(formParams) > 0 || (len(formFiles) > 0) {
310 if body != nil {
311 return nil, errors.New("Cannot specify postBody and multipart form at the same time.")
312 }
313 body = &bytes.Buffer{}
314 w := multipart.NewWriter(body)
315
316 for k, v := range formParams {
317 for _, iv := range v {
318 if strings.HasPrefix(k, "@") { // file
319 err = addFile(w, k[1:], iv)
320 if err != nil {
321 return nil, err
322 }
323 } else { // form value
324 w.WriteField(k, iv)
325 }
326 }
327 }
328 for _, formFile := range formFiles {
329 if len(formFile.fileBytes) > 0 && formFile.fileName != "" {
330 w.Boundary()
331 part, err := w.CreateFormFile(formFile.formFileName, filepath.Base(formFile.fileName))
332 if err != nil {
333 return nil, err
334 }
335 _, err = part.Write(formFile.fileBytes)
336 if err != nil {
337 return nil, err
338 }
339 }
340 }
341
342 // Set the Boundary in the Content-Type
343 headerParams["Content-Type"] = w.FormDataContentType()
344
345 // Set Content-Length
346 headerParams["Content-Length"] = fmt.Sprintf("%d", body.Len())
347 w.Close()
348 }
349
350 if strings.HasPrefix(headerParams["Content-Type"], "application/x-www-form-urlencoded") && len(formParams) > 0 {
351 if body != nil {
352 return nil, errors.New("Cannot specify postBody and x-www-form-urlencoded form at the same time.")
353 }
354 body = &bytes.Buffer{}
355 body.WriteString(formParams.Encode())
356 // Set Content-Length
357 headerParams["Content-Length"] = fmt.Sprintf("%d", body.Len())
358 }
359
360 // Setup path and query parameters
361 url, err := url.Parse(path)
362 if err != nil {
363 return nil, err
364 }
365
366 // Override request host, if applicable
367 if c.cfg.Host != "" {
368 url.Host = c.cfg.Host
369 }
370
371 // Override request scheme, if applicable
372 if c.cfg.Scheme != "" {
373 url.Scheme = c.cfg.Scheme
374 }
375
376 // Adding Query Param
377 query := url.Query()
378 for k, v := range queryParams {
379 for _, iv := range v {
380 query.Add(k, iv)
381 }
382 }
383
384 // Encode the parameters.
385 url.RawQuery = queryParamSplit.ReplaceAllStringFunc(query.Encode(), func(s string) string {
386 pieces := strings.Split(s, "=")
387 pieces[0] = queryDescape.Replace(pieces[0])
388 return strings.Join(pieces, "=")
389 })
390
391 // Generate a new request
392 if body != nil {
393 localVarRequest, err = http.NewRequest(method, url.String(), body)
394 } else {
395 localVarRequest, err = http.NewRequest(method, url.String(), nil)
396 }
397 if err != nil {
398 return nil, err
399 }
400
401 // add header parameters, if any
402 if len(headerParams) > 0 {
403 headers := http.Header{}
404 for h, v := range headerParams {
405 headers[h] = []string{v}
406 }
407 localVarRequest.Header = headers
408 }
409
410 // Add the user agent to the request.
411 localVarRequest.Header.Add("User-Agent", c.cfg.UserAgent)
412
413 if ctx != nil {
414 // add context to the request
415 localVarRequest = localVarRequest.WithContext(ctx)
416
417 // Walk through any authentication.
418
419 }
420
421 for header, value := range c.cfg.DefaultHeader {
422 localVarRequest.Header.Add(header, value)
423 }
424 return localVarRequest, nil
425 }
426
427 func (c *APIClient) decode(v interface{}, b []byte, contentType string) (err error) {
428 if len(b) == 0 {
429 return nil
430 }
431 if s, ok := v.(*string); ok {
432 *s = string(b)
433 return nil
434 }
435 if f, ok := v.(*os.File); ok {
436 f, err = os.CreateTemp("", "HttpClientFile")
437 if err != nil {
438 return
439 }
440 _, err = f.Write(b)
441 if err != nil {
442 return
443 }
444 _, err = f.Seek(0, io.SeekStart)
445 err = os.Remove(f.Name())
446 return
447 }
448 if f, ok := v.(**os.File); ok {
449 *f, err = os.CreateTemp("", "HttpClientFile")
450 if err != nil {
451 return
452 }
453 _, err = (*f).Write(b)
454 if err != nil {
455 return
456 }
457 _, err = (*f).Seek(0, io.SeekStart)
458 err = os.Remove((*f).Name())
459 return
460 }
461 if xmlCheck.MatchString(contentType) {
462 if err = xml.Unmarshal(b, v); err != nil {
463 return err
464 }
465 return nil
466 }
467 if jsonCheck.MatchString(contentType) {
468 if actualObj, ok := v.(interface{ GetActualInstance() interface{} }); ok { // oneOf, anyOf schemas
469 if unmarshalObj, ok := actualObj.(interface{ UnmarshalJSON([]byte) error }); ok { // make sure it has UnmarshalJSON defined
470 if err = unmarshalObj.UnmarshalJSON(b); err != nil {
471 return err
472 }
473 } else {
474 return errors.New("Unknown type with GetActualInstance but no unmarshalObj.UnmarshalJSON defined")
475 }
476 } else if err = json.Unmarshal(b, v); err != nil { // simple model
477 return err
478 }
479 return nil
480 }
481 return errors.New("undefined response type")
482 }
483
484 // Add a file to the multipart request
485 func addFile(w *multipart.Writer, fieldName, path string) error {
486 file, err := os.Open(filepath.Clean(path))
487 if err != nil {
488 return err
489 }
490 err = file.Close()
491 if err != nil {
492 return err
493 }
494
495 part, err := w.CreateFormFile(fieldName, filepath.Base(path))
496 if err != nil {
497 return err
498 }
499 _, err = io.Copy(part, file)
500
501 return err
502 }
503
504 // Prevent trying to import "fmt"
505 func reportError(format string, a ...interface{}) error {
506 return fmt.Errorf(format, a...)
507 }
508
509 // A wrapper for strict JSON decoding
510 func newStrictDecoder(data []byte) *json.Decoder {
511 dec := json.NewDecoder(bytes.NewBuffer(data))
512 dec.DisallowUnknownFields()
513 return dec
514 }
515
516 // Set request body from an interface{}
517 func setBody(body interface{}, contentType string) (bodyBuf *bytes.Buffer, err error) {
518 if bodyBuf == nil {
519 bodyBuf = &bytes.Buffer{}
520 }
521
522 if reader, ok := body.(io.Reader); ok {
523 _, err = bodyBuf.ReadFrom(reader)
524 } else if fp, ok := body.(*os.File); ok {
525 _, err = bodyBuf.ReadFrom(fp)
526 } else if b, ok := body.([]byte); ok {
527 _, err = bodyBuf.Write(b)
528 } else if s, ok := body.(string); ok {
529 _, err = bodyBuf.WriteString(s)
530 } else if s, ok := body.(*string); ok {
531 _, err = bodyBuf.WriteString(*s)
532 } else if jsonCheck.MatchString(contentType) {
533 err = json.NewEncoder(bodyBuf).Encode(body)
534 } else if xmlCheck.MatchString(contentType) {
535 var bs []byte
536 bs, err = xml.Marshal(body)
537 if err == nil {
538 bodyBuf.Write(bs)
539 }
540 }
541
542 if err != nil {
543 return nil, err
544 }
545
546 if bodyBuf.Len() == 0 {
547 err = fmt.Errorf("invalid body type %s\n", contentType)
548 return nil, err
549 }
550 return bodyBuf, nil
551 }
552
553 // detectContentType method is used to figure out `Request.Body` content type for request header
554 func detectContentType(body interface{}) string {
555 contentType := "text/plain; charset=utf-8"
556 kind := reflect.TypeOf(body).Kind()
557
558 switch kind {
559 case reflect.Struct, reflect.Map, reflect.Ptr:
560 contentType = "application/json; charset=utf-8"
561 case reflect.String:
562 contentType = "text/plain; charset=utf-8"
563 default:
564 if b, ok := body.([]byte); ok {
565 contentType = http.DetectContentType(b)
566 } else if kind == reflect.Slice {
567 contentType = "application/json; charset=utf-8"
568 }
569 }
570
571 return contentType
572 }
573
574 // Ripped from https://github.com/gregjones/httpcache/blob/master/httpcache.go
575 type cacheControl map[string]string
576
577 func parseCacheControl(headers http.Header) cacheControl {
578 cc := cacheControl{}
579 ccHeader := headers.Get("Cache-Control")
580 for _, part := range strings.Split(ccHeader, ",") {
581 part = strings.Trim(part, " ")
582 if part == "" {
583 continue
584 }
585 if strings.ContainsRune(part, '=') {
586 keyval := strings.Split(part, "=")
587 cc[strings.Trim(keyval[0], " ")] = strings.Trim(keyval[1], ",")
588 } else {
589 cc[part] = ""
590 }
591 }
592 return cc
593 }
594
595 // CacheExpires helper function to determine remaining time before repeating a request.
596 func CacheExpires(r *http.Response) time.Time {
597 // Figure out when the cache expires.
598 var expires time.Time
599 now, err := time.Parse(time.RFC1123, r.Header.Get("date"))
600 if err != nil {
601 return time.Now()
602 }
603 respCacheControl := parseCacheControl(r.Header)
604
605 if maxAge, ok := respCacheControl["max-age"]; ok {
606 lifetime, err := time.ParseDuration(maxAge + "s")
607 if err != nil {
608 expires = now
609 } else {
610 expires = now.Add(lifetime)
611 }
612 } else {
613 expiresHeader := r.Header.Get("Expires")
614 if expiresHeader != "" {
615 expires, err = time.Parse(time.RFC1123, expiresHeader)
616 if err != nil {
617 expires = now
618 }
619 }
620 }
621 return expires
622 }
623
624 func strlen(s string) int {
625 return utf8.RuneCountInString(s)
626 }
627
628 // GenericOpenAPIError Provides access to the body, error and model on returned errors.
629 type GenericOpenAPIError struct {
630 body []byte
631 error string
632 model interface{}
633 }
634
635 // Error returns non-empty string if there was an error.
636 func (e GenericOpenAPIError) Error() string {
637 return e.error
638 }
639
640 // Body returns the raw bytes of the response
641 func (e GenericOpenAPIError) Body() []byte {
642 return e.body
643 }
644
645 // Model returns the unpacked model of the error
646 func (e GenericOpenAPIError) Model() interface{} {
647 return e.model
648 }
649
650 // format error message using title and detail when model implements rfc7807
651 func formatErrorMessage(status string, v interface{}) string {
652 str := ""
653 metaValue := reflect.ValueOf(v).Elem()
654
655 if metaValue.Kind() == reflect.Struct {
656 field := metaValue.FieldByName("Title")
657 if field != (reflect.Value{}) {
658 str = fmt.Sprintf("%s", field.Interface())
659 }
660
661 field = metaValue.FieldByName("Detail")
662 if field != (reflect.Value{}) {
663 str = fmt.Sprintf("%s (%s)", str, field.Interface())
664 }
665 }
666
667 return strings.TrimSpace(fmt.Sprintf("%s %s", status, str))
668 }
669