requestoption.go

  1// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
  2
  3package option
  4
  5import (
  6	"bytes"
  7	"fmt"
  8	"io"
  9	"net/http"
 10	"net/url"
 11	"strings"
 12	"time"
 13
 14	"github.com/openai/openai-go/internal/requestconfig"
 15	"github.com/tidwall/sjson"
 16)
 17
 18// RequestOption is an option for the requests made by the openai API Client
 19// which can be supplied to clients, services, and methods. You can read more about this functional
 20// options pattern in our [README].
 21//
 22// [README]: https://pkg.go.dev/github.com/openai/openai-go#readme-requestoptions
 23type RequestOption = requestconfig.RequestOption
 24
 25// WithBaseURL returns a RequestOption that sets the BaseURL for the client.
 26//
 27// For security reasons, ensure that the base URL is trusted.
 28func WithBaseURL(base string) RequestOption {
 29	u, err := url.Parse(base)
 30	return requestconfig.RequestOptionFunc(func(r *requestconfig.RequestConfig) error {
 31		if err != nil {
 32			return fmt.Errorf("requestoption: WithBaseURL failed to parse url %s\n", err)
 33		}
 34
 35		if u.Path != "" && !strings.HasSuffix(u.Path, "/") {
 36			u.Path += "/"
 37		}
 38		r.BaseURL = u
 39		return nil
 40	})
 41}
 42
 43// HTTPClient is primarily used to describe an [*http.Client], but also
 44// supports custom implementations.
 45//
 46// For bespoke implementations, prefer using an [*http.Client] with a
 47// custom transport. See [http.RoundTripper] for further information.
 48type HTTPClient interface {
 49	Do(*http.Request) (*http.Response, error)
 50}
 51
 52// WithHTTPClient returns a RequestOption that changes the underlying http client used to make this
 53// request, which by default is [http.DefaultClient].
 54//
 55// For custom uses cases, it is recommended to provide an [*http.Client] with a custom
 56// [http.RoundTripper] as its transport, rather than directly implementing [HTTPClient].
 57func WithHTTPClient(client HTTPClient) RequestOption {
 58	return requestconfig.RequestOptionFunc(func(r *requestconfig.RequestConfig) error {
 59		if client == nil {
 60			return fmt.Errorf("requestoption: custom http client cannot be nil")
 61		}
 62
 63		if c, ok := client.(*http.Client); ok {
 64			// Prefer the native client if possible.
 65			r.HTTPClient = c
 66			r.CustomHTTPDoer = nil
 67		} else {
 68			r.CustomHTTPDoer = client
 69		}
 70
 71		return nil
 72	})
 73}
 74
 75// MiddlewareNext is a function which is called by a middleware to pass an HTTP request
 76// to the next stage in the middleware chain.
 77type MiddlewareNext = func(*http.Request) (*http.Response, error)
 78
 79// Middleware is a function which intercepts HTTP requests, processing or modifying
 80// them, and then passing the request to the next middleware or handler
 81// in the chain by calling the provided MiddlewareNext function.
 82type Middleware = func(*http.Request, MiddlewareNext) (*http.Response, error)
 83
 84// WithMiddleware returns a RequestOption that applies the given middleware
 85// to the requests made. Each middleware will execute in the order they were given.
 86func WithMiddleware(middlewares ...Middleware) RequestOption {
 87	return requestconfig.RequestOptionFunc(func(r *requestconfig.RequestConfig) error {
 88		r.Middlewares = append(r.Middlewares, middlewares...)
 89		return nil
 90	})
 91}
 92
 93// WithMaxRetries returns a RequestOption that sets the maximum number of retries that the client
 94// attempts to make. When given 0, the client only makes one request. By
 95// default, the client retries two times.
 96//
 97// WithMaxRetries panics when retries is negative.
 98func WithMaxRetries(retries int) RequestOption {
 99	if retries < 0 {
100		panic("option: cannot have fewer than 0 retries")
101	}
102	return requestconfig.RequestOptionFunc(func(r *requestconfig.RequestConfig) error {
103		r.MaxRetries = retries
104		return nil
105	})
106}
107
108// WithHeader returns a RequestOption that sets the header value to the associated key. It overwrites
109// any value if there was one already present.
110func WithHeader(key, value string) RequestOption {
111	return requestconfig.RequestOptionFunc(func(r *requestconfig.RequestConfig) error {
112		r.Request.Header.Set(key, value)
113		return nil
114	})
115}
116
117// WithHeaderAdd returns a RequestOption that adds the header value to the associated key. It appends
118// onto any existing values.
119func WithHeaderAdd(key, value string) RequestOption {
120	return requestconfig.RequestOptionFunc(func(r *requestconfig.RequestConfig) error {
121		r.Request.Header.Add(key, value)
122		return nil
123	})
124}
125
126// WithHeaderDel returns a RequestOption that deletes the header value(s) associated with the given key.
127func WithHeaderDel(key string) RequestOption {
128	return requestconfig.RequestOptionFunc(func(r *requestconfig.RequestConfig) error {
129		r.Request.Header.Del(key)
130		return nil
131	})
132}
133
134// WithQuery returns a RequestOption that sets the query value to the associated key. It overwrites
135// any value if there was one already present.
136func WithQuery(key, value string) RequestOption {
137	return requestconfig.RequestOptionFunc(func(r *requestconfig.RequestConfig) error {
138		query := r.Request.URL.Query()
139		query.Set(key, value)
140		r.Request.URL.RawQuery = query.Encode()
141		return nil
142	})
143}
144
145// WithQueryAdd returns a RequestOption that adds the query value to the associated key. It appends
146// onto any existing values.
147func WithQueryAdd(key, value string) RequestOption {
148	return requestconfig.RequestOptionFunc(func(r *requestconfig.RequestConfig) error {
149		query := r.Request.URL.Query()
150		query.Add(key, value)
151		r.Request.URL.RawQuery = query.Encode()
152		return nil
153	})
154}
155
156// WithQueryDel returns a RequestOption that deletes the query value(s) associated with the key.
157func WithQueryDel(key string) RequestOption {
158	return requestconfig.RequestOptionFunc(func(r *requestconfig.RequestConfig) error {
159		query := r.Request.URL.Query()
160		query.Del(key)
161		r.Request.URL.RawQuery = query.Encode()
162		return nil
163	})
164}
165
166// WithJSONSet returns a RequestOption that sets the body's JSON value associated with the key.
167// The key accepts a string as defined by the [sjson format].
168//
169// [sjson format]: https://github.com/tidwall/sjson
170func WithJSONSet(key string, value any) RequestOption {
171	return requestconfig.RequestOptionFunc(func(r *requestconfig.RequestConfig) (err error) {
172		var b []byte
173
174		if r.Body == nil {
175			b, err = sjson.SetBytes(nil, key, value)
176			if err != nil {
177				return err
178			}
179		} else if buffer, ok := r.Body.(*bytes.Buffer); ok {
180			b = buffer.Bytes()
181			b, err = sjson.SetBytes(b, key, value)
182			if err != nil {
183				return err
184			}
185		} else {
186			return fmt.Errorf("cannot use WithJSONSet on a body that is not serialized as *bytes.Buffer")
187		}
188
189		r.Body = bytes.NewBuffer(b)
190		return nil
191	})
192}
193
194// WithJSONDel returns a RequestOption that deletes the body's JSON value associated with the key.
195// The key accepts a string as defined by the [sjson format].
196//
197// [sjson format]: https://github.com/tidwall/sjson
198func WithJSONDel(key string) RequestOption {
199	return requestconfig.RequestOptionFunc(func(r *requestconfig.RequestConfig) (err error) {
200		if buffer, ok := r.Body.(*bytes.Buffer); ok {
201			b := buffer.Bytes()
202			b, err = sjson.DeleteBytes(b, key)
203			if err != nil {
204				return err
205			}
206			r.Body = bytes.NewBuffer(b)
207			return nil
208		}
209
210		return fmt.Errorf("cannot use WithJSONDel on a body that is not serialized as *bytes.Buffer")
211	})
212}
213
214// WithResponseBodyInto returns a RequestOption that overwrites the deserialization target with
215// the given destination. If provided, we don't deserialize into the default struct.
216func WithResponseBodyInto(dst any) RequestOption {
217	return requestconfig.RequestOptionFunc(func(r *requestconfig.RequestConfig) error {
218		r.ResponseBodyInto = dst
219		return nil
220	})
221}
222
223// WithResponseInto returns a RequestOption that copies the [*http.Response] into the given address.
224func WithResponseInto(dst **http.Response) RequestOption {
225	return requestconfig.RequestOptionFunc(func(r *requestconfig.RequestConfig) error {
226		r.ResponseInto = dst
227		return nil
228	})
229}
230
231// WithRequestBody returns a RequestOption that provides a custom serialized body with the given
232// content type.
233//
234// body accepts an io.Reader or raw []bytes.
235func WithRequestBody(contentType string, body any) RequestOption {
236	return requestconfig.RequestOptionFunc(func(r *requestconfig.RequestConfig) error {
237		if reader, ok := body.(io.Reader); ok {
238			r.Body = reader
239			return r.Apply(WithHeader("Content-Type", contentType))
240		}
241
242		if b, ok := body.([]byte); ok {
243			r.Body = bytes.NewBuffer(b)
244			return r.Apply(WithHeader("Content-Type", contentType))
245		}
246
247		return fmt.Errorf("body must be a byte slice or implement io.Reader")
248	})
249}
250
251// WithRequestTimeout returns a RequestOption that sets the timeout for
252// each request attempt. This should be smaller than the timeout defined in
253// the context, which spans all retries.
254func WithRequestTimeout(dur time.Duration) RequestOption {
255	return requestconfig.RequestOptionFunc(func(r *requestconfig.RequestConfig) error {
256		r.RequestTimeout = dur
257		return nil
258	})
259}
260
261// WithEnvironmentProduction returns a RequestOption that sets the current
262// environment to be the "production" environment. An environment specifies which base URL
263// to use by default.
264func WithEnvironmentProduction() RequestOption {
265	return requestconfig.WithDefaultBaseURL("https://api.openai.com/v1/")
266}
267
268// WithAPIKey returns a RequestOption that sets the client setting "api_key".
269func WithAPIKey(value string) RequestOption {
270	return requestconfig.RequestOptionFunc(func(r *requestconfig.RequestConfig) error {
271		r.APIKey = value
272		return r.Apply(WithHeader("authorization", fmt.Sprintf("Bearer %s", r.APIKey)))
273	})
274}
275
276// WithOrganization returns a RequestOption that sets the client setting "organization".
277func WithOrganization(value string) RequestOption {
278	return requestconfig.RequestOptionFunc(func(r *requestconfig.RequestConfig) error {
279		r.Organization = value
280		return r.Apply(WithHeader("OpenAI-Organization", value))
281	})
282}
283
284// WithProject returns a RequestOption that sets the client setting "project".
285func WithProject(value string) RequestOption {
286	return requestconfig.RequestOptionFunc(func(r *requestconfig.RequestConfig) error {
287		r.Project = value
288		return r.Apply(WithHeader("OpenAI-Project", value))
289	})
290}
291
292// WithWebhookSecret returns a RequestOption that sets the client setting "webhook_secret".
293func WithWebhookSecret(value string) requestconfig.PreRequestOptionFunc {
294	return requestconfig.PreRequestOptionFunc(func(r *requestconfig.RequestConfig) error {
295		r.WebhookSecret = value
296		return nil
297	})
298}