Skip to content

Commit c34bc77

Browse files
authored
Add testable request builder (#162)
* Add testable request builder * improve tests
1 parent 53d195c commit c34bc77

13 files changed

+205
-152
lines changed

Diff for: api.go

+5-15
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package openai
22

33
import (
4-
"bytes"
54
"context"
65
"encoding/json"
76
"fmt"
@@ -12,7 +11,7 @@ import (
1211
type Client struct {
1312
config ClientConfig
1413

15-
marshaller marshaller
14+
requestBuilder requestBuilder
1615
}
1716

1817
// NewClient creates new OpenAI API client.
@@ -24,8 +23,8 @@ func NewClient(authToken string) *Client {
2423
// NewClientWithConfig creates new OpenAI API client for specified config.
2524
func NewClientWithConfig(config ClientConfig) *Client {
2625
return &Client{
27-
config: config,
28-
marshaller: &jsonMarshaller{},
26+
config: config,
27+
requestBuilder: newRequestBuilder(),
2928
}
3029
}
3130

@@ -91,17 +90,8 @@ func (c *Client) newStreamRequest(
9190
ctx context.Context,
9291
method string,
9392
urlSuffix string,
94-
body interface{}) (*http.Request, error) {
95-
var reqBody []byte
96-
if body != nil {
97-
var err error
98-
reqBody, err = c.marshaller.marshal(body)
99-
if err != nil {
100-
return nil, err
101-
}
102-
}
103-
104-
req, err := http.NewRequestWithContext(ctx, method, c.fullURL(urlSuffix), bytes.NewBuffer(reqBody))
93+
body any) (*http.Request, error) {
94+
req, err := c.requestBuilder.build(ctx, method, c.fullURL(urlSuffix), body)
10595
if err != nil {
10696
return nil, err
10797
}

Diff for: chat.go

+1-8
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package openai
22

33
import (
4-
"bytes"
54
"context"
65
"errors"
76
"net/http"
@@ -72,14 +71,8 @@ func (c *Client) CreateChatCompletion(
7271
return
7372
}
7473

75-
var reqBytes []byte
76-
reqBytes, err = c.marshaller.marshal(request)
77-
if err != nil {
78-
return
79-
}
80-
8174
urlSuffix := "/chat/completions"
82-
req, err := http.NewRequestWithContext(ctx, http.MethodPost, c.fullURL(urlSuffix), bytes.NewBuffer(reqBytes))
75+
req, err := c.requestBuilder.build(ctx, http.MethodPost, c.fullURL(urlSuffix), request)
8376
if err != nil {
8477
return
8578
}

Diff for: completion.go

+1-8
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package openai
22

33
import (
4-
"bytes"
54
"context"
65
"errors"
76
"net/http"
@@ -105,14 +104,8 @@ func (c *Client) CreateCompletion(
105104
return
106105
}
107106

108-
var reqBytes []byte
109-
reqBytes, err = c.marshaller.marshal(request)
110-
if err != nil {
111-
return
112-
}
113-
114107
urlSuffix := "/completions"
115-
req, err := http.NewRequestWithContext(ctx, http.MethodPost, c.fullURL(urlSuffix), bytes.NewBuffer(reqBytes))
108+
req, err := c.requestBuilder.build(ctx, http.MethodPost, c.fullURL(urlSuffix), request)
116109
if err != nil {
117110
return
118111
}

Diff for: edits.go

+1-8
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package openai
22

33
import (
4-
"bytes"
54
"context"
65
"net/http"
76
)
@@ -32,13 +31,7 @@ type EditsResponse struct {
3231

3332
// Perform an API call to the Edits endpoint.
3433
func (c *Client) Edits(ctx context.Context, request EditsRequest) (response EditsResponse, err error) {
35-
var reqBytes []byte
36-
reqBytes, err = c.marshaller.marshal(request)
37-
if err != nil {
38-
return
39-
}
40-
41-
req, err := http.NewRequestWithContext(ctx, http.MethodPost, c.fullURL("/edits"), bytes.NewBuffer(reqBytes))
34+
req, err := c.requestBuilder.build(ctx, http.MethodPost, c.fullURL("/edits"), request)
4235
if err != nil {
4336
return
4437
}

Diff for: embeddings.go

+1-9
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package openai
22

33
import (
4-
"bytes"
54
"context"
65
"net/http"
76
)
@@ -133,14 +132,7 @@ type EmbeddingRequest struct {
133132
// CreateEmbeddings returns an EmbeddingResponse which will contain an Embedding for every item in |request.Input|.
134133
// https://beta.openai.com/docs/api-reference/embeddings/create
135134
func (c *Client) CreateEmbeddings(ctx context.Context, request EmbeddingRequest) (resp EmbeddingResponse, err error) {
136-
var reqBytes []byte
137-
reqBytes, err = c.marshaller.marshal(request)
138-
if err != nil {
139-
return
140-
}
141-
142-
urlSuffix := "/embeddings"
143-
req, err := http.NewRequestWithContext(ctx, http.MethodPost, c.fullURL(urlSuffix), bytes.NewBuffer(reqBytes))
135+
req, err := c.requestBuilder.build(ctx, http.MethodPost, c.fullURL("/embeddings"), request)
144136
if err != nil {
145137
return
146138
}

Diff for: engines.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ type EnginesList struct {
2222
// ListEngines Lists the currently available engines, and provides basic
2323
// information about each option such as the owner and availability.
2424
func (c *Client) ListEngines(ctx context.Context) (engines EnginesList, err error) {
25-
req, err := http.NewRequestWithContext(ctx, http.MethodGet, c.fullURL("/engines"), nil)
25+
req, err := c.requestBuilder.build(ctx, http.MethodGet, c.fullURL("/engines"), nil)
2626
if err != nil {
2727
return
2828
}
@@ -38,7 +38,7 @@ func (c *Client) GetEngine(
3838
engineID string,
3939
) (engine Engine, err error) {
4040
urlSuffix := fmt.Sprintf("/engines/%s", engineID)
41-
req, err := http.NewRequestWithContext(ctx, http.MethodGet, c.fullURL(urlSuffix), nil)
41+
req, err := c.requestBuilder.build(ctx, http.MethodGet, c.fullURL(urlSuffix), nil)
4242
if err != nil {
4343
return
4444
}

Diff for: files.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ func (c *Client) CreateFile(ctx context.Context, request FileRequest) (file File
112112

113113
// DeleteFile deletes an existing file.
114114
func (c *Client) DeleteFile(ctx context.Context, fileID string) (err error) {
115-
req, err := http.NewRequestWithContext(ctx, http.MethodDelete, c.fullURL("/files/"+fileID), nil)
115+
req, err := c.requestBuilder.build(ctx, http.MethodDelete, c.fullURL("/files/"+fileID), nil)
116116
if err != nil {
117117
return
118118
}
@@ -124,7 +124,7 @@ func (c *Client) DeleteFile(ctx context.Context, fileID string) (err error) {
124124
// ListFiles Lists the currently available files,
125125
// and provides basic information about each file such as the file name and purpose.
126126
func (c *Client) ListFiles(ctx context.Context) (files FilesList, err error) {
127-
req, err := http.NewRequestWithContext(ctx, http.MethodGet, c.fullURL("/files"), nil)
127+
req, err := c.requestBuilder.build(ctx, http.MethodGet, c.fullURL("/files"), nil)
128128
if err != nil {
129129
return
130130
}
@@ -137,7 +137,7 @@ func (c *Client) ListFiles(ctx context.Context) (files FilesList, err error) {
137137
// such as the file name and purpose.
138138
func (c *Client) GetFile(ctx context.Context, fileID string) (file File, err error) {
139139
urlSuffix := fmt.Sprintf("/files/%s", fileID)
140-
req, err := http.NewRequestWithContext(ctx, http.MethodGet, c.fullURL(urlSuffix), nil)
140+
req, err := c.requestBuilder.build(ctx, http.MethodGet, c.fullURL(urlSuffix), nil)
141141
if err != nil {
142142
return
143143
}

Diff for: fine_tunes.go

+6-13
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package openai
22

33
import (
4-
"bytes"
54
"context"
65
"fmt"
76
"net/http"
@@ -68,14 +67,8 @@ type FineTuneDeleteResponse struct {
6867
}
6968

7069
func (c *Client) CreateFineTune(ctx context.Context, request FineTuneRequest) (response FineTune, err error) {
71-
var reqBytes []byte
72-
reqBytes, err = c.marshaller.marshal(request)
73-
if err != nil {
74-
return
75-
}
76-
7770
urlSuffix := "/fine-tunes"
78-
req, err := http.NewRequestWithContext(ctx, http.MethodPost, c.fullURL(urlSuffix), bytes.NewBuffer(reqBytes))
71+
req, err := c.requestBuilder.build(ctx, http.MethodPost, c.fullURL(urlSuffix), request)
7972
if err != nil {
8073
return
8174
}
@@ -86,7 +79,7 @@ func (c *Client) CreateFineTune(ctx context.Context, request FineTuneRequest) (r
8679

8780
// CancelFineTune cancel a fine-tune job.
8881
func (c *Client) CancelFineTune(ctx context.Context, fineTuneID string) (response FineTune, err error) {
89-
req, err := http.NewRequestWithContext(ctx, http.MethodPost, c.fullURL("/fine-tunes/"+fineTuneID+"/cancel"), nil)
82+
req, err := c.requestBuilder.build(ctx, http.MethodPost, c.fullURL("/fine-tunes/"+fineTuneID+"/cancel"), nil)
9083
if err != nil {
9184
return
9285
}
@@ -96,7 +89,7 @@ func (c *Client) CancelFineTune(ctx context.Context, fineTuneID string) (respons
9689
}
9790

9891
func (c *Client) ListFineTunes(ctx context.Context) (response FineTuneList, err error) {
99-
req, err := http.NewRequestWithContext(ctx, http.MethodGet, c.fullURL("/fine-tunes"), nil)
92+
req, err := c.requestBuilder.build(ctx, http.MethodGet, c.fullURL("/fine-tunes"), nil)
10093
if err != nil {
10194
return
10295
}
@@ -107,7 +100,7 @@ func (c *Client) ListFineTunes(ctx context.Context) (response FineTuneList, err
107100

108101
func (c *Client) GetFineTune(ctx context.Context, fineTuneID string) (response FineTune, err error) {
109102
urlSuffix := fmt.Sprintf("/fine-tunes/%s", fineTuneID)
110-
req, err := http.NewRequestWithContext(ctx, http.MethodGet, c.fullURL(urlSuffix), nil)
103+
req, err := c.requestBuilder.build(ctx, http.MethodGet, c.fullURL(urlSuffix), nil)
111104
if err != nil {
112105
return
113106
}
@@ -117,7 +110,7 @@ func (c *Client) GetFineTune(ctx context.Context, fineTuneID string) (response F
117110
}
118111

119112
func (c *Client) DeleteFineTune(ctx context.Context, fineTuneID string) (response FineTuneDeleteResponse, err error) {
120-
req, err := http.NewRequestWithContext(ctx, http.MethodDelete, c.fullURL("/fine-tunes/"+fineTuneID), nil)
113+
req, err := c.requestBuilder.build(ctx, http.MethodDelete, c.fullURL("/fine-tunes/"+fineTuneID), nil)
121114
if err != nil {
122115
return
123116
}
@@ -127,7 +120,7 @@ func (c *Client) DeleteFineTune(ctx context.Context, fineTuneID string) (respons
127120
}
128121

129122
func (c *Client) ListFineTuneEvents(ctx context.Context, fineTuneID string) (response FineTuneEventList, err error) {
130-
req, err := http.NewRequestWithContext(ctx, http.MethodGet, c.fullURL("/fine-tunes/"+fineTuneID+"/events"), nil)
123+
req, err := c.requestBuilder.build(ctx, http.MethodGet, c.fullURL("/fine-tunes/"+fineTuneID+"/events"), nil)
131124
if err != nil {
132125
return
133126
}

Diff for: image.go

+1-7
Original file line numberDiff line numberDiff line change
@@ -45,14 +45,8 @@ type ImageResponseDataInner struct {
4545

4646
// CreateImage - API call to create an image. This is the main endpoint of the DALL-E API.
4747
func (c *Client) CreateImage(ctx context.Context, request ImageRequest) (response ImageResponse, err error) {
48-
var reqBytes []byte
49-
reqBytes, err = c.marshaller.marshal(request)
50-
if err != nil {
51-
return
52-
}
53-
5448
urlSuffix := "/images/generations"
55-
req, err := http.NewRequestWithContext(ctx, http.MethodPost, c.fullURL(urlSuffix), bytes.NewBuffer(reqBytes))
49+
req, err := c.requestBuilder.build(ctx, http.MethodPost, c.fullURL(urlSuffix), request)
5650
if err != nil {
5751
return
5852
}

Diff for: marshaller_test.go

-71
This file was deleted.

Diff for: moderation.go

+1-8
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package openai
22

33
import (
4-
"bytes"
54
"context"
65
"net/http"
76
)
@@ -51,13 +50,7 @@ type ModerationResponse struct {
5150
// Moderations — perform a moderation api call over a string.
5251
// Input can be an array or slice but a string will reduce the complexity.
5352
func (c *Client) Moderations(ctx context.Context, request ModerationRequest) (response ModerationResponse, err error) {
54-
var reqBytes []byte
55-
reqBytes, err = c.marshaller.marshal(request)
56-
if err != nil {
57-
return
58-
}
59-
60-
req, err := http.NewRequestWithContext(ctx, http.MethodPost, c.fullURL("/moderations"), bytes.NewBuffer(reqBytes))
53+
req, err := c.requestBuilder.build(ctx, http.MethodPost, c.fullURL("/moderations"), request)
6154
if err != nil {
6255
return
6356
}

0 commit comments

Comments
 (0)