A tiny, full-featured, modern client / server library for the Twitter API.
Features
- Promise driven via Async / Await
- REST and Stream support
- Works both in Node and in browsers
- Rate limiting support
- Under 1kb
- Minimal dependencies
- Test suite
Why
We have built this library because existing ones have not been recently maintained, or depend on outdated libraries.
Installation
yarn add twitter-lite
npm install twitter-lite
Usage
- Create an app on https://apps.twitter.com/
- Grab the Consumer Key (API Key) and Consumer Secret (API Secret) from Keys and Access Tokens
- Make sure you set the right access level for your app
- If you want to use user-based authentication, grab the access token key and secret as well
App vs. User authentication
Twitter has two different authentication options:
- App: higher rate limits. Great for building your own Twitter App.
- User: lower rate limits. Great for making requests on behalf of a User.
User authentication requires:
consumer_key
consumer_secret
access_token_key
access_token_secret
App authentication requires:
App authentication is a simple header behind the scenes:
headers: {
Authorization: `Bearer ${bearer_token}`;
}
You can get the bearer token by calling .getBearerToken()
.
Verifying credentials example (user auth)
const client = new Twitter({
subdomain: "api",
consumer_key: "abc", // from Twitter.
consumer_secret: "def", // from Twitter.
access_token_key: "uvw", // from your User (oauth_token)
access_token_secret: "xyz" // from your User (oauth_token_secret)
});
client
.get("account/verify_credentials")
.then(results => {
console.log("results", results);
})
.catch(console.error);
App authentication example
const user = new Twitter({
consumer_key: "abc",
consumer_secret: "def"
});
const response = await user.getBearerToken();
const app = new Twitter({
bearer_token: response.access_token
});
Oauth authentication
According to the docs this helps you get access token from your users.
const client = new Twitter({
consumer_key: "xyz",
consumer_secret: "xyz"
});
client
.getRequestToken("http://callbackurl.com")
.then(res =>
console.log({
reqTkn: res.oauth_token,
reqTknSecret: res.oauth_token_secret
})
)
.catch(console.error);
Then you redirect your user to https://api.twitter.com/oauth/authenticate?oauth_token=xyz123abc
, and once you get the verifier and the token, you pass them on to the next stage of the authentication.
const client = new Twitter({
consumer_key: "xyz",
consumer_secret: "xyz"
});
client
.getAccessToken({
key: requestToken,
secret: requestTokenSecret,
verifier: oauthVerifier
})
.then(res =>
console.log({
accTkn: res.oauth_token,
accTknSecret: res.oauth_token_secret,
userId: res.user_id,
screenName: res.screen_name
})
)
.catch(console.error);
And this will return you your access_token
and access_token_secret
.
Streams
To learn more about the streaming API visit the Twitter Docs. The streaming API works only in Node.
const client = new Twitter({
consumer_key: "xyz" // from Twitter.
consumer_secret: "xyz" // from Twitter.
access_token_key: "abc" // from your User (oauth_token)
access_token_secret: "abc" // from your User (oauth_token_secret)
});
const parameters = {
track: "#bitcoin,#litecoin,#monero",
follow: "422297024,873788249839370240", // @OrchardAI, @tylerbuchea
locations: "-122.75,36.8,-121.75,37.8", // Bounding box - San Francisco
};
const stream = client.stream("statuses/filter", parameters)
.on("start", response => console.log("start"))
.on("data", tweet => console.log("data", tweet.text))
.on("ping", () => console.log("ping"))
.on("error", error => console.log("error", error))
.on("end", response => console.log("end"));
// To stop the stream:
process.nextTick(() => stream.destroy()); // emits "end" and "error" events
To stop a stream, call stream.destroy()
. That might take a while though, if the stream receives a lot of traffic. Also, if you attempt to destroy a stream from an on
handler, you may get an error about writing to a destroyed stream.
To avoid both these issues, defer the destroy()
call:
process.nextTick(() => stream.destroy());
After you've destroyed a stream, you can create another one - see the "should switch from one stream to another" test.
Methods
.get(endpoint, parameters)
Returns a Promise resolving to the API response object, or rejecting on error. The response and error objects also contain the HTTP response code and headers, under the _headers
key. These are useful to check for rate limit information.
const client = new Twitter({
consumer_key: "xyz",
consumer_secret: "xyz",
access_token_key: "abc",
access_token_secret: "abc"
});
const rateLimits = await app.get("statuses/show", {
id: "1016078154497048576"
});
.post(endpoint, parameters)
Same return as .get()
.
Use the .post
method for actions that change state, or when the total size of the parameters might be too long for a GET request. For example, to follow a user:
const client = new Twitter({
consumer_key: "xyz",
consumer_secret: "xyz",
access_token_key: "abc",
access_token_secret: "abc"
});
await client.post("friendships/create", {
screen_name: "dandv"
});
The second use case for POST is when you need to pass more parameters than suitable for the length of a URL, such as when looking up a larger number of user ids or screen names:
const users = await client.post("users/lookup", {
screen_name: "longScreenName1,longerScreeName2,...,veryLongScreenName100"
});
.getBearerToken()
See the app authentication example.
See the OAuth example.
.getAccessToken(options)
See the OAuth example.
Troubleshooting
API errors
.get
and .post
reject on error, so you can use try/catch to handle errors. The error object contains an errors
property with the error code
and message
, and a _headers
property with the the HTTP response code and Headers object returned by the Twitter API. Note that each _headers
property is an array, usually of length 1.
try {
const response = await client.get("some/endpoint");
// ... use response here ...
} catch (e) {
if ('errors' in e) {
// Twitter API error
if (e.errors[0].code === 88)
// rate limit exceeded
console.log("Rate limit will reset on", new Date(e._headers["x-rate-limit-reset"] * 1000));
else
// some other kind of error, e.g. read-only API trying to POST
} else {
// non-API error, e.g. network problem or invalid JSON in response
}
}
Rate limiting
A particular case of errors is exceeding the rate limits. See the example immediately above for detecting rate limit errors, and read Twitter's documentation on rate limiting.
Numeric vs. string IDs
Twitter uses numeric IDs that in practice can be up to 18 characters long. Due to rounding errors, it's unsafe to use numeric IDs in JavaScript. Always set stringify_ids: true
when possible, so that Twitter will return strings instead of numbers, and rely on the id_str
field, rather than on the id
field.
Contributing
With the library nearing v1.0, contributions are welcome! Areas especially in need of help involve multimedia (see #33 for example), adding tests (see these for reference), and getting v1.0 out the door.
Development
- Fork/clone the repo
yarn/npm install
- Go to https://apps.twitter.com and create an app for testing this module. Make sure it has read/write permissions.
- Grab the consumer key/secret, and the access token/secret and place them in a .env file in the project's root directory, under the following variables:
TWITTER_CONSUMER_KEY=...
TWITTER_CONSUMER_SECRET=...
ACCESS_TOKEN=...
ACCESS_TOKEN_SECRET=...
yarn/npm test
and make sure all tests pass- Add your contribution, along with test case(s). Note: feel free to skip the "should DM user" test during development by changing that
it()
call to it.skip()
, but remember to revert that change before committing. This will prevent your account from being flagged as abusing the API to send too many DMs. - Make sure all tests pass.
git add
the changed filesnpm run precommit
to lint with prettier- Commit using a descriptive message (please squash commits into one per fix/improvement!)
git push
and submit your PR!
Credits
Authors:
Over the years, thanks to: