Skip to content

Commit 13255f6

Browse files
committed
feat: raise ResendError on custom client error
1 parent b168cd5 commit 13255f6

3 files changed

Lines changed: 47 additions & 8 deletions

File tree

resend/http_client_requests.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@
66

77

88
class RequestsClient(HTTPClient):
9+
"""
10+
This is the default HTTP client implementation using the requests library.
11+
"""
12+
913
def __init__(self, timeout: int = 30):
1014
self._timeout = timeout
1115

@@ -26,4 +30,6 @@ def request(
2630
)
2731
return resp.content, resp.status_code, resp.headers
2832
except requests.RequestException as e:
33+
# This gets caught by the request.perform() method
34+
# and raises a ResendError with the error type "HttpClientError"
2935
raise RuntimeError(f"Request failed: {e}") from e

resend/request.py

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
from typing_extensions import Literal, TypeVar
55

66
import resend
7-
from resend.exceptions import NoContentError, raise_for_code_and_type
7+
from resend.exceptions import (NoContentError, ResendError,
8+
raise_for_code_and_type)
89
from resend.version import get_version
910

1011
RequestVerb = Literal["get", "post", "put", "patch", "delete"]
@@ -69,12 +70,22 @@ def make_request(self, url: str) -> Union[Dict[str, Any], List[Any]]:
6970
else:
7071
json_params = None
7172

72-
content, _status_code, resp_headers = resend.default_http_client.request(
73-
method=self.verb,
74-
url=url,
75-
headers=headers,
76-
json=json_params,
77-
)
73+
try:
74+
content, _status_code, resp_headers = resend.default_http_client.request(
75+
method=self.verb,
76+
url=url,
77+
headers=headers,
78+
json=json_params,
79+
)
80+
81+
# Safety net around the HTTP Client
82+
except Exception as e:
83+
raise ResendError(
84+
code=500,
85+
message=str(e),
86+
error_type="HttpClientError",
87+
suggested_action="Request failed, please try again.",
88+
)
7889

7990
content_type = {k.lower(): v for k, v in resp_headers.items()}.get(
8091
"content-type", ""

tests/default_http_client_test.py

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
1-
from typing import cast
1+
from typing import Any, Dict, Mapping, Tuple, cast
22
from unittest import TestCase
33
from unittest.mock import create_autospec
44

5+
import pytest
6+
57
import resend
8+
import resend.exceptions
69
from resend.http_client import HTTPClient
710

811

@@ -40,3 +43,22 @@ def test_default_http_client_called_with_correct_payload(self) -> None:
4043
assert kwargs["method"] == "post"
4144
assert "/emails" in kwargs["url"]
4245
assert kwargs["json"]["subject"] == "Hi!"
46+
47+
def test_perform_raises_resend_error_on_runtime_error(self) -> None:
48+
class RaisesClient(resend.http_client.HTTPClient):
49+
def request(
50+
self, *args: object, **kwargs: object
51+
) -> Tuple[bytes, int, Mapping[str, str]]:
52+
raise RuntimeError("Connection broken")
53+
54+
resend.default_http_client = RaisesClient()
55+
56+
request: resend.Request[Dict[str, Any]] = resend.Request(
57+
path="/emails", params={}, verb="post"
58+
)
59+
60+
with pytest.raises(resend.exceptions.ResendError) as exc:
61+
request.perform()
62+
63+
assert "Connection broken" in str(exc.value)
64+
assert exc.value.error_type == "HttpClientError"

0 commit comments

Comments
 (0)