Skip to content

Commit 442d080

Browse files
authored
feat: add rate limit error class (#178)
1 parent 546ab8c commit 442d080

4 files changed

Lines changed: 52 additions & 3 deletions

File tree

resend/contacts/_topics.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ def list(
112112
) -> "Topics.ListResponse":
113113
"""
114114
List all topics for a contact.
115-
see more: https://resend.com/docs/api-reference/contacts/list-contact-topics
115+
see more: https://resend.com/docs/api-reference/contacts/get-contact-topics
116116
117117
Args:
118118
contact_id (Optional[str]): The contact ID (either contact_id or email must be provided)

resend/exceptions.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,27 @@ def __init__(
160160
)
161161

162162

163+
class RateLimitError(ResendError):
164+
"""see https://resend.com/docs/api-reference/errors"""
165+
166+
def __init__(
167+
self,
168+
message: str,
169+
error_type: str,
170+
code: Union[str, int],
171+
):
172+
suggested_action = """Reduce your request rate or wait before retrying. """
173+
suggested_action += """Check the response headers for rate limit information."""
174+
175+
ResendError.__init__(
176+
self,
177+
code=code or "429",
178+
message=message,
179+
suggested_action=suggested_action,
180+
error_type=error_type,
181+
)
182+
183+
163184
# Dict with error code -> error type mapping
164185
ERRORS: Dict[str, Dict[str, Any]] = {
165186
"400": {"validation_error": ValidationError},
@@ -169,6 +190,11 @@ def __init__(
169190
},
170191
"401": {"missing_api_key": MissingApiKeyError},
171192
"403": {"invalid_api_key": InvalidApiKeyError},
193+
"429": {
194+
"rate_limit_exceeded": RateLimitError,
195+
"daily_quota_exceeded": RateLimitError,
196+
"monthly_quota_exceeded": RateLimitError,
197+
},
172198
"500": {"application_error": ApplicationError},
173199
}
174200

@@ -194,6 +220,8 @@ def raise_for_code_and_type(
194220
or
195221
InvalidApiKeyError: If the error type is invalid_api_key
196222
or
223+
RateLimitError: If the error type is rate_limit_exceeded, daily_quota_exceeded, or monthly_quota_exceeded
224+
or
197225
ApplicationError: If the error type is application_error
198226
or
199227
TypeError: If the error type is not found

resend/version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
__version__ = "2.19.0"
1+
__version__ = "2.20.0"
22

33

44
def get_version() -> str:

tests/exceptions_test.py

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import pytest
44

55
from resend.exceptions import (ApplicationError, MissingApiKeyError,
6-
ResendError, ValidationError,
6+
RateLimitError, ResendError, ValidationError,
77
raise_for_code_and_type)
88

99

@@ -32,3 +32,24 @@ def test_error_500(self) -> None:
3232
with pytest.raises(ApplicationError) as e:
3333
raise_for_code_and_type(500, "application_error", "err")
3434
assert e.type is ApplicationError
35+
36+
def test_rate_limit_exceeded_error(self) -> None:
37+
with pytest.raises(RateLimitError) as e:
38+
raise_for_code_and_type(429, "rate_limit_exceeded", "Rate limit exceeded")
39+
assert e.type is RateLimitError
40+
assert e.value.code == 429
41+
assert e.value.error_type == "rate_limit_exceeded"
42+
43+
def test_daily_quota_exceeded_error(self) -> None:
44+
with pytest.raises(RateLimitError) as e:
45+
raise_for_code_and_type(429, "daily_quota_exceeded", "Daily quota exceeded")
46+
assert e.type is RateLimitError
47+
assert e.value.code == 429
48+
assert e.value.error_type == "daily_quota_exceeded"
49+
50+
def test_monthly_quota_exceeded_error(self) -> None:
51+
with pytest.raises(RateLimitError) as e:
52+
raise_for_code_and_type(429, "monthly_quota_exceeded", "Monthly quota exceeded")
53+
assert e.type is RateLimitError
54+
assert e.value.code == 429
55+
assert e.value.error_type == "monthly_quota_exceeded"

0 commit comments

Comments
 (0)