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