Skip to content

Commit b249e83

Browse files
committed
Fix: Content-type request header is missing
1 parent 3b6c40e commit b249e83

2 files changed

Lines changed: 36 additions & 17 deletions

File tree

src/Client.php

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727
use Psr\Http\Message\StreamFactoryInterface;
2828
use RuntimeException;
2929

30-
use function array_map;
3130
use function curl_close;
3231
use function curl_exec;
3332
use function curl_getinfo;
@@ -43,7 +42,7 @@ class Client implements GeminiClientInterface
4342
private string $baseUrl = 'https://generativelanguage.googleapis.com';
4443

4544
/**
46-
* @var array<string, string>
45+
* @var array<string, string|string[]>
4746
*/
4847
private array $requestHeaders = [];
4948

@@ -137,13 +136,11 @@ public function generateContentStream(
137136
throw new RuntimeException('Gemini API cannot initialize streaming content request');
138137
}
139138

140-
$headers = $this->requestHeaders + [
141-
'content-type' => 'application/json',
142-
self::API_KEY_HEADER_NAME => $this->apiKey,
143-
];
144139
$headerLines = [];
145-
foreach ($headers as $name => $value) {
146-
$headerLines[] = "{$name}: {$value}";
140+
foreach ($this->getRequestHeaders() as $name => $values) {
141+
foreach ((array) $values as $value) {
142+
$headerLines[] = "{$name}: {$value}";
143+
}
147144
}
148145

149146
curl_setopt($ch, CURLOPT_URL, "{$this->baseUrl}/v1/{$request->getOperation()}");
@@ -198,17 +195,32 @@ public function withBaseUrl(string $baseUrl): self
198195
}
199196

200197
/**
201-
* @param array<string, string> $headers
198+
* @param array<string, string|string[]> $headers
202199
* @return self
203200
*/
204201
public function withRequestHeaders(array $headers): self
205202
{
206203
$clone = clone $this;
207-
$clone->requestHeaders = array_map(strtolower(...), $headers);
204+
$clone->requestHeaders = [];
205+
206+
foreach ($headers as $name => $value) {
207+
$clone->requestHeaders[strtolower($name)] = $value;
208+
}
208209

209210
return $clone;
210211
}
211212

213+
/**
214+
* @return array<string, string|string[]>
215+
*/
216+
private function getRequestHeaders(): array
217+
{
218+
return $this->requestHeaders + [
219+
'content-type' => 'application/json',
220+
self::API_KEY_HEADER_NAME => $this->apiKey,
221+
];
222+
}
223+
212224
/**
213225
* @throws ClientExceptionInterface
214226
*/
@@ -220,10 +232,9 @@ private function doRequest(RequestInterface $request): string
220232

221233
$uri = "{$this->baseUrl}/v1/{$request->getOperation()}";
222234
$httpRequest = $this->requestFactory
223-
->createRequest($request->getHttpMethod(), $uri)
224-
->withAddedHeader(self::API_KEY_HEADER_NAME, $this->apiKey);
235+
->createRequest($request->getHttpMethod(), $uri);
225236

226-
foreach ($this->requestHeaders as $name => $value) {
237+
foreach ($this->getRequestHeaders() as $name => $value) {
227238
$httpRequest = $httpRequest->withAddedHeader($name, $value);
228239
}
229240

tests/Unit/ClientTest.php

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,9 @@ public function testGenerateContent()
120120
->with('POST', 'https://generativelanguage.googleapis.com/v1/models/gemini-pro:generateContent')
121121
->willReturn($httpRequest);
122122

123-
$httpRequest = $httpRequest->withAddedHeader(GeminiAPIClientInterface::API_KEY_HEADER_NAME, 'test-api-key');
123+
$httpRequest = $httpRequest
124+
->withAddedHeader(GeminiAPIClientInterface::API_KEY_HEADER_NAME, 'test-api-key')
125+
->withAddedHeader('content-type', 'application/json');
124126

125127
$stream = Utils::streamFor('{"model":"models\/gemini-pro","contents":[{"parts":[{"text":"this is a text"}],"role":"user"}]}');
126128
$streamFactory = $this->createMock(StreamFactoryInterface::class);
@@ -173,7 +175,9 @@ public function testEmbedContent()
173175
->with('POST', 'https://generativelanguage.googleapis.com/v1/models/embedding-001:embedContent')
174176
->willReturn($httpRequest);
175177

176-
$httpRequest = $httpRequest->withAddedHeader(GeminiAPIClientInterface::API_KEY_HEADER_NAME, 'test-api-key');
178+
$httpRequest = $httpRequest
179+
->withAddedHeader(GeminiAPIClientInterface::API_KEY_HEADER_NAME, 'test-api-key')
180+
->withAddedHeader('content-type', 'application/json');
177181

178182
$stream = Utils::streamFor('{"content":{"parts":[{"text":"this is a text"}],"role":"user"}}');
179183
$streamFactory = $this->createMock(StreamFactoryInterface::class);
@@ -221,7 +225,9 @@ public function testCountTokens()
221225
->with('POST', 'https://generativelanguage.googleapis.com/v1/models/gemini-pro:countTokens')
222226
->willReturn($httpRequest);
223227

224-
$httpRequest = $httpRequest->withAddedHeader(GeminiAPIClientInterface::API_KEY_HEADER_NAME, 'test-api-key');
228+
$httpRequest = $httpRequest
229+
->withAddedHeader(GeminiAPIClientInterface::API_KEY_HEADER_NAME, 'test-api-key')
230+
->withAddedHeader('content-type', 'application/json');
225231

226232
$stream = Utils::streamFor('{"model":"models\/gemini-pro","contents":[{"parts":[{"text":"this is a text"}],"role":"user"}]}');
227233
$streamFactory = $this->createMock(StreamFactoryInterface::class);
@@ -300,7 +306,9 @@ public function testListModels()
300306
->with('GET', 'https://generativelanguage.googleapis.com/v1/models')
301307
->willReturn($httpRequest);
302308

303-
$httpRequest = $httpRequest->withAddedHeader(GeminiAPIClientInterface::API_KEY_HEADER_NAME, 'test-api-key');
309+
$httpRequest = $httpRequest
310+
->withAddedHeader(GeminiAPIClientInterface::API_KEY_HEADER_NAME, 'test-api-key')
311+
->withAddedHeader('content-type', 'application/json');
304312

305313
$httpClient = $this->createMock(HttpClientInterface::class);
306314
$httpClient->expects(self::once())

0 commit comments

Comments
 (0)