Skip to content

Implement PromiseLike<T> for Paginator, and deprecate iterate, fetchAll, fetchMany #763

@neet

Description

@neet

I'm planning to change the interface of API that returns a collection of entities to a more intuitive one in the next major release.

Currently, we have three methods to fetch a collection of entities; fetchMany, fetchAll and iterate. The difference between fetchMany and iterate is the return type. fetchMany just returns an array while iterate returns an async iterable. fetchAll is for APIs that don't support pagination, such as suggestions, announcements, etc.

// This is an array. You can check if there's more by `done`
const { value: collection1, done } = await masto.timelines.fetchHome();

// This is an asyncIterable. You can fetch more by calling .next()
const collection2 = masto.timelines.iterateHome();

// This is an array without pagination
const collection3 = await masto.announcements.fetchAll();

However, this implementation has some disadvantages. It is simply intricate because we have to maintain at least two methods for each API. On top of that, there had been APIs that used to not support pagination but added a Link header later on. If we mapped such API by fetchAll() at first and then they come to support pagination, we have to make a breaking change to rename fetchAll() to fetchMany() and also introduce iterate().

To solve this, I'm planning to integrate these three methods into a single method named list, and implement PromiseLike<T> to the Pagination class. It would look like this; since Paginator is now then-able, we can await to get the first page, while you can also iterate over multiple pages by using the iteration protocol.

// You can directly fetch an array
const array = await masto.announcements.list();

// While you can also iterate over the collection
for await (const items of masto.announcements.list()) {
  console.info(items);
}

I'm planning to prevail this change to all methods that currently return an array. As a result, we can achieve two features ―fetching a single page, and iterating over multiple pages―in a single method. Furthermore, even if Mastodon started to support pagination in some API, we can smoothly start to adopt the update without any breaking changes.

This is inspired by twitter-api-typescript-sdk returns AsyncIterable + PromiseLike for APIs that supports pagination
https://github.com/twitterdev/twitter-api-typescript-sdk/blob/0d12a20a76d6dd9c346decf9cc80bc611975d43f/src/types.ts#L21

The possible drawbacks are the fact that PromiseLike is not an actual Promise, so it's a bit inconvenient when you need an actual Promise object. However, PromiseLike can be easily converted into Promise by calling then, so I think this is not a critical problem.

const result1 = masto.announcements.list() instanceof Promise;
const result2 = masto.announcements.list().then() instanceof Promise;
// result1 === false, result2 === true

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions