Skip to content

Conversation

@gabrielmfern
Copy link
Member

@gabrielmfern gabrielmfern commented Aug 8, 2025

Closes #189.

Adds a type to use on all responses to avoid repeating the definition for it, and add a rateLimiting field there that gives access to the ratelimit-limit, ratelimit-reset and ratelimit-remaining headers.

The actual changes to use the new Response type were made by claudinho, so take that portion with a grain of salt

Here's how an example of the API would feel like:

const response = await resend.emails.send(/* ... */);

//  limit: number;
//  remainingRequests: number;
//  shouldResetAfter: number;
if (response.rateLimiting?.remainingRequests === 0) {
	setTimeout(() => {
		// ...continue making requests...
	}, response.rateLimiting.shouldResetAfter * 1000);
}

Unfortunately, there are a few cases that are errors that happen on the client and not on the server, so if error is not null, rateLimiting can be null. Ideally the user would not need to handle that, but seems like it's unavoidable.

Additionally, this also adds in a retryAfter property to the ErrorResponse when the name is 'rate_limit_exceeded' taken from the retry-after header that only comes on 429 responses. It feels like this:

const response = resend.emails.send(/* ... */);

if (response.error?.name === 'rate_limit_exceeded') {
	setTimeout(() => {
		/* ...code for retrying... */
	}, 1000 * response.error.retryAfter);
}

@gabrielmfern gabrielmfern self-assigned this Aug 8, 2025
@gabrielmfern gabrielmfern marked this pull request as ready for review August 8, 2025 18:29
@gabrielmfern gabrielmfern requested a review from a team as a code owner August 8, 2025 18:29
@gabrielmfern gabrielmfern requested a review from vcapretz August 8, 2025 18:29
@gabrielmfern gabrielmfern requested review from joaopcm and removed request for vcapretz August 8, 2025 20:06
Comment on lines +30 to +34
if (!limitHeader || !remainingHeader || !resetHeader) {
throw new Error(
"The rate limit headers are not present in the response, something must've gone wrong, please email us at [email protected]",
);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if we gracefully fail here? This would be a big problem if we change how the rate limit works in the API

Copy link
Member Author

@gabrielmfern gabrielmfern Aug 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that function is only called from

const rateLimiting = parseRateLimit(response.headers);

and there it errors gracefully, but with an error message that isn't very clear. we could return something else for when it isn't able to get the rate limiting headers, I also thought of just warning, but my worry with not erroring here is that it could break workflows for users silently

imo the best would be to have tests on the SDK's side that tested things directly with the production API ensuring that this rate limiting is working so it would fail early, instead of doing mocking

@gabrielmfern gabrielmfern merged commit ee0d2a1 into canary Aug 14, 2025
10 checks passed
@gabrielmfern gabrielmfern deleted the feat/rate-limiting-information-access branch August 14, 2025 14:08
gabrielmfern added a commit that referenced this pull request Sep 5, 2025
@gabrielmfern gabrielmfern restored the feat/rate-limiting-information-access branch September 5, 2025 15:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

The rate limit headers aren't returned to users

3 participants