FeedHive / twitter-api-client

A user-friendly Node.js / JavaScript client library for interacting with the Twitter API.
MIT License
948 stars 84 forks source link

twitter-api-client should throw `Error`s, not objects #102

Open lostfictions opened 2 years ago

lostfictions commented 2 years ago

Describe the bug

Hi again, here's another serious issue I've encountered with this library, When I was experiencing the problem described #101 -- confusing 404 errors from the API due to non-string user IDs -- I was having a lot of trouble debugging which twitter-api-client method calls were actually failing. This is because this package appears to throw arbitrary objects rather than Errors when something goes wrong. While this is technically permitted in JavaScript -- one of the language's many quirks -- throwing objects that do not inherit from Error is strongly recommended against, since non-Error objects usually do not provide stack traces and thus make it difficult to identify where the problem originated.

Here's a simple reproduction:

const client = new TwitterClient({
  apiKey: TWITTER_CONSUMER_KEY,
  apiSecret: TWITTER_CONSUMER_SECRET,
  accessToken: TWITTER_ACCESS_KEY,
  accessTokenSecret: TWITTER_ACCESS_SECRET,
});

const tl = await client.tweets.statusesUserTimeline({
  user_id: 12892389, // some arbitrary number, not a real id
});

console.log(tl);

This yields the following console output:

{
  statusCode: 404,
  data: '{"errors":[{"code":34,"message":"Sorry, that page does not exist."}]}'
}

Now, imagine this is part of a chain of several API calls, interleaved with my own business logic. For example, I could be getting a list of user IDs a user follows (via accountsAndUsers.friendsIds()), checking whether retweets are disabled for each of the returned users (via accountsAndUsers.friendshipsNoRetweetsIds()), and then retrieving each user's timeline (via tweets.statusesUserTimeline()), setting include_rts based on whether retweets are disabled for a given user. If something goes wrong in this process and I receive an error like the above 404, how am I supposed to reason about where it originated?

Expected behavior

Method calls should throw new Error(...) or from a custom error type that inherits from Error, as per standard JavaScript best practice. This would provide stack traces to consumers, allowing them to identify where a problem arose, rather than, say, having to verbosely and hermetically seal each twitter-api-client call in a try-catch block with custom error handling to be able to debug which method exploded.

Package Manager:

Yarn