I Found 3 Bugs in Twitter’s API Example Code

What I’m Building
It should come to no surprise to anyone who has been alive for the past ten months in the U.S. that things are …different, unexpected, and dare I say: unprecedented. Due to COVID and the sudden shift for millions to work-from-home, or worse yet, surprise-you’re-unemployed, has created a monumental uptick in residential trash output. This led to a lot of delays here in Philadelphia that were unpredictable and often signalled by a tweet from the Streets Department that there would be delays followed by estimates of when collections would resume.
I wanted to create a NodeJS app that emails, or texts, me anytime a tweet from PhilaStreets included the terms: suspend, collection, resume, delay. The first step was signing up for Twitter’s new API(v2) which more or less involved an application that detailed how I would use the API, as well as a polygraph, and commitment to hand over my firstborn child. After a little back and forth I was granted an Authorization Bearer Token and dove into the documentation.
As of this writing the errors in Twitter’s example code are still up on GitHub.
Twitter’s Documentation
The endpoint that served my purpose is called “User Tweet Timeline,” a paginated response that offers query parameters to either narrow or expand your searches. Thankfully they provide Python, Ruby, Java and JavaScript implementations on their Github. I’ll be using the latter to get more experience working within the NodeJS ecosystem.
Problem 1
Below you’ll see the function getUserTweets()
. It uses the getPage()
function where I found the bug.

Notice line #44 in the getPage()
definition: if there’s a next_token
key in the API’s resp.meta
then their Github code example says you need to set a key in in the next request of next_token
that equals that returned token to take advantage of their pagination feature. I kept getting an “Error: Bad Request” though after just receiving the first page and requesting the following page. After some sleuthing and cross-checking their API docs on their website I discovered that the key under which to store the next_token
value upon subsequent requests should be pagination_toke
. Oopsies!

Problem 2
After I squashed this bug, another reared its head. It had to do with the setting of the hasNextPage
variable as determined by the truthiness of resp.meta.next_token
on line #33. I wanted hasNextPage
to be set to false when a next_token
wasn’t received in the API’s response, but line #33 was never hit and it just endlessly called everything in the while
loop forever and ever, amen. It turns out I needed an else
with a hasNextPage = false
inserted on line #31. Bingo! With special attention to lines #31–32 and #46, check out the corrected code below:

Problem 3
The final line of their GitHub example function, getUserTweets()
logs the number of tweets along with the username of the account you are querying, but their code doesn’t ever declare the username variable, assign it, or even ask for it from the API. To do this you need to add a key/value pair to the params
object:
{"expansions": "author_id"}
A barebones example of the params
object would look like this:
let params = {
"max_results": 100,
"tweet.fields": "created_at",
"expansions": "author_id"
}
This will instruct the API to return an includes
object with a users
array in its response. You can access the username at resp.includes.users[0].username
. Observe the changes below in lines 12, 23, and 29 for this particular bug.

What’s Next
Time to make an Issue and initiate a Pull Request!
Conclusion
Thanks for reading! You can check out my work-in-progress NodeJS app over on my Github. Get at me with any questions, or feedback.
I’m currently working on some filo I/O to persist IDs of tweets that I’ve already flagged and sent to myself. The conditional for sending me alerts was originally based on Date
stuff. I noticed they’re using HootSuite and they send those scheduled tweets at 10:01am, but other spur of the moment tweets can happen at any time. Right now I’m running this hourly via macOS launchctl
. Happy coding!