openai/openai-go

Public

mirrored from https://github.com/openai/openai-goAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
next

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

internal/requestconfig/requestconfig.go

795lines · modecode

1// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
2
3package requestconfig
4
5import (
6 "bytes"
7 "context"
8 "encoding/json"
9 "fmt"
10 "io"
11 "math"
12 "math/rand"
13 "mime"
14 "net/http"
15 "net/url"
16 "runtime"
17 "strconv"
18 "strings"
19 "time"
20
21 "github.com/openai/openai-go/v3/internal"
22 "github.com/openai/openai-go/v3/internal/apierror"
23 "github.com/openai/openai-go/v3/internal/apiform"
24 "github.com/openai/openai-go/v3/internal/apiquery"
25 "github.com/tidwall/gjson"
26)
27
28func getDefaultHeaders() map[string]string {
29 return map[string]string{
30 "User-Agent": fmt.Sprintf("OpenAI/Go %s", internal.PackageVersion),
31 }
32}
33
34func encodePathParam(value string) string {
35 switch value {
36 case ".":
37 return "%2E"
38 case "..":
39 return "%2E%2E"
40 }
41 return url.PathEscape(value)
42}
43
44// FormatPath escapes path parameters and inserts them into a request path.
45func FormatPath(format string, params ...string) string {
46 args := make([]any, len(params))
47 for i, param := range params {
48 args[i] = encodePathParam(param)
49 }
50 return fmt.Sprintf(format, args...)
51}
52
53func getNormalizedOS() string {
54 switch runtime.GOOS {
55 case "ios":
56 return "iOS"
57 case "android":
58 return "Android"
59 case "darwin":
60 return "MacOS"
61 case "window":
62 return "Windows"
63 case "freebsd":
64 return "FreeBSD"
65 case "openbsd":
66 return "OpenBSD"
67 case "linux":
68 return "Linux"
69 default:
70 return fmt.Sprintf("Other:%s", runtime.GOOS)
71 }
72}
73
74func getNormalizedArchitecture() string {
75 switch runtime.GOARCH {
76 case "386":
77 return "x32"
78 case "amd64":
79 return "x64"
80 case "arm":
81 return "arm"
82 case "arm64":
83 return "arm64"
84 default:
85 return fmt.Sprintf("other:%s", runtime.GOARCH)
86 }
87}
88
89func getPlatformProperties() map[string]string {
90 return map[string]string{
91 "X-Stainless-Lang": "go",
92 "X-Stainless-Package-Version": internal.PackageVersion,
93 "X-Stainless-OS": getNormalizedOS(),
94 "X-Stainless-Arch": getNormalizedArchitecture(),
95 "X-Stainless-Runtime": "go",
96 "X-Stainless-Runtime-Version": runtime.Version(),
97 }
98}
99
100type RequestOption interface {
101 Apply(*RequestConfig) error
102}
103
104type RequestOptionFunc func(*RequestConfig) error
105type PreRequestOptionFunc func(*RequestConfig) error
106
107func (s RequestOptionFunc) Apply(r *RequestConfig) error { return s(r) }
108func (s PreRequestOptionFunc) Apply(r *RequestConfig) error { return s(r) }
109
110func NewRequestConfig(ctx context.Context, method string, u string, body any, dst any, opts ...RequestOption) (*RequestConfig, error) {
111 var reader io.Reader
112
113 contentType := "application/json"
114 hasSerializationFunc := false
115
116 if body, ok := body.(json.Marshaler); ok {
117 content, err := body.MarshalJSON()
118 if err != nil {
119 return nil, err
120 }
121 reader = bytes.NewBuffer(content)
122 hasSerializationFunc = true
123 }
124 if body, ok := body.(apiform.Marshaler); ok {
125 var (
126 content []byte
127 err error
128 )
129 content, contentType, err = body.MarshalMultipart()
130 if err != nil {
131 return nil, err
132 }
133 reader = bytes.NewBuffer(content)
134 hasSerializationFunc = true
135 }
136 if body, ok := body.(apiquery.Queryer); ok {
137 hasSerializationFunc = true
138 q, err := body.URLQuery()
139 if err != nil {
140 return nil, err
141 }
142 params := q.Encode()
143 if params != "" {
144 parsed, _ := url.Parse(u)
145 if parsed.RawQuery != "" {
146 parsed.RawQuery = parsed.RawQuery + "&" + params
147 u = parsed.String()
148 } else {
149 u = u + "?" + params
150 }
151 }
152 }
153 if body, ok := body.([]byte); ok {
154 reader = bytes.NewBuffer(body)
155 hasSerializationFunc = true
156 }
157 if body, ok := body.(io.Reader); ok {
158 reader = body
159 hasSerializationFunc = true
160 }
161
162 // Fallback to json serialization if none of the serialization functions that we expect
163 // to see is present.
164 if body != nil && !hasSerializationFunc {
165 buf := new(bytes.Buffer)
166 enc := json.NewEncoder(buf)
167 enc.SetEscapeHTML(false)
168 if err := enc.Encode(body); err != nil {
169 return nil, err
170 }
171 reader = buf
172 }
173
174 req, err := http.NewRequestWithContext(ctx, method, u, nil)
175 if err != nil {
176 return nil, err
177 }
178 if reader != nil {
179 req.Header.Set("Content-Type", contentType)
180 }
181
182 req.Header.Set("Accept", "application/json")
183 req.Header.Set("X-Stainless-Retry-Count", "0")
184 req.Header.Set("X-Stainless-Timeout", "0")
185 for k, v := range getDefaultHeaders() {
186 req.Header.Add(k, v)
187 }
188
189 for k, v := range getPlatformProperties() {
190 req.Header.Add(k, v)
191 }
192 cfg := RequestConfig{
193 MaxRetries: 2,
194 Context: ctx,
195 Request: req,
196 HTTPClient: http.DefaultClient,
197 Body: reader,
198 }
199 cfg.ResponseBodyInto = dst
200 cfg.Security = Security{
201 BearerAuth: true,
202 AdminAPIKeyAuth: true,
203 }
204 err = cfg.Apply(opts...)
205 if err != nil {
206 return nil, err
207 }
208
209 // This must run after `cfg.Apply(...)` above so we know which specific security scheme to add
210 ApplySecurity(cfg)
211
212 // This must run after `cfg.Apply(...)` above in case the request timeout gets modified. We also only
213 // apply our own logic for it if it's still "0" from above. If it's not, then it was deleted or modified
214 // by the user and we should respect that.
215 if req.Header.Get("X-Stainless-Timeout") == "0" {
216 if cfg.RequestTimeout == time.Duration(0) {
217 req.Header.Del("X-Stainless-Timeout")
218 } else {
219 req.Header.Set("X-Stainless-Timeout", strconv.Itoa(int(cfg.RequestTimeout.Seconds())))
220 }
221 }
222
223 return &cfg, nil
224}
225
226// This interface is primarily used to describe an [*http.Client], but also
227// supports custom HTTP implementations.
228type HTTPDoer interface {
229 Do(req *http.Request) (*http.Response, error)
230}
231
232// RequestConfig represents all the state related to one request.
233//
234// Editing the variables inside RequestConfig directly is unstable api. Prefer
235// composing the RequestOption instead if possible.
236type RequestConfig struct {
237 MaxRetries int
238 RequestTimeout time.Duration
239 Context context.Context
240 Request *http.Request
241 BaseURL *url.URL
242 // DefaultBaseURL will be used if BaseURL is not explicitly overridden using
243 // WithBaseURL.
244 DefaultBaseURL *url.URL
245 CustomHTTPDoer HTTPDoer
246 HTTPClient *http.Client
247 Middlewares []middleware
248 APIKey string
249 AdminAPIKey string
250 Organization string
251 Project string
252 WebhookSecret string
253 authHeaderOverride bool
254 authPreference authCredentialPreference
255 // Configure which security scheme(s) should be enabled for this request
256 Security Security
257 // If ResponseBodyInto not nil, then we will attempt to deserialize into
258 // ResponseBodyInto. If Destination is a []byte, then it will return the body as
259 // is.
260 ResponseBodyInto any
261 // ResponseInto copies the \*http.Response of the corresponding request into the
262 // given address
263 ResponseInto **http.Response
264 Body io.Reader
265}
266
267// middleware is exactly the same type as the Middleware type found in the [option] package,
268// but it is redeclared here for circular dependency issues.
269type middleware = func(*http.Request, middlewareNext) (*http.Response, error)
270
271// middlewareNext is exactly the same type as the MiddlewareNext type found in the [option] package,
272// but it is redeclared here for circular dependency issues.
273type middlewareNext = func(*http.Request) (*http.Response, error)
274
275func applyMiddleware(middleware middleware, next middlewareNext) middlewareNext {
276 return func(req *http.Request) (res *http.Response, err error) {
277 return middleware(req, next)
278 }
279}
280
281func shouldRetry(req *http.Request, res *http.Response) bool {
282 // If there is no way to recover the Body, then we shouldn't retry.
283 if req.Body != nil && req.GetBody == nil {
284 return false
285 }
286
287 // If there is no response, that indicates that there is a connection error
288 // so we retry the request.
289 if res == nil {
290 return true
291 }
292
293 // If the header explicitly wants a retry behavior, respect that over the
294 // http status code.
295 if res.Header.Get("x-should-retry") == "true" {
296 return true
297 }
298 if res.Header.Get("x-should-retry") == "false" {
299 return false
300 }
301
302 return res.StatusCode == http.StatusRequestTimeout ||
303 res.StatusCode == http.StatusConflict ||
304 res.StatusCode == http.StatusTooManyRequests ||
305 res.StatusCode >= http.StatusInternalServerError
306}
307
308func parseRetryAfterHeader(resp *http.Response) (time.Duration, bool) {
309 if resp == nil {
310 return 0, false
311 }
312
313 type retryData struct {
314 header string
315 units time.Duration
316
317 // custom is used when the regular algorithm failed and is optional.
318 // the returned duration is used verbatim (units is not applied).
319 custom func(string) (time.Duration, bool)
320 }
321
322 nop := func(string) (time.Duration, bool) { return 0, false }
323
324 // the headers are listed in order of preference
325 retries := []retryData{
326 {
327 header: "Retry-After-Ms",
328 units: time.Millisecond,
329 custom: nop,
330 },
331 {
332 header: "Retry-After",
333 units: time.Second,
334
335 // retry-after values are expressed in either number of
336 // seconds or an HTTP-date indicating when to try again
337 custom: func(ra string) (time.Duration, bool) {
338 t, err := time.Parse(time.RFC1123, ra)
339 if err != nil {
340 return 0, false
341 }
342 return time.Until(t), true
343 },
344 },
345 }
346
347 for _, retry := range retries {
348 v := resp.Header.Get(retry.header)
349 if v == "" {
350 continue
351 }
352 if retryAfter, err := strconv.ParseFloat(v, 64); err == nil {
353 return time.Duration(retryAfter * float64(retry.units)), true
354 }
355 if d, ok := retry.custom(v); ok {
356 return d, true
357 }
358 }
359
360 return 0, false
361}
362
363// isBeforeContextDeadline reports whether the non-zero Time t is
364// before ctx's deadline. If ctx does not have a deadline, it
365// always reports true (the deadline is considered infinite).
366func isBeforeContextDeadline(t time.Time, ctx context.Context) bool {
367 d, ok := ctx.Deadline()
368 if !ok {
369 return true
370 }
371 return t.Before(d)
372}
373
374// bodyWithTimeout is an io.ReadCloser which can observe a context's cancel func
375// to handle timeouts etc. It wraps an existing io.ReadCloser.
376type bodyWithTimeout struct {
377 stop func() // stops the time.Timer waiting to cancel the request
378 rc io.ReadCloser
379}
380
381func (b *bodyWithTimeout) Read(p []byte) (n int, err error) {
382 n, err = b.rc.Read(p)
383 if err == nil {
384 return n, nil
385 }
386 if err == io.EOF {
387 return n, err
388 }
389 return n, err
390}
391
392func (b *bodyWithTimeout) Close() error {
393 err := b.rc.Close()
394 b.stop()
395 return err
396}
397
398func retryDelay(res *http.Response, retryCount int) time.Duration {
399 // If the backend tells us to wait a certain amount of time, use that value
400 if retryAfterDelay, ok := parseRetryAfterHeader(res); ok {
401 return max(0, retryAfterDelay)
402 }
403
404 maxDelay := 8 * time.Second
405 delay := time.Duration(0.5 * float64(time.Second) * math.Pow(2, float64(retryCount)))
406 if delay > maxDelay {
407 delay = maxDelay
408 }
409
410 jitter := rand.Int63n(int64(delay / 4))
411 delay -= time.Duration(jitter)
412 return delay
413}
414
415func (cfg *RequestConfig) Execute() (err error) {
416 if cfg.BaseURL == nil {
417 if cfg.DefaultBaseURL != nil {
418 cfg.BaseURL = cfg.DefaultBaseURL
419 } else {
420 return fmt.Errorf("requestconfig: base url is not set")
421 }
422 }
423
424 cfg.Request.URL, err = cfg.BaseURL.Parse(strings.TrimLeft(cfg.Request.URL.String(), "/"))
425 if err != nil {
426 return err
427 }
428
429 if cfg.Body != nil && cfg.Request.Body == nil {
430 switch body := cfg.Body.(type) {
431 case *bytes.Buffer:
432 b := body.Bytes()
433 cfg.Request.ContentLength = int64(body.Len())
434 cfg.Request.GetBody = func() (io.ReadCloser, error) { return io.NopCloser(bytes.NewReader(b)), nil }
435 cfg.Request.Body, _ = cfg.Request.GetBody()
436 case *bytes.Reader:
437 cfg.Request.ContentLength = int64(body.Len())
438 cfg.Request.GetBody = func() (io.ReadCloser, error) {
439 _, err := body.Seek(0, 0)
440 return io.NopCloser(body), err
441 }
442 cfg.Request.Body, _ = cfg.Request.GetBody()
443 default:
444 if rc, ok := body.(io.ReadCloser); ok {
445 cfg.Request.Body = rc
446 } else {
447 cfg.Request.Body = io.NopCloser(body)
448 }
449 }
450 }
451
452 handler := cfg.HTTPClient.Do
453 if cfg.CustomHTTPDoer != nil {
454 handler = cfg.CustomHTTPDoer.Do
455 }
456 for i := len(cfg.Middlewares) - 1; i >= 0; i -= 1 {
457 handler = applyMiddleware(cfg.Middlewares[i], handler)
458 }
459
460 // Don't send the current retry count in the headers if the caller modified the header defaults.
461 shouldSendRetryCount := cfg.Request.Header.Get("X-Stainless-Retry-Count") == "0"
462
463 var res *http.Response
464 var cancel context.CancelFunc
465 for retryCount := 0; retryCount <= cfg.MaxRetries; retryCount += 1 {
466 ctx := cfg.Request.Context()
467 if cfg.RequestTimeout != time.Duration(0) && isBeforeContextDeadline(time.Now().Add(cfg.RequestTimeout), ctx) {
468 ctx, cancel = context.WithTimeout(ctx, cfg.RequestTimeout)
469 defer func() {
470 // The cancel function is nil if it was handed off to be handled in a different scope.
471 if cancel != nil {
472 cancel()
473 }
474 }()
475 }
476
477 req := cfg.Request.Clone(ctx)
478 if shouldSendRetryCount {
479 req.Header.Set("X-Stainless-Retry-Count", strconv.Itoa(retryCount))
480 }
481
482 res, err = handler(req)
483 if ctx != nil && ctx.Err() != nil {
484 return ctx.Err()
485 }
486 if !shouldRetry(cfg.Request, res) || retryCount >= cfg.MaxRetries {
487 break
488 }
489
490 // Prepare next request and wait for the retry delay
491 if cfg.Request.GetBody != nil {
492 cfg.Request.Body, err = cfg.Request.GetBody()
493 if err != nil {
494 return err
495 }
496 }
497
498 // Can't actually refresh the body, so we don't attempt to retry here
499 if cfg.Request.GetBody == nil && cfg.Request.Body != nil {
500 break
501 }
502
503 // Close the response body before retrying to prevent connection leaks
504 if res != nil && res.Body != nil {
505 _ = res.Body.Close()
506 }
507
508 select {
509 case <-ctx.Done():
510 return ctx.Err()
511 case <-time.After(retryDelay(res, retryCount)):
512 }
513 }
514
515 // Save *http.Response if it is requested to, even if there was an error making the request. This is
516 // useful in cases where you might want to debug by inspecting the response. Note that if err != nil,
517 // the response should be generally be empty, but there are edge cases.
518 if cfg.ResponseInto != nil {
519 *cfg.ResponseInto = res
520 }
521 if responseBodyInto, ok := cfg.ResponseBodyInto.(**http.Response); ok {
522 *responseBodyInto = res
523 }
524
525 // If there was a connection error in the final request or any other transport error,
526 // return that early without trying to coerce into an APIError.
527 if err != nil {
528 return err
529 }
530
531 if res.StatusCode >= 400 {
532 contents, err := io.ReadAll(res.Body)
533 _ = res.Body.Close()
534 if err != nil {
535 return err
536 }
537
538 // If there is an APIError, re-populate the response body so that debugging
539 // utilities can conveniently dump the response without issue.
540 res.Body = io.NopCloser(bytes.NewBuffer(contents))
541
542 // Load the contents into the error format if it is provided.
543 aerr := apierror.Error{Request: cfg.Request, Response: res, StatusCode: res.StatusCode}
544 unwrapped := gjson.GetBytes(contents, "error").Raw
545 err = aerr.UnmarshalJSON([]byte(unwrapped))
546 if err != nil {
547 return err
548 }
549 return &aerr
550 }
551
552 _, intoCustomResponseBody := cfg.ResponseBodyInto.(**http.Response)
553 if cfg.ResponseBodyInto == nil || intoCustomResponseBody {
554 // We aren't reading the response body in this scope, but whoever is will need the
555 // cancel func from the context to observe request timeouts.
556 // Put the cancel function in the response body so it can be handled elsewhere.
557 if cancel != nil {
558 res.Body = &bodyWithTimeout{rc: res.Body, stop: cancel}
559 cancel = nil
560 }
561 return nil
562 }
563
564 contents, err := io.ReadAll(res.Body)
565 _ = res.Body.Close()
566 if err != nil {
567 return fmt.Errorf("error reading response body: %w", err)
568 }
569
570 // If we are not json, return plaintext
571 contentType := res.Header.Get("content-type")
572 mediaType, _, _ := mime.ParseMediaType(contentType)
573 isJSON := strings.Contains(mediaType, "application/json") || strings.HasSuffix(mediaType, "+json")
574 if !isJSON {
575 switch dst := cfg.ResponseBodyInto.(type) {
576 case *string:
577 *dst = string(contents)
578 case **string:
579 tmp := string(contents)
580 *dst = &tmp
581 case *[]byte:
582 *dst = contents
583 default:
584 return fmt.Errorf("expected destination type of 'string' or '[]byte' for responses with content-type '%s' that is not 'application/json'", contentType)
585 }
586 return nil
587 }
588
589 switch dst := cfg.ResponseBodyInto.(type) {
590 // If the response happens to be a byte array, deserialize the body as-is.
591 case *[]byte:
592 *dst = contents
593 default:
594 err = json.NewDecoder(bytes.NewReader(contents)).Decode(cfg.ResponseBodyInto)
595 if err != nil {
596 return fmt.Errorf("error parsing response json: %w", err)
597 }
598 }
599
600 return nil
601}
602
603func ExecuteNewRequest(ctx context.Context, method string, u string, body any, dst any, opts ...RequestOption) error {
604 cfg, err := NewRequestConfig(ctx, method, u, body, dst, opts...)
605 if err != nil {
606 return err
607 }
608 return cfg.Execute()
609}
610
611func (cfg *RequestConfig) Clone(ctx context.Context) *RequestConfig {
612 if cfg == nil {
613 return nil
614 }
615 req := cfg.Request.Clone(ctx)
616 var err error
617 if req.Body != nil {
618 req.Body, err = req.GetBody()
619 }
620 if err != nil {
621 return nil
622 }
623 new := &RequestConfig{
624 MaxRetries: cfg.MaxRetries,
625 RequestTimeout: cfg.RequestTimeout,
626 Context: ctx,
627 Request: req,
628 BaseURL: cfg.BaseURL,
629 HTTPClient: cfg.HTTPClient,
630 Middlewares: cfg.Middlewares,
631 APIKey: cfg.APIKey,
632 AdminAPIKey: cfg.AdminAPIKey,
633 Organization: cfg.Organization,
634 Project: cfg.Project,
635 WebhookSecret: cfg.WebhookSecret,
636 authHeaderOverride: cfg.authHeaderOverride,
637 authPreference: cfg.authPreference,
638 }
639
640 return new
641}
642
643func (cfg *RequestConfig) SetHeader(key, value string) {
644 cfg.Request.Header.Set(key, value)
645 if strings.EqualFold(key, "Authorization") {
646 cfg.authHeaderOverride = true
647 }
648}
649
650func (cfg *RequestConfig) AddHeader(key, value string) {
651 cfg.Request.Header.Add(key, value)
652 if strings.EqualFold(key, "Authorization") {
653 cfg.authHeaderOverride = true
654 }
655}
656
657func (cfg *RequestConfig) DelHeader(key string) {
658 cfg.Request.Header.Del(key)
659 if strings.EqualFold(key, "Authorization") {
660 cfg.authHeaderOverride = true
661 }
662}
663
664func (cfg *RequestConfig) SetAPIKey(value string) {
665 cfg.APIKey = value
666 cfg.authHeaderOverride = false
667 cfg.authPreference = authCredentialPreferenceBearer
668}
669
670func (cfg *RequestConfig) SetAdminAPIKey(value string) {
671 cfg.AdminAPIKey = value
672 cfg.authHeaderOverride = false
673 cfg.authPreference = authCredentialPreferenceAdmin
674}
675
676func (cfg *RequestConfig) Apply(opts ...RequestOption) error {
677 for _, opt := range opts {
678 err := opt.Apply(cfg)
679 if err != nil {
680 return err
681 }
682 }
683 return nil
684}
685
686// PreRequestOptions is used to collect all the options which need to be known before
687// a call to [RequestConfig.ExecuteNewRequest], such as path parameters
688// or global defaults.
689// PreRequestOptions will return a [RequestConfig] with the options applied.
690//
691// Only request option functions of type [PreRequestOptionFunc] are applied.
692func PreRequestOptions(opts ...RequestOption) (RequestConfig, error) {
693 cfg := RequestConfig{}
694 for _, opt := range opts {
695 if opt, ok := opt.(PreRequestOptionFunc); ok {
696 err := opt.Apply(&cfg)
697 if err != nil {
698 return cfg, err
699 }
700 }
701 }
702 return cfg, nil
703}
704
705// WithDefaultBaseURL returns a RequestOption that sets the client's default Base URL.
706// This is always overridden by setting a base URL with WithBaseURL.
707// WithBaseURL should be used instead of WithDefaultBaseURL except in internal code.
708func WithDefaultBaseURL(baseURL string) RequestOption {
709 u, err := url.Parse(baseURL)
710 return RequestOptionFunc(func(r *RequestConfig) error {
711 if err != nil {
712 return err
713 }
714 r.DefaultBaseURL = u
715 return nil
716 })
717}
718
719type Security struct {
720 BearerAuth bool
721 AdminAPIKeyAuth bool
722}
723
724type authCredentialPreference int
725
726const (
727 authCredentialPreferenceNone authCredentialPreference = iota
728 authCredentialPreferenceBearer
729 authCredentialPreferenceAdmin
730)
731
732func WithSecurity(security Security) RequestOption {
733 return RequestOptionFunc(func(r *RequestConfig) error {
734 r.Security = security
735 return nil
736 })
737}
738
739// WithBearerAuthSecurity() should only be used within a method, not provided to at
740// the client-level.
741func WithBearerAuthSecurity() RequestOption {
742 return RequestOptionFunc(func(r *RequestConfig) error {
743 r.Security = Security{
744 BearerAuth: true,
745 AdminAPIKeyAuth: false,
746 }
747 return nil
748 })
749}
750
751// WithAdminAPIKeyAuthSecurity() should only be used within a method, not provided
752// to at the client-level.
753func WithAdminAPIKeyAuthSecurity() RequestOption {
754 return RequestOptionFunc(func(r *RequestConfig) error {
755 r.Security = Security{
756 BearerAuth: false,
757 AdminAPIKeyAuth: true,
758 }
759 return nil
760 })
761}
762
763// WithBearerAuthPreference() should only be used when a request supports multiple
764// auth schemes and has no endpoint-specific security preference.
765func WithBearerAuthPreference() RequestOption {
766 return RequestOptionFunc(func(r *RequestConfig) error {
767 r.authPreference = authCredentialPreferenceBearer
768 return nil
769 })
770}
771
772func ApplySecurity(r RequestConfig) {
773 if r.authHeaderOverride {
774 return
775 }
776
777 if r.authPreference == authCredentialPreferenceBearer && r.Security.BearerAuth && r.APIKey != "" {
778 r.Request.Header.Set("authorization", fmt.Sprintf("Bearer %s", r.APIKey))
779 return
780 }
781
782 if r.authPreference == authCredentialPreferenceAdmin && r.Security.AdminAPIKeyAuth && r.AdminAPIKey != "" {
783 r.Request.Header.Set("authorization", fmt.Sprintf("Bearer %s", r.AdminAPIKey))
784 return
785 }
786
787 if r.Security.AdminAPIKeyAuth && r.AdminAPIKey != "" {
788 r.Request.Header.Set("authorization", fmt.Sprintf("Bearer %s", r.AdminAPIKey))
789 return
790 }
791
792 if r.Security.BearerAuth && r.APIKey != "" {
793 r.Request.Header.Set("authorization", fmt.Sprintf("Bearer %s", r.APIKey))
794 }
795}