-
Notifications
You must be signed in to change notification settings - Fork 54
feat: add async iterator support to emails.list method #611
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: canary
Are you sure you want to change the base?
feat: add async iterator support to emails.list method #611
Conversation
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Bu Kinoshita <[email protected]> Co-authored-by: Gabriel Miranda <[email protected]>
Co-authored-by: Bu Kinoshita <[email protected]> Co-authored-by: Gabriel Miranda <[email protected]>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Carolina de Moraes Josephik <[email protected]>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Gabriel Miranda <[email protected]>
Co-authored-by: Gabriel Miranda <[email protected]>
Co-authored-by: Gabriel Miranda <[email protected]> Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, I started implementing this wanting to give the users an API where they would iterate over T
.
But we can't do that and return errors as value. So I'm opening the PR as it is for us to discuss on how to solve that problem.
My suggestion is to change the .iterate()
to iterate over the pages instead of over the items. So the iterator would yield Response<PaginatedData<T>
instead of just T
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
3 issues found across 4 files
React with 👍 or 👎 to teach cubic. You can also tag @cubic-dev-ai
to give feedback, ask questions, or re-run the review.
src/common/paginated-request.ts
Outdated
const response = await this.fetchPageWithRetry(currentOptions); | ||
if (response.error) { | ||
// TODO: how do we expose this error to the caller? | ||
console.error('Error fetching page:', response.error); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Errors during subsequent page fetches are logged and iteration silently stops; throw to let callers handle failures rather than silently truncating results.
Prompt for AI agents
Address the following comment on src/common/paginated-request.ts at line 116:
<comment>Errors during subsequent page fetches are logged and iteration silently stops; throw to let callers handle failures rather than silently truncating results.</comment>
<file context>
@@ -0,0 +1,166 @@
+ const response = await this.fetchPageWithRetry(currentOptions);
+ if (response.error) {
+ // TODO: how do we expose this error to the caller?
+ console.error('Error fetching page:', response.error);
+ break;
+ }
</file context>
src/common/paginated-request.ts
Outdated
}); | ||
} else { | ||
// TODO: how do we expose this error to the caller? | ||
console.error('Error fetching initial page:', initialPage.error); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Non–rate-limit errors in the initial request are logged and swallowed, preventing callers from handling failures; throw the error to propagate it to consumers of the async iterator.
Prompt for AI agents
Address the following comment on src/common/paginated-request.ts at line 92:
<comment>Non–rate-limit errors in the initial request are logged and swallowed, preventing callers from handling failures; throw the error to propagate it to consumers of the async iterator.</comment>
<file context>
@@ -0,0 +1,166 @@
+ });
+ } else {
+ // TODO: how do we expose this error to the caller?
+ console.error('Error fetching initial page:', initialPage.error);
+ return;
+ }
</file context>
src/common/paginated-request.ts
Outdated
|
||
if ( | ||
response.error?.name === 'rate_limit_exceeded' && | ||
response.error.retryAfter |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Truthiness check on retryAfter may skip retries when retryAfter is 0; for rate_limit_exceeded, retryAfter is always defined by type, so this guard is unnecessary and can prevent immediate retries.
Prompt for AI agents
Address the following comment on src/common/paginated-request.ts at line 143:
<comment>Truthiness check on retryAfter may skip retries when retryAfter is 0; for rate_limit_exceeded, retryAfter is always defined by type, so this guard is unnecessary and can prevent immediate retries.</comment>
<file context>
@@ -0,0 +1,166 @@
+
+ if (
+ response.error?.name === 'rate_limit_exceeded' &&
+ response.error.retryAfter
+ ) {
+ const retryAfter = response.error.retryAfter * 1000;
</file context>
@gabrielmfern about handling errors: Unless we want to use exceptions I though of 2 alternatives for the api to expose the error as value:
for await (const page of resend.emails.list().iterate()) {
if (page.error) {
// handle the error
break;
}
// iterate page items
for (const item of page.data) {
}
}
for await (const item of resend.email.list().iterate()) {
if (item.error) {
// handle the error
break;
}
const email = item.data;
} |
@vieiralucas From an outside perspective, I’d love it if you could explain in more detail what problems we’re trying to solve with this change, and why our current implementation of the emails listing API doesn’t address them. If it is just for an easier developer experience, I think that is a totally valid reason. Also, if we agree on the solution, I’d lean toward iterating on the pages (option 1) rather than on the items. The reason is that, technically, the implementation isn’t fetching one item at a time. It’s fetching new pages as needed. Because of that, showing an error tied to a specific item feels a bit misleading, since the error actually occurs when fetching the entire next page, not the individual item. Does that make sense? |
Add PaginatedRequest class with async iteration capabilities to handle paginated email listing. Includes automatic retry logic for rate limits, forward and backward pagination support.
e4a9a49
to
c2df484
Compare
Hi @emiliosheinz, thanks for the comment. This is basically us wanting to provide better DX, just pushed a new commit that yields the page instead of the item btw, but we're still doing some discussions internally about this PR. |
c2df484
to
4cc8f42
Compare
5b639fe
to
6c06191
Compare
Add PaginatedRequest class with async iteration capabilities to handle paginated email listing. Includes automatic retry logic for rate limits, forward and backward pagination support.
Summary by cubic
Adds async iterator support to emails.list via a new PaginatedRequest, enabling simple forward/backward pagination with automatic rate-limit retries. Aligns with ENG-4362 and preserves await emails.list(...) for first-page fetching.
New Features
Migration