Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion resend/async_request.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ async def make_request(self, url: str) -> Union[Dict[str, Any], List[Any]]:
parsed_data["http_headers"] = dict(self._response_headers)
# For list responses, return as-is (lists can't have headers key)
return parsed_data
except json.JSONDecodeError:
except (json.JSONDecodeError, UnicodeDecodeError):
raise_for_code_and_type(
code=error_code,
message="Failed to decode JSON response",
Expand Down
2 changes: 1 addition & 1 deletion resend/request.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ def make_request(self, url: str) -> Union[Dict[str, Any], List[Any]]:
parsed_data["http_headers"] = dict(self._response_headers)
# For list responses, return as-is (lists can't have headers key)
return parsed_data
except json.JSONDecodeError:
except (json.JSONDecodeError, UnicodeDecodeError):
raise_for_code_and_type(
code=error_code,
message="Failed to decode JSON response",
Expand Down
2 changes: 1 addition & 1 deletion resend/version.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
__version__ = "2.43.0"
__version__ = "2.43.1"


def get_version() -> str:
Expand Down
40 changes: 40 additions & 0 deletions tests/request_test.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import asyncio
import unittest
from typing import Any, Dict
from unittest.mock import AsyncMock, MagicMock, Mock, patch
Expand All @@ -10,6 +11,45 @@
from resend.version import get_version


@pytest.mark.parametrize("content", [b'"\xff"', b'\xff\xfe{', b'not-json'])
@pytest.mark.parametrize("status_code", [200, 429, 502])
class TestResponseDecodingErrors:
def test_sync_preserves_status_and_headers(
self, content: bytes, status_code: int
) -> None:
headers = {"content-type": "application/json", "retry-after": "2"}
response = Mock(content=content, status_code=status_code, headers=headers)
req = request.Request[Dict[str, Any]]("/emails", {}, "get")

with patch("resend.http_client_requests.requests.request", return_value=response):
with pytest.raises(ResendError) as error:
req.perform()

assert error.value.code == (status_code if status_code >= 400 else 500)
assert error.value.headers == headers
assert error.value.message == "Failed to decode JSON response"

def test_async_preserves_status_and_headers(
self, content: bytes, status_code: int
) -> None:
from resend.async_request import AsyncRequest
from resend.http_client_httpx import HTTPXClient

headers = {"content-type": "application/json", "retry-after": "2"}
response = Mock(content=content, status_code=status_code, headers=headers)
req = AsyncRequest[Dict[str, Any]]("/emails", {}, "get")

with patch("resend.default_async_http_client", HTTPXClient()):
with patch("httpx.AsyncClient.request", new_callable=AsyncMock) as send:
send.return_value = response
with pytest.raises(ResendError) as error:
asyncio.run(req.perform())

assert error.value.code == (status_code if status_code >= 400 else 500)
assert error.value.headers == headers
assert error.value.message == "Failed to decode JSON response"


class TestResendRequest(unittest.TestCase):
@patch("resend.http_client_requests.requests.request")
@patch("resend.api_key", new="test_key")
Expand Down