sdk: allow specifying run time headers in http client (#4000)

This PR only allows this in the HTTP client. 

I can follow up with a PR to allow throughout the entire API.

The use case is to allow instantiating the client once (w/ a single connection pool), but allowing changing api keys and any other headers at run time
This commit is contained in:
Eugene Yurtsev
2025-03-24 14:47:35 -04:00
committed by GitHub
parent c84f35eff5
commit addb491cfd
+93 -31
View File
@@ -208,9 +208,15 @@ class HttpClient:
def __init__(self, client: httpx.AsyncClient) -> None:
self.client = client
async def get(self, path: str, *, params: Optional[QueryParamTypes] = None) -> Any:
async def get(
self,
path: str,
*,
params: Optional[QueryParamTypes] = None,
headers: Optional[dict[str, str]] = None,
) -> Any:
"""Send a GET request."""
r = await self.client.get(path, params=params)
r = await self.client.get(path, params=params, headers=headers)
try:
r.raise_for_status()
except httpx.HTTPStatusError as e:
@@ -222,13 +228,22 @@ class HttpClient:
raise e
return await adecode_json(r)
async def post(self, path: str, *, json: Optional[dict]) -> Any:
async def post(
self,
path: str,
*,
json: Optional[dict],
headers: Optional[dict[str, str]] = None,
) -> Any:
"""Send a POST request."""
if json is not None:
headers, content = await aencode_json(json)
request_headers, content = await aencode_json(json)
else:
headers, content = {}, b""
r = await self.client.post(path, headers=headers, content=content)
request_headers, content = {}, b""
# Merge headers, with runtime headers taking precedence
if headers:
request_headers.update(headers)
r = await self.client.post(path, headers=request_headers, content=content)
try:
r.raise_for_status()
except httpx.HTTPStatusError as e:
@@ -240,10 +255,14 @@ class HttpClient:
raise e
return await adecode_json(r)
async def put(self, path: str, *, json: dict) -> Any:
async def put(
self, path: str, *, json: dict, headers: Optional[dict[str, str]] = None
) -> Any:
"""Send a PUT request."""
headers, content = await aencode_json(json)
r = await self.client.put(path, headers=headers, content=content)
request_headers, content = await aencode_json(json)
if headers:
request_headers.update(headers)
r = await self.client.put(path, headers=request_headers, content=content)
try:
r.raise_for_status()
except httpx.HTTPStatusError as e:
@@ -255,10 +274,14 @@ class HttpClient:
raise e
return await adecode_json(r)
async def patch(self, path: str, *, json: dict) -> Any:
async def patch(
self, path: str, *, json: dict, headers: Optional[dict[str, str]] = None
) -> Any:
"""Send a PATCH request."""
headers, content = await aencode_json(json)
r = await self.client.patch(path, headers=headers, content=content)
request_headers, content = await aencode_json(json)
if headers:
request_headers.update(headers)
r = await self.client.patch(path, headers=request_headers, content=content)
try:
r.raise_for_status()
except httpx.HTTPStatusError as e:
@@ -270,9 +293,15 @@ class HttpClient:
raise e
return await adecode_json(r)
async def delete(self, path: str, *, json: Optional[Any] = None) -> None:
async def delete(
self,
path: str,
*,
json: Optional[Any] = None,
headers: Optional[dict[str, str]] = None,
) -> None:
"""Send a DELETE request."""
r = await self.client.request("DELETE", path, json=json)
r = await self.client.request("DELETE", path, json=json, headers=headers)
try:
r.raise_for_status()
except httpx.HTTPStatusError as e:
@@ -290,14 +319,18 @@ class HttpClient:
*,
json: Optional[dict] = None,
params: Optional[QueryParamTypes] = None,
headers: Optional[dict[str, str]] = None,
) -> AsyncIterator[StreamPart]:
"""Stream results using SSE."""
headers, content = await aencode_json(json)
headers["Accept"] = "text/event-stream"
headers["Cache-Control"] = "no-store"
request_headers, content = await aencode_json(json)
request_headers["Accept"] = "text/event-stream"
request_headers["Cache-Control"] = "no-store"
# Add runtime headers with precedence
if headers:
request_headers.update(headers)
async with self.client.stream(
method, path, headers=headers, content=content, params=params
method, path, headers=request_headers, content=content, params=params
) as res:
# check status
try:
@@ -2447,9 +2480,15 @@ class SyncHttpClient:
def __init__(self, client: httpx.Client) -> None:
self.client = client
def get(self, path: str, *, params: Optional[QueryParamTypes] = None) -> Any:
def get(
self,
path: str,
*,
params: Optional[QueryParamTypes] = None,
headers: Optional[dict[str, str]] = None,
) -> Any:
"""Send a GET request."""
r = self.client.get(path, params=params)
r = self.client.get(path, params=params, headers=headers)
try:
r.raise_for_status()
except httpx.HTTPStatusError as e:
@@ -2461,13 +2500,21 @@ class SyncHttpClient:
raise e
return decode_json(r)
def post(self, path: str, *, json: Optional[dict]) -> Any:
def post(
self,
path: str,
*,
json: Optional[dict],
headers: Optional[dict[str, str]] = None,
) -> Any:
"""Send a POST request."""
if json is not None:
headers, content = encode_json(json)
request_headers, content = encode_json(json)
else:
headers, content = {}, b""
r = self.client.post(path, headers=headers, content=content)
request_headers, content = {}, b""
if headers:
request_headers.update(headers)
r = self.client.post(path, headers=request_headers, content=content)
try:
r.raise_for_status()
except httpx.HTTPStatusError as e:
@@ -2494,10 +2541,14 @@ class SyncHttpClient:
raise e
return decode_json(r)
def patch(self, path: str, *, json: dict) -> Any:
def patch(
self, path: str, *, json: dict, headers: Optional[dict[str, str]] = None
) -> Any:
"""Send a PATCH request."""
headers, content = encode_json(json)
r = self.client.patch(path, headers=headers, content=content)
request_headers, content = encode_json(json)
if headers:
request_headers.update(headers)
r = self.client.patch(path, headers=request_headers, content=content)
try:
r.raise_for_status()
except httpx.HTTPStatusError as e:
@@ -2509,9 +2560,15 @@ class SyncHttpClient:
raise e
return decode_json(r)
def delete(self, path: str, *, json: Optional[Any] = None) -> None:
def delete(
self,
path: str,
*,
json: Optional[Any] = None,
headers: Optional[dict[str, str]] = None,
) -> None:
"""Send a DELETE request."""
r = self.client.request("DELETE", path, json=json)
r = self.client.request("DELETE", path, json=json, headers=headers)
try:
r.raise_for_status()
except httpx.HTTPStatusError as e:
@@ -2529,11 +2586,16 @@ class SyncHttpClient:
*,
json: Optional[dict] = None,
params: Optional[QueryParamTypes] = None,
headers: Optional[dict[str, str]] = None,
) -> Iterator[StreamPart]:
"""Stream the results of a request using SSE."""
headers, content = encode_json(json)
request_headers, content = encode_json(json)
request_headers["Accept"] = "text/event-stream"
request_headers["Cache-Control"] = "no-store"
if headers:
request_headers.update(headers)
with self.client.stream(
method, path, headers=headers, content=content, params=params
method, path, headers=request_headers, content=content, params=params
) as res:
# check status
try: