Skip to content

Commit 3a03d68

Browse files
committed
init
1 parent e4a2974 commit 3a03d68

28 files changed

+8757
-10
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
node_modules
2+
dist
3+
examples/node_modules
4+
examples/.env

.npmrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
registry=https://registry.npmjs.org

CONTRIBUTING.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,18 @@ We'd love to get patches from you!
77
We follow the [GitHub Flow Workflow](https://guides.github.com/introduction/flow/)
88

99
1. Fork the project
10-
1. Check out the `master` branch
10+
1. Check out the `main` branch
1111
1. Create a feature branch
1212
1. Write code and tests for your change
13-
1. From your branch, make a pull request against `twitter/repo-scaffolding/master`
13+
1. From your branch, make a pull request against `twitterdev/twitter-api-typescript-sdk/main`
1414
1. Work with repo maintainers to get your change reviewed
15-
1. Wait for your change to be pulled into `twitter/repo-scaffolding/master`
15+
1. Wait for your change to be pulled into `twitterdev/twitter-api-typescript-sdk/main`
1616
1. Delete your feature branch
1717

1818
## License
1919

2020
By contributing your code, you agree to license your contribution under the
21-
terms of the APLv2: https://github.com/twitter/repo-scaffolding/blob/master/LICENSE
21+
terms of the APLv2: https://github.com/twitterdev/twitter-api-typescript-sdk/blob/main/LICENSE
2222

2323
## Code of Conduct
2424

LICENSE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@
186186
same "printed page" as the copyright notice for easier
187187
identification within third-party archives.
188188

189-
Copyright [yyyy] [name of copyright owner]
189+
Copyright 2021 Twitter, Inc
190190

191191
Licensed under the Apache License, Version 2.0 (the "License");
192192
you may not use this file except in compliance with the License.

README.md

Lines changed: 141 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,144 @@
1-
# An incredible project
1+
# Twitter API SDK for TypeScript
22

3-
This is the file you get to write to document your new project!
3+
## Introduction
44

5-
Also, don't forget to edit the couple of references in CONTRIBUTING.md that will need to be customized to link to this repo.
6-
Update the LICENSE file with the correct date and attribution.
5+
A TypeScript SDK for the Twitter API. This library is built with TypeScript developers in mind, but it also works with JavaScript.
76

8-
You also might want to create a .gitignore file to make things nicer.
7+
**Note: This SDK is in beta and is not ready for production**
8+
9+
You can find examples of using the client in the [examples/](examples/) directory
10+
11+
**Note: Only Twitter API V2 is supported**
12+
13+
### Features
14+
15+
- Full type information for requests and responses
16+
- OAuth2 support
17+
- Supports Node.js 14+. **Doesn't work in browser environments due to the Twitter API not supporting CORS**
18+
19+
## Installing
20+
21+
```
22+
npm install twitter-api-sdk
23+
```
24+
25+
## Client
26+
27+
To setup the client we will authenticate with a bearer-token as follows
28+
29+
```typescript
30+
import { Client } from "twitter-api-sdk";
31+
32+
const client = new Client("MY-BEARER-TOKEN");
33+
```
34+
35+
For more information about authentication [go here](#authentication)
36+
37+
## Examples
38+
39+
### Consuming a stream
40+
41+
```typescript
42+
import { Client } from "twitter-api-sdk";
43+
44+
const client = new Client(process.env.BEARER_TOKEN);
45+
46+
async function main() {
47+
const stream = client.tweets.sampleStream({
48+
"tweet.fields": ["author_id"],
49+
});
50+
for await (const tweet of stream) {
51+
console.log(tweet.data?.author_id);
52+
}
53+
}
54+
55+
main();
56+
```
57+
58+
### Getting a tweet
59+
60+
```typescript
61+
import { Client } from "twitter-api-sdk";
62+
63+
const client = new Client(process.env.BEARER_TOKEN);
64+
65+
async function main() {
66+
const tweet = await client.tweets.findTweetById("20");
67+
console.log(tweet.data.text);
68+
}
69+
70+
main();
71+
```
72+
73+
## Streaming
74+
75+
For endpoints that return a stream you get sent back an Async Generator which you can iterate over:
76+
77+
```typescript
78+
const stream = client.tweets.sampleStream();
79+
80+
for await (const tweet of stream) {
81+
console.log(tweet.data.text);
82+
}
83+
```
84+
85+
## Pagination
86+
87+
For endpoints that have pagination you can
88+
89+
```typescript
90+
const followers = client.users.usersIdFollowers("20");
91+
92+
for await (const page of followers) {
93+
console.log(page.data);
94+
}
95+
96+
// This also works
97+
const followers = await client.users.usersIdFollowers("20");
98+
console.log(followers.data);
99+
```
100+
101+
## Authentication
102+
103+
This library supports App-only Bearer Token and OAuth 2.0
104+
105+
You can see various examples on how to use the authentication in [examples/](examples/)
106+
107+
## Getting Started
108+
109+
Make sure you to turn on OAuth2 in your apps user authentication settings, and set the type of app to be a confidential client (Web App or Automated App or Bot).
110+
111+
### Creating an Auth Client
112+
113+
```typescript
114+
const authClient = new auth.OAuth2User({
115+
client_id: process.env.CLIENT_ID,
116+
client_secret: process.env.CLIENT_SECRET,
117+
callback: "http://127.0.0.1:3000/callback",
118+
scopes: ["tweet.read", "users.read", "offline.access"],
119+
});
120+
121+
const client = new Client(authClient);
122+
```
123+
124+
### Generating an Authentication URL
125+
126+
```typescript
127+
const authUrl = authClient.generateAuthURL({
128+
code_challenge_method: "s256",
129+
});
130+
```
131+
132+
### Getting an Access Token
133+
134+
Once the user has approved the OAuth flow, you will receive a `code` query parameter at the callback URL you specified.
135+
136+
```typescript
137+
await authClient.requestAccessToken(code);
138+
```
139+
140+
### Revoking an Access Token
141+
142+
```typescript
143+
const response = await authClient.revokeAccessToken();
144+
```

examples/.npmrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
registry=https://registry.npmjs.org

examples/README.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# Twitter API TypeScript SDK Examples
2+
3+
## To run the examples
4+
5+
Make sure you are in the `examples` directory
6+
7+
Install the required packages
8+
9+
```
10+
npm install
11+
```
12+
13+
Next, create a `.env` file in the example directory and populate the following variables (You do not need them all for each example, for example `oauth2-bearer.ts` only requires a `BEARER_TOKEN`):
14+
15+
```
16+
BEARER_TOKEN=my-bearer-token
17+
API_KEY=my-api-key
18+
API_SECRET_KEY=my-secret-key
19+
ACCESS_TOKEN=my-access-token
20+
ACCESS_TOKEN_SECRET=my-access-token-secret
21+
```
22+
23+
Run the example with `ts-node`
24+
25+
`npx ts-node *.ts`
26+
27+
For example:
28+
29+
```
30+
npx ts-node oauth2-bearer.ts
31+
```

examples/filtered-stream.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// Copyright 2021 Twitter, Inc.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
import { Client } from "twitter-api-sdk";
5+
import dotenv from "dotenv";
6+
7+
dotenv.config();
8+
9+
async function main() {
10+
const client = new Client(process.env.BEARER_TOKEN as string);
11+
await client.tweets.addOrDeleteRules(
12+
{
13+
add: [
14+
{ value: "cat has:media", tag: "cats with media" },
15+
{ value: "cat has:media -grumpy", tag: "happy cats with media" },
16+
{ value: "meme", tag: "funny things" },
17+
{ value: "meme has:images" },
18+
],
19+
},
20+
{
21+
dry_run: true,
22+
}
23+
);
24+
const rules = await client.tweets.getRules();
25+
console.log(rules);
26+
const stream = client.tweets.searchStream({
27+
"tweet.fields": ["author_id", "geo"],
28+
});
29+
for await (const tweet of stream) {
30+
console.log(tweet.data?.author_id);
31+
}
32+
}
33+
34+
main();

examples/oauth2-bearer.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Copyright 2021 Twitter, Inc.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
import { Client } from "twitter-api-sdk";
5+
import * as dotenv from "dotenv";
6+
7+
dotenv.config();
8+
9+
async function main() {
10+
const client = new Client(process.env.BEARER_TOKEN as string);
11+
const { data } = await client.users.findUserByUsername("TwitterDev");
12+
if (!data) throw new Error("Couldn't find user");
13+
let count = 0;
14+
for await (const followers of client.users.usersIdFollowers(data.id)) {
15+
console.log(followers);
16+
if (++count == 3) {
17+
break;
18+
}
19+
}
20+
}
21+
22+
main();

examples/oauth2-callback.ts

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
// Copyright 2021 Twitter, Inc.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
import { Client, auth } from "twitter-api-sdk";
5+
import express from "express";
6+
import dotenv from "dotenv";
7+
8+
dotenv.config();
9+
10+
const app = express();
11+
12+
const authClient = new auth.OAuth2User({
13+
client_id: process.env.CLIENT_ID as string,
14+
client_secret: process.env.CLIENT_SECRET as string,
15+
callback: "http://127.0.0.1:3000/callback",
16+
scopes: ["tweet.read", "users.read", "offline.access"],
17+
});
18+
19+
const client = new Client(authClient);
20+
21+
const STATE = "my-state";
22+
23+
app.get("/callback", async function (req, res) {
24+
try {
25+
const { code, state } = req.query;
26+
if (state !== STATE) {
27+
return res.status(500).send("State isn't matching");
28+
}
29+
await authClient.requestAccessToken(code as string);
30+
res.redirect("/tweets");
31+
} catch (error) {
32+
console.log(error);
33+
}
34+
});
35+
36+
app.get("/login", async function (req, res) {
37+
const authUrl = authClient.generateAuthURL({
38+
state: STATE,
39+
code_challenge: "challenge",
40+
});
41+
res.redirect(authUrl);
42+
});
43+
44+
app.get("/tweets", async function (req, res) {
45+
const tweets = await client.tweets.findTweetById("20");
46+
res.send(tweets.data);
47+
});
48+
49+
app.get("/revoke", async function (req, res) {
50+
const refresh_token = authClient.refresh_token;
51+
if (refresh_token) {
52+
const response = await authClient.revokeAccessToken();
53+
return res.send(response);
54+
}
55+
res.send("No access token to revoke");
56+
});
57+
58+
app.listen(3000, () => {
59+
console.log(`Go here to login: http://127.0.0.1:3000/login`);
60+
});

0 commit comments

Comments
 (0)