Skip to content

Commit ba0c8cc

Browse files
committed
Add support for per-request extra_headers parameter
Allow passing custom HTTP headers on individual API calls rather than only at client initialization time. This enables varying headers per request while reusing a single cached client instance. Changes: - HTTP#get, #post, #json_post, #multipart_post, #delete accept extra_headers: {} - Client#chat, #embeddings, #completions, #moderations accept extra_headers: {} - Added tests for extra_headers functionality
1 parent 6c834c2 commit ba0c8cc

File tree

3 files changed

+63
-20
lines changed

3 files changed

+63
-20
lines changed

lib/openai/client.rb

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,16 @@ def initialize(config = {}, &faraday_middleware)
2121
@faraday_middleware = faraday_middleware
2222
end
2323

24-
def chat(parameters: {})
25-
json_post(path: "/chat/completions", parameters: parameters)
24+
def chat(parameters: {}, extra_headers: {})
25+
json_post(path: "/chat/completions", parameters: parameters, extra_headers: extra_headers)
2626
end
2727

28-
def embeddings(parameters: {})
29-
json_post(path: "/embeddings", parameters: parameters)
28+
def embeddings(parameters: {}, extra_headers: {})
29+
json_post(path: "/embeddings", parameters: parameters, extra_headers: extra_headers)
3030
end
3131

32-
def completions(parameters: {})
33-
json_post(path: "/completions", parameters: parameters)
32+
def completions(parameters: {}, extra_headers: {})
33+
json_post(path: "/completions", parameters: parameters, extra_headers: extra_headers)
3434
end
3535

3636
def audio
@@ -97,8 +97,8 @@ def realtime
9797
@realtime ||= OpenAI::Realtime.new(client: self)
9898
end
9999

100-
def moderations(parameters: {})
101-
json_post(path: "/moderations", parameters: parameters)
100+
def moderations(parameters: {}, extra_headers: {})
101+
json_post(path: "/moderations", parameters: parameters, extra_headers: extra_headers)
102102
end
103103

104104
def usage

lib/openai/http.rb

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,35 +6,35 @@ module OpenAI
66
module HTTP
77
include HTTPHeaders
88

9-
def get(path:, parameters: nil)
9+
def get(path:, parameters: nil, extra_headers: {})
1010
parse_json(conn.get(uri(path: path), parameters) do |req|
11-
req.headers = headers
11+
req.headers = headers.merge(extra_headers)
1212
end&.body)
1313
end
1414

15-
def post(path:)
15+
def post(path:, extra_headers: {})
1616
parse_json(conn.post(uri(path: path)) do |req|
17-
req.headers = headers
17+
req.headers = headers.merge(extra_headers)
1818
end&.body)
1919
end
2020

21-
def json_post(path:, parameters:, query_parameters: {})
21+
def json_post(path:, parameters:, query_parameters: {}, extra_headers: {})
2222
parse_json(conn.post(uri(path: path)) do |req|
23-
configure_json_post_request(req, parameters)
23+
configure_json_post_request(req, parameters, extra_headers: extra_headers)
2424
req.params = req.params.merge(query_parameters)
2525
end&.body)
2626
end
2727

28-
def multipart_post(path:, parameters: nil)
28+
def multipart_post(path:, parameters: nil, extra_headers: {})
2929
parse_json(conn(multipart: true).post(uri(path: path)) do |req|
30-
req.headers = headers.merge({ "Content-Type" => "multipart/form-data" })
30+
req.headers = headers.merge("Content-Type" => "multipart/form-data").merge(extra_headers)
3131
req.body = multipart_parameters(parameters)
3232
end&.body)
3333
end
3434

35-
def delete(path:)
35+
def delete(path:, extra_headers: {})
3636
parse_json(conn.delete(uri(path: path)) do |req|
37-
req.headers = headers
37+
req.headers = headers.merge(extra_headers)
3838
end&.body)
3939
end
4040

@@ -95,7 +95,7 @@ def multipart_parameters(parameters)
9595
end
9696
end
9797

98-
def configure_json_post_request(req, parameters)
98+
def configure_json_post_request(req, parameters, extra_headers: {})
9999
req_parameters = parameters.dup
100100

101101
if parameters[:stream].respond_to?(:call)
@@ -105,7 +105,7 @@ def configure_json_post_request(req, parameters)
105105
raise ArgumentError, "The stream parameter must be a Proc or have a #call method"
106106
end
107107

108-
req.headers = headers
108+
req.headers = headers.merge(extra_headers)
109109
req.body = req_parameters.to_json
110110
end
111111
end

spec/openai/client/http_spec.rb

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,47 @@
11
RSpec.describe OpenAI::HTTP do
2+
describe "extra_headers" do
3+
include WebMock::API
4+
5+
let(:client) { OpenAI::Client.new }
6+
let(:custom_headers) { { "X-Custom-Header" => "custom-value", "X-Another" => "another-value" } }
7+
let(:chat_url) { "https://api.openai.com/v1/chat/completions" }
8+
9+
before do
10+
VCR.turn_off!
11+
WebMock.disable_net_connect!
12+
stub_request(:post, chat_url)
13+
.to_return(status: 200, body: { choices: [] }.to_json, headers: {})
14+
end
15+
16+
after do
17+
WebMock.reset!
18+
VCR.turn_on!
19+
end
20+
21+
it "merges extra_headers into the request" do
22+
client.chat(parameters: { model: "gpt-4", messages: [] }, extra_headers: custom_headers)
23+
24+
assert_requested(:post, chat_url, headers: custom_headers)
25+
end
26+
27+
it "allows extra_headers to override default headers" do
28+
client.chat(
29+
parameters: { model: "gpt-4", messages: [] },
30+
extra_headers: { "Content-Type" => "application/json; charset=utf-8" }
31+
)
32+
33+
assert_requested(
34+
:post, chat_url, headers: { "Content-Type" => "application/json; charset=utf-8" }
35+
)
36+
end
37+
38+
it "works without extra_headers (backward compatible)" do
39+
client.chat(parameters: { model: "gpt-4", messages: [] })
40+
41+
assert_requested(:post, chat_url)
42+
end
43+
end
44+
245
describe "with an aggressive timeout" do
346
let(:timeout_errors) { [Faraday::ConnectionFailed, Faraday::TimeoutError] }
447
let(:timeout) { 0 }

0 commit comments

Comments
 (0)