1 | #twit
|
2 |
|
3 | Twitter API Client for node
|
4 |
|
5 | Supports both the **REST** and **Streaming** API.
|
6 |
|
7 | #Installing
|
8 |
|
9 | ```
|
10 | npm install twit
|
11 | ```
|
12 |
|
13 | ##Usage:
|
14 |
|
15 | ```javascript
|
16 | var Twit = require('twit')
|
17 |
|
18 | var T = new Twit({
|
19 | consumer_key: '...'
|
20 | , consumer_secret: '...'
|
21 | , access_token: '...'
|
22 | , access_token_secret: '...'
|
23 | })
|
24 |
|
25 | //
|
26 | // tweet 'hello world!'
|
27 | //
|
28 | T.post('statuses/update', { status: 'hello world!' }, function(err, data, response) {
|
29 | console.log(data)
|
30 | })
|
31 |
|
32 | //
|
33 | // search twitter for all tweets containing the word 'banana' since Nov. 11, 2011
|
34 | //
|
35 | T.get('search/tweets', { q: 'banana since:2011-11-11', count: 100 }, function(err, data, response) {
|
36 | console.log(data)
|
37 | })
|
38 |
|
39 | //
|
40 | // get the list of user id's that follow @tolga_tezel
|
41 | //
|
42 | T.get('followers/ids', { screen_name: 'tolga_tezel' }, function (err, data, response) {
|
43 | console.log(data)
|
44 | })
|
45 |
|
46 | //
|
47 | // retweet a tweet with id '343360866131001345'
|
48 | //
|
49 | T.post('statuses/retweet/:id', { id: '343360866131001345' }, function (err, data, response) {
|
50 | console.log(data)
|
51 | })
|
52 |
|
53 | //
|
54 | // destroy a tweet with id '343360866131001345'
|
55 | //
|
56 | T.post('statuses/destroy/:id', { id: '343360866131001345' }, function (err, data, response) {
|
57 | console.log(data)
|
58 | })
|
59 |
|
60 | //
|
61 | // get `funny` twitter users
|
62 | //
|
63 | T.get('users/suggestions/:slug', { slug: 'funny' }, function (err, data, response) {
|
64 | console.log(data)
|
65 | })
|
66 |
|
67 | //
|
68 | // post a tweet with media
|
69 | //
|
70 | var b64content = fs.readFileSync('/path/to/img', { encoding: 'base64' })
|
71 |
|
72 | // first we must post the media to Twitter
|
73 | T.post('media/upload', { media_data: b64content }, function (err, data, response) {
|
74 |
|
75 | // now we can reference the media and post a tweet (media will attach to the tweet)
|
76 | var mediaIdStr = data.media_id_string
|
77 | var params = { status: 'loving life #nofilter', media_ids: [mediaIdStr] }
|
78 |
|
79 | T.post('statuses/update', params, function (err, data, response) {
|
80 | console.log(data)
|
81 | })
|
82 | })
|
83 |
|
84 | //
|
85 | // stream a sample of public statuses
|
86 | //
|
87 | var stream = T.stream('statuses/sample')
|
88 |
|
89 | stream.on('tweet', function (tweet) {
|
90 | console.log(tweet)
|
91 | })
|
92 |
|
93 | //
|
94 | // filter the twitter public stream by the word 'mango'.
|
95 | //
|
96 | var stream = T.stream('statuses/filter', { track: 'mango' })
|
97 |
|
98 | stream.on('tweet', function (tweet) {
|
99 | console.log(tweet)
|
100 | })
|
101 |
|
102 | //
|
103 | // filter the public stream by the latitude/longitude bounded box of San Francisco
|
104 | //
|
105 | var sanFrancisco = [ '-122.75', '36.8', '-121.75', '37.8' ]
|
106 |
|
107 | var stream = T.stream('statuses/filter', { locations: sanFrancisco })
|
108 |
|
109 | stream.on('tweet', function (tweet) {
|
110 | console.log(tweet)
|
111 | })
|
112 |
|
113 | //
|
114 | // filter the public stream by english tweets containing `#apple`
|
115 | //
|
116 | var stream = T.stream('statuses/filter', { track: '#apple', language: 'en' })
|
117 |
|
118 | stream.on('tweet', function (tweet) {
|
119 | console.log(tweet)
|
120 | })
|
121 |
|
122 | ```
|
123 |
|
124 | # twit API:
|
125 |
|
126 | ##`var T = new Twit(config)`
|
127 |
|
128 | Create a `Twit` instance that can be used to make requests to Twitter's APIs.
|
129 |
|
130 | If authenticating with user context, `config` should be an object of the form:
|
131 | ```
|
132 | {
|
133 | consumer_key: '...'
|
134 | , consumer_secret: '...'
|
135 | , access_token: '...'
|
136 | , access_token_secret: '...'
|
137 | }
|
138 | ```
|
139 |
|
140 | If authenticating with application context, `config` should be an object of the form:
|
141 | ```
|
142 | {
|
143 | consumer_key: '...'
|
144 | , consumer_secret: '...'
|
145 | , app_only_auth: true
|
146 | }
|
147 | ```
|
148 | Note that Application-only auth will not allow you to perform requests to API endpoints requiring
|
149 | a user context, such as posting tweets. However, the endpoints available can have a higher rate limit.
|
150 |
|
151 | ##`T.get(path, [params], callback)`
|
152 | GET any of the REST API endpoints.
|
153 |
|
154 | **path**
|
155 |
|
156 | The endpoint to hit. When specifying `path` values, omit the **'.json'** at the end (i.e. use **'search/tweets'** instead of **'search/tweets.json'**).
|
157 |
|
158 | **params**
|
159 |
|
160 | (Optional) parameters for the request.
|
161 |
|
162 | **callback**
|
163 |
|
164 | `function (err, data, response)`
|
165 |
|
166 | - `data` is the parsed data received from Twitter.
|
167 | - `response` is the [http.IncomingMessage](http://nodejs.org/api/http.html#http_http_incomingmessage) received from Twitter.
|
168 |
|
169 | ##`T.post(path, [params], callback)`
|
170 |
|
171 | POST any of the REST API endpoints. Same usage as `T.get()`.
|
172 |
|
173 | ##`T.getAuth()`
|
174 | Get the client's authentication tokens.
|
175 |
|
176 | ##`T.setAuth(tokens)`
|
177 | Update the client's authentication tokens.
|
178 |
|
179 | ##`T.stream(path, [params])`
|
180 | Use this with the Streaming API.
|
181 |
|
182 | **path**
|
183 |
|
184 | Streaming endpoint to hit. One of:
|
185 |
|
186 | - **'statuses/filter'**
|
187 | - **'statuses/sample'**
|
188 | - **'statuses/firehose'**
|
189 | - **'user'**
|
190 | - **'site'**
|
191 |
|
192 | For a description of each Streaming endpoint, see the [Twitter API docs](https://dev.twitter.com/docs/api/1.1#334).
|
193 |
|
194 | **params**
|
195 |
|
196 | (Optional) parameters for the request. Any Arrays passed in `params` get converted to comma-separated strings, allowing you to do requests like:
|
197 |
|
198 | ```javascript
|
199 | //
|
200 | // I only want to see tweets about my favorite fruits
|
201 | //
|
202 |
|
203 | // same result as doing { track: 'bananas,oranges,strawberries' }
|
204 | var stream = T.stream('statuses/filter', { track: ['bananas', 'oranges', 'strawberries'] })
|
205 |
|
206 | stream.on('tweet', function (tweet) {
|
207 | //...
|
208 | })
|
209 | ```
|
210 |
|
211 | # Using the Streaming API
|
212 |
|
213 | `T.stream(path, [params])` keeps the connection alive, and returns an `EventEmitter`.
|
214 |
|
215 | The following events are emitted:
|
216 |
|
217 | ##event: 'message'
|
218 |
|
219 | Emitted each time an object is received in the stream. This is a catch-all event that can be used to process any data received in the stream, rather than using the more specific events documented below.
|
220 | New in version 2.1.0.
|
221 |
|
222 | ```javascript
|
223 | stream.on('message', function (msg) {
|
224 | //...
|
225 | })
|
226 | ```
|
227 |
|
228 | ##event: 'tweet'
|
229 |
|
230 | Emitted each time a status (tweet) comes into the stream.
|
231 |
|
232 | ```javascript
|
233 | stream.on('tweet', function (tweet) {
|
234 | //...
|
235 | })
|
236 | ```
|
237 |
|
238 | ##event: 'delete'
|
239 |
|
240 | Emitted each time a status (tweet) deletion message comes into the stream.
|
241 |
|
242 | ```javascript
|
243 | stream.on('delete', function (deleteMessage) {
|
244 | //...
|
245 | })
|
246 | ```
|
247 |
|
248 | ##event: 'limit'
|
249 |
|
250 | Emitted each time a limitation message comes into the stream.
|
251 |
|
252 | ```javascript
|
253 | stream.on('limit', function (limitMessage) {
|
254 | //...
|
255 | })
|
256 | ```
|
257 |
|
258 | ##event: 'scrub_geo'
|
259 |
|
260 | Emitted each time a location deletion message comes into the stream.
|
261 |
|
262 | ```javascript
|
263 | stream.on('scrub_geo', function (scrubGeoMessage) {
|
264 | //...
|
265 | })
|
266 | ```
|
267 |
|
268 | ##event: 'disconnect'
|
269 |
|
270 | Emitted when a disconnect message comes from Twitter. This occurs if you have multiple streams connected to Twitter's API. Upon receiving a disconnect message from Twitter, `Twit` will close the connection and emit this event with the message details received from twitter.
|
271 |
|
272 | ```javascript
|
273 | stream.on('disconnect', function (disconnectMessage) {
|
274 | //...
|
275 | })
|
276 | ```
|
277 |
|
278 | ##event: 'connect'
|
279 |
|
280 | Emitted when a connection attempt is made to Twitter. The http `request` object is emitted.
|
281 |
|
282 | ```javascript
|
283 | stream.on('connect', function (request) {
|
284 | //...
|
285 | })
|
286 | ```
|
287 |
|
288 | ##event: 'connected'
|
289 |
|
290 | Emitted when the response is received from Twitter. The http `response` object is emitted.
|
291 |
|
292 | ```javascript
|
293 | stream.on('connected', function (response) {
|
294 | //...
|
295 | })
|
296 | ```
|
297 |
|
298 | ##event: 'reconnect'
|
299 |
|
300 | Emitted when a reconnection attempt to Twitter is scheduled. If Twitter is having problems or we get rate limited, we schedule a reconnect according to Twitter's [reconnection guidelines](https://dev.twitter.com/docs/streaming-apis/connecting). The last http `request` and `response` objects are emitted, along with the time (in milliseconds) left before the reconnect occurs.
|
301 |
|
302 | ```javascript
|
303 | stream.on('reconnect', function (request, response, connectInterval) {
|
304 | //...
|
305 | })
|
306 | ```
|
307 |
|
308 | ##event: 'warning'
|
309 |
|
310 | This message is appropriate for clients using high-bandwidth connections, like the firehose. If your connection is falling behind, Twitter will queue messages for you, until your queue fills up, at which point they will disconnect you.
|
311 |
|
312 | ```javascript
|
313 | stream.on('warning', function (warning) {
|
314 | //...
|
315 | })
|
316 | ```
|
317 |
|
318 | ##event: 'status_withheld'
|
319 |
|
320 | Emitted when Twitter sends back a `status_withheld` message in the stream. This means that a tweet was withheld in certain countries.
|
321 |
|
322 | ```javascript
|
323 | stream.on('status_withheld', function (withheldMsg) {
|
324 | //...
|
325 | })
|
326 | ```
|
327 |
|
328 | ##event: 'user_withheld'
|
329 |
|
330 | Emitted when Twitter sends back a `user_withheld` message in the stream. This means that a Twitter user was withheld in certain countries.
|
331 |
|
332 | ```javascript
|
333 | stream.on('user_withheld', function (withheldMsg) {
|
334 | //...
|
335 | })
|
336 | ```
|
337 |
|
338 | ##event: 'friends'
|
339 |
|
340 | Emitted when Twitter sends the ["friends" preamble](https://dev.twitter.com/docs/streaming-apis/messages#User_stream_messages) when connecting to a user stream. This message contains a list of the user's friends, represented as an array of user ids.
|
341 |
|
342 | ```javascript
|
343 | stream.on('friends', function (friendsMsg) {
|
344 | //...
|
345 | })
|
346 | ```
|
347 |
|
348 | ##event: 'direct_message'
|
349 |
|
350 | Emitted when a direct message is sent to the user. Unfortunately, Twitter has not documented this event for user streams.
|
351 |
|
352 | ```javascript
|
353 | stream.on('direct_message', function (directMsg) {
|
354 | //...
|
355 | })
|
356 | ```
|
357 |
|
358 | ##event: 'user_event'
|
359 |
|
360 | Emitted when Twitter sends back a [User stream event](https://dev.twitter.com/docs/streaming-apis/messages#User_stream_messages).
|
361 | See the Twitter docs for more information on each event's structure.
|
362 |
|
363 | ```javascript
|
364 | stream.on('user_event', function (eventMsg) {
|
365 | //...
|
366 | })
|
367 | ```
|
368 |
|
369 | In addition, the following user stream events are provided for you to listen on:
|
370 |
|
371 | * `blocked`
|
372 | * `unblocked`
|
373 | * `favorite`
|
374 | * `unfavorite`
|
375 | * `follow`
|
376 | * `unfollow`
|
377 | * `user_update`
|
378 | * `list_created`
|
379 | * `list_destroyed`
|
380 | * `list_updated`
|
381 | * `list_member_added`
|
382 | * `list_member_removed`
|
383 | * `list_user_subscribed`
|
384 | * `list_user_unsubscribed`
|
385 | * `unknown_user_event` (for an event that doesn't match any of the above)
|
386 |
|
387 | ###Example:
|
388 |
|
389 | ```javascript
|
390 | stream.on('favorite', function (event) {
|
391 | //...
|
392 | })
|
393 | ```
|
394 |
|
395 | ##event: 'error'
|
396 |
|
397 | Emitted when an API request or response error occurs.
|
398 | An `Error` object is emitted, with properties:
|
399 |
|
400 | ```js
|
401 | {
|
402 | message: '...', // error message
|
403 | statusCode: '...', // statusCode from Twitter
|
404 | code: '...', // error code from Twitter
|
405 | twitterReply: '...', // raw response data from Twitter
|
406 | allErrors: '...' // array of errors returned from Twitter
|
407 | }
|
408 | ```
|
409 |
|
410 | ##stream.stop()
|
411 |
|
412 | Call this function on the stream to stop streaming (closes the connection with Twitter).
|
413 |
|
414 | ##stream.start()
|
415 |
|
416 | Call this function to restart the stream after you called `.stop()` on it.
|
417 | Note: there is no need to call `.start()` to begin streaming. `Twit.stream` calls `.start()` for you.
|
418 |
|
419 | -------
|
420 |
|
421 | #What do I have access to?
|
422 |
|
423 | Anything in the Twitter API:
|
424 |
|
425 | * REST API Endpoints: https://dev.twitter.com/docs/api
|
426 | * Public stream endpoints: https://dev.twitter.com/docs/streaming-api/methods
|
427 | * User stream endpoints: https://dev.twitter.com/docs/streaming-api/user-streams
|
428 | * Site stream endpoints: https://dev.twitter.com/docs/streaming-api/site-streams
|
429 |
|
430 | -------
|
431 |
|
432 | Go here to create an app and get OAuth credentials (if you haven't already): https://dev.twitter.com/apps/new
|
433 |
|
434 |
|
435 | #How do I run the tests?
|
436 |
|
437 | Create two files: `config1.js` and `config2.js` at the root of the `twit` folder. They should contain two different sets of oauth credentials for twit to use (two accounts are needed for testing interactions). They should both look something like this:
|
438 |
|
439 | ```
|
440 | module.exports = {
|
441 | consumer_key: '...'
|
442 | , consumer_secret: '...'
|
443 | , access_token: '...'
|
444 | , access_token_secret: '...'
|
445 | }
|
446 | ```
|
447 |
|
448 | Then run the tests:
|
449 |
|
450 | ```
|
451 | npm test
|
452 | ```
|
453 |
|
454 | You can also run the example:
|
455 |
|
456 | ```
|
457 | node examples/rtd2.js
|
458 | ```
|
459 |
|
460 | ![iRTD2](http://dl.dropbox.com/u/32773572/RTD2_logo.png)
|
461 |
|
462 | The example is a twitter bot named [RTD2](https://twitter.com/#!/iRTD2) written using `twit`. RTD2 tweets about **github** and curates its social graph.
|
463 |
|
464 | -------
|
465 |
|
466 | [FAQ](https://github.com/ttezel/twit/wiki/FAQ)
|
467 |
|
468 | -------
|
469 |
|
470 | ## License
|
471 |
|
472 | (The MIT License)
|
473 |
|
474 | Copyright (c) by Tolga Tezel <tolgatezel11@gmail.com>
|
475 |
|
476 | Permission is hereby granted, free of charge, to any person obtaining a copy
|
477 | of this software and associated documentation files (the "Software"), to deal
|
478 | in the Software without restriction, including without limitation the rights
|
479 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
480 | copies of the Software, and to permit persons to whom the Software is
|
481 | furnished to do so, subject to the following conditions:
|
482 |
|
483 | The above copyright notice and this permission notice shall be included in
|
484 | all copies or substantial portions of the Software.
|
485 |
|
486 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
487 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
488 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
489 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
490 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
491 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
492 | THE SOFTWARE.
|
493 |
|
494 | ## Changelog
|
495 |
|
496 | ###2.1.0
|
497 | * Add `message` event.
|
498 |
|
499 | ###2.0.0
|
500 | * Implement Application-only auth
|
501 | * Remove oauth module as a dependency
|
502 |
|
503 | ###1.1.20
|
504 | * Implement support for POST /media/upload
|
505 | * Reconnect logic fix for streaming; add stall abort/reconnect timeout on first connection attempt.
|
506 |
|
507 | ###1.1.14
|
508 | * Emit `connected` event upon receiving the response from twitter
|
509 |
|
510 | ###1.0.0
|
511 | * now to stop and start the stream, use `stream.stop()` and `stream.start()` instead of emitting the `start` and `stop` events
|
512 | * If twitter sends a `disconnect` message, closes the stream and emits `disconnect` with the disconnect message received from twitter
|
513 |
|
514 | ###0.2.0
|
515 | * Updated `twit` for usage with v1.1 of the Twitter API.
|
516 |
|
517 | ###0.1.5
|
518 |
|
519 | * **BREAKING CHANGE** to `twit.stream()`. Does not take a callback anymore. It returns
|
520 | immediately with the `EventEmitter` that you can listen on. The `Usage` section in
|
521 | the Readme.md has been updated. Read it.
|
522 |
|
523 |
|
524 | ###0.1.4
|
525 |
|
526 | * `twit.stream()` has signature `function (path, params, callback)`
|