Skip to content

Commit

Permalink
Adds support for preset endpoint base paths and completes test covera…
Browse files Browse the repository at this point in the history
…ge for the constructor
  • Loading branch information
desmondmorris committed Jan 25, 2015
1 parent 0198892 commit 8ee7a95
Show file tree
Hide file tree
Showing 4 changed files with 273 additions and 125 deletions.
92 changes: 64 additions & 28 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,36 @@
Twitter for Node.js [![NPM](https://nodei.co/npm/twitter.png?mini=true)](https://nodei.co/npm/twitter/) [![wercker status](https://app.wercker.com/status/624dbe8ad011852d1e01d7dc03941fc5/s/master "wercker status")](https://app.wercker.com/project/bykey/624dbe8ad011852d1e01d7dc03941fc5)
======================================
# Twitter for Node.js

[node-twitter](https://github.com/desmondmorris/node-twitter) aims to provide a complete, asynchronous client library for the Twitter API, including the REST, search and streaming endpoints. It's a fork of [@jdub](https://github.com/jdub)'s [twitter-node](https://github.com/jdub) which was inspired by, and used some code from, [@technoweenie](https://github.com/technoweenie)'s [twitter-node](https://github.com/technoweenie/twitter-node).
An asynchronous client library for the Twitter [REST](https://dev.twitter.com/rest/public) and [Streaming](https://dev.twitter.com/streaming/overview) API's.

[![wercker status](https://app.wercker.com/status/624dbe8ad011852d1e01d7dc03941fc5/s/master "wercker status")](https://app.wercker.com/project/bykey/624dbe8ad011852d1e01d7dc03941fc5) [![NPM](https://nodei.co/npm/twitter.png?mini=true)](https://nodei.co/npm/twitter/)

```javascript
var Twitter = require('twitter');

var t = new Twitter({
consumer_key: '',
consumer_secret: '',
access_token_key: '',
access_token_secret: ''
});

var params = {screen_name: 'nodejs'};
t.get('statuses/user_timeline', params, function(error, tweets, response){
if (!error) {
console.log(tweets);
}
});
```

## Installation

`npm install twitter`

## Configuration
## Quick Start

You will need valid Twitter developer credentials in the form of a set of consumer and access tokens/keys. You can get these [here](https://apps.twitter.com/). Do not forgot to adjust your permissions - most POST request require write permissions.

````
```javascript
var Twitter = require('twitter');

var client = new Twitter({
Expand All @@ -20,69 +39,86 @@ var client = new Twitter({
access_token_key: '',
access_token_secret: ''
});
````
```

Add your credentials accordingly. I would use environment variables to keep your private info safe. So something like:

````
```javascript
var client = new Twitter({
consumer_key: process.env.TWITTER_CONSUMER_KEY,
consumer_secret: process.env.TWITTER_CONSUMER_SECRET,
access_token_key: process.env.TWITTER_ACCESS_TOKEN_KEY,
access_token_secret: process.env.TWITTER_ACCESS_TOKEN_SECRET,
});
````
```

## Usage
You now have the ability to make GET and POST requests against the API via the convenience methods.

The library comes with two helper methods for `get` and `post` requests. To use, you simply need to pass the API path and parameters. Example, lets get a list of favorites:
```javascript
client.get(path, params, callback);
client.post(path, params, callback);
client.stream(path, params, callback);
```

````
// @see configuration above for the client variable
## REST API

client.get('favorites/list', function(error, params, response){
You simply need to pass the endpoint and parameters to one of convenience methods. Take a look at the [documentation site](https://dev.twitter.com/rest/public) to reference available endpoints.

Example, lets get a [list of favorites](https://dev.twitter.com/rest/reference/get/favorites/list):

```javascript
client.get('favorites/list', function(error, tweets, response){

if(error) throw error;

console.log(params); // The favorites.
console.log(tweets); // The favorites.

console.log(response); // Raw response object.

});
```

````

How about an example that passes parameters? Let's post a tweet:
How about an example that passes parameters? Let's [tweet something](https://dev.twitter.com/rest/reference/post/statuses/update):

````
// @see configuration above for the client variable
client.post('statuses/update', {status: 'TYBG for twitter'}, function(error, params, response){
```javascript
client.post('statuses/update', {status: 'I Love Twitter'}, function(error, tweet, response){

if(error) throw error;

console.log(params); // Tweet body.
console.log(tweet); // Tweet body.

console.log(response); // Raw response object.

});
````
```

Or even streaming? Let's see whose talking about javascript:
## Streaming API

````
// @see configuration above for the client variable
Using the `stream` convenience method, you to open and manipulate data via a stream piped directly from one of the streaming API's. Let's see who is talking about javascript:

```javascript
client.stream('statuses/filter', {track: 'javascript'}, function(stream) {

stream.on('data', function(tweet) {
console.log(tweet.text);
});

stream.on('error', function(error) {
throw error;
});

});
````
```

## Contributors

Originally authored by [@technoweenie](http://github.com/technoweenie)
and maintained by [@jdub](http://github.com/jdub)

Currently maintained by [@desmondmorris](http://github.com/desmondmorris)

[And we cannot forget the community](https://github.com/desmondmorris/node-twitter/graphs/contributors)

## [1.x Changes](https://github.com/desmondmorris/node-twitter/wiki/1.x)

## LICENSE

Expand Down
87 changes: 41 additions & 46 deletions lib/twitter.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,31 +17,30 @@ function Twitter (options) {

this.VERSION = VERSION;

var defaults = {
// Merge the default options with the client submitted options
this.options = extend({
consumer_key: null,
consumer_secret: null,
access_token_key: null,
access_token_secret: null,

rest_base: 'https://api.twitter.com/1.1',
stream_base: 'https://stream.twitter.com/1.1',
user_stream_base: 'https://userstream.twitter.com/1.1',
site_stream_base: 'https://sitestream.twitter.com/1.1',
filter_stream_base: 'https://stream.twitter.com/1.1/statuses',
media_base: 'https://upload.twitter.com/1.1',

request_options: {
headers: {
'Accept': '*/*',
'Connection': 'close',
'User-Agent': 'node-twitter/' + VERSION
}
}
};
this.options = extend(defaults, options);
}, options);

// Build a request object
this.request = request.defaults(
extend(
// Pass the client submitted request options
this.options.request_options,
{
oauth: {
Expand All @@ -53,44 +52,38 @@ function Twitter (options) {
}
)
);
}

this.__generateURL = function(path) {

var bases = {
'rest': this.options.rest_base,
'stream': this.options.stream_base,
'user_stream': this.options.user_stream_base,
'site_stream': this.options.site_stream_base,
'media_base': this.options.media_base,
};

//var uri = (bases.hasOwnProperty(base)) ? base[base] : base.rest;
Twitter.prototype.__buildEndpoint = function(path, base) {

if (url.parse(path).protocol === null) {
if (path.charAt(0) !== '/') {
path = '/' + path;
}
var bases = {
'rest': this.options.rest_base,
'stream': this.options.stream_base,
'user_stream': this.options.user_stream_base,
'site_stream': this.options.site_stream_base,
'media': this.options.media_base,
};
var endpoint = (bases.hasOwnProperty(base)) ? bases[base] : bases.rest;

switch (true) {
case /^\/media/.test(path):
path = this.options.media_base + path;
break;
default:
path = this.options.rest_base + path;
break;
}
if (url.parse(path).protocol !== null) {
endpoint = path;
}
else {
// If the path begins with media or /media
if (path.match(/^(\/)?media/)) {
endpoint = bases.media;
}
endpoint += (path.charAt(0) === '/') ? path : '/' + path;
}

// Remove trailing slash
path = path.replace(/\/$/, "");

// Add json extension if not provided in call
path += (path.split('.').pop() !== 'json') ? '.json' : '';
// Remove trailing slash
endpoint = endpoint.replace(/\/$/, "");

return path;
};
}
// Add json extension if not provided in call
endpoint += (path.split('.').pop() !== 'json') ? '.json' : '';

return endpoint;
};

Twitter.prototype.__request = function(method, path, params, callback) {
// Set the callback if no params are passed
Expand All @@ -99,11 +92,12 @@ Twitter.prototype.__request = function(method, path, params, callback) {
params = {};
}

// Build the options to pass to our custom request object
var options = {
method: method.toLowerCase(),
url: this.__generateURL(path),
qs: (method === 'get') ? params : {},
form: (method === 'post') ? params : {}
method: method.toLowerCase(), // Request method - get || post
url: this.__buildEndpoint(path), // Generate url
qs: (method === 'get') ? params : {}, // Pass url parameters if get
form: (method === 'post') ? params : {} // Pass form data if post
};

this.request(options, function(error, response, data){
Expand Down Expand Up @@ -162,31 +156,31 @@ Twitter.prototype.stream = function (method, params, callback) {
params = {};
}

var stream_base = this.options.stream_base;
var base = 'stream';

// Stream type customisations
if (method === 'user') {
stream_base = this.options.user_stream_base;
base = 'user_stream';
// Workaround for node-oauth vs. twitter commas-in-params bug
if ( params && params.track && Array.isArray(params.track) ) {
params.track = params.track.join(',');
}

} else if (method === 'site') {
stream_base = this.options.site_stream_base;
base = 'site_stream';
// Workaround for node-oauth vs. twitter double-encode-commas bug
if ( params && params.follow && Array.isArray(params.follow) ) {
params.follow = params.follow.join(',');
}
} else if (method === 'filter') {
stream_base = this.options.filter_stream_base;
base = 'stream';
// Workaround for node-oauth vs. twitter commas-in-params bug
if ( params && params.track && Array.isArray(params.track) ) {
params.track = params.track.join(',');
}
}

var url = this.__generateURL(stream_base + '/' + escape(method));
var url = this.__buildEndpoint(method, base);

var request = this.request({ url: url, qs: params});

Expand Down Expand Up @@ -277,4 +271,5 @@ Twitter.prototype.stream = function (method, params, callback) {
}
};


module.exports = Twitter;
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,16 @@
},
"scripts": {
"test": "npm run lint && mocha",
"lint": "jshint test/*.js lib/*.js examples/*.js && echo Lint passed."
"lint": "jshint test/*.js lib/*.js && echo Lint passed."
},
"dependencies": {
"deep-extend": "^0.3.2",
"request": "^2.51.0"
},
"devDependencies": {
"jshint": "^2.6.0",
"mocha": "^2.1.0"
"mocha": "^2.1.0",
"nock": "^0.57.0"
},
"main": "./lib/twitter",
"jshintConfig": {
Expand Down

0 comments on commit 8ee7a95

Please sign in to comment.