Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Refactor

+ Rewrite code to follow modern node conventions (fixes #2)
+ Replace old "tests" with new BDD tests
+ Bump version to 1.0
  • Loading branch information...
commit b6eb0f9ad0b7ed850c8073155a22272b19c1213b 1 parent b9dbce9
@kaimallea authored
View
3  .gitignore
@@ -1 +1,2 @@
-.npmignore
+.npmignore
+node_modules
View
45 README.md
@@ -4,29 +4,54 @@
## Command-line Usage
- goo.gl www.google.com
- goo.gl http://goo.gl/fbsS
- goo.gl www.google.com http://goo.gl/fbsS nba.com
+```bash
+$ goo.gl www.google.com
+http://www.google.com -> http://goo.gl/fbsS
-It'll automatically shorten or expand single or multiple urls
+$ goo.gl http://goo.gl/fbsS
+http://goo.gl/fbsS -> http://www.google.com/
+
+$ goo.gl www.google.com http://goo.gl/fbsS nba.com
+http://goo.gl/fbsS -> http://www.google.com/
+http://www.google.com -> http://goo.gl/fbsS
+http://nba.com -> http://goo.gl/d1T8
+
+$ goo.gl --key aBcDeFGhIjKLMnOPqRsT www.spotify.com
+http://www.spotify.com/ -> http://goo.gl/cJFAL
+```
+
+It'll shorten and/or expand one or more URLs at a time.
## Module Usage
+Methods return promises.
+
```javascript
var googl = require('goo.gl');
// Shorten a long url and output the result
-googl.shorten('http://www.google.com/', function (shortUrl) {
- console.log(shortUrl);
-});
+googl.shorten('http://www.google.com/')
+ .then(function (shortUrl) {
+ console.log(shortUrl);
+ }).
+ .catch(function (err) {
+ console.error(err.message);
+ });
// Set a developer key (see http://goo.gl/4DvFk for more info.)
googl.setKey('aBcDeFGhIjKLMnOPqRsT');
+// Get currently set developer key
+googl.getKey();
// Expand a goo.gl url and output the result
-googl.expand('http://goo.gl/fbsS', function (longUrl) {
- console.log(shortUrl);
+googl.expand('http://goo.gl/fbsS')
+ .then(function (longUrl) {
+ console.log(shortUrl);
+ })
+ .catch(function (err) {
+ console.error(err.message);
+ });
});
-```
+```
View
74 cli.js
@@ -1,33 +1,51 @@
#!/usr/bin/env node
+(function() {
+ 'use strict';
-var googl = require('./lib/googl.js'),
- url = require('url'),
- args = process.argv.slice(2),
- hostname = null;
+ var googl = require('./lib/googl.js'),
+ commander = require('commander'),
+ urlParser = require('url').parse;
-if (args.length) {
- args.forEach(function (val, index, array) {
- if (typeof url.parse(val).protocol === 'undefined') {
- val = 'http://' + val;
- }
-
- hostname = (typeof url.parse(val).hostname === 'undefined' ? '' :
- url.parse(val).hostname);
-
- if (!hostname) {
- console.log('Invalid url: %s', val);
- return;
- }
-
- if (hostname === 'goo.gl') {
- googl.expand(val, function (res) {
- console.log('%s -> %s', val, (res.longUrl || JSON.stringify(res)));
- });
- return;
+ commander
+ .version(googl.VERSION)
+ .usage('[options] <url ...>')
+ .option('-k, --key <api-key>', 'Specify an API key to use')
+ .parse(process.argv);
+
+ if (commander.args.length) {
+
+ if (commander.key) {
+ googl.setKey(commander.key);
}
-
- googl.shorten(val, function (res) {
- console.log('%s -> %s', val, (res.id || JSON.stringify(res)));
+
+ commander.args.forEach(function (url, index, array) {
+
+ if (!urlParser(url).protocol) {
+ url = 'http://' + url;
+ }
+
+ if ('goo.gl' === urlParser(url).hostname) {
+
+ googl.expand(url)
+ .then(function (longUrl) {
+ console.log('%s -> %s', url, longUrl);
+ })
+ .catch(function (err) {
+ console.error(err.message);
+ });
+
+ } else {
+
+ googl.shorten(url)
+ .then(function (shortUrl) {
+ console.log('%s -> %s', url, shortUrl);
+ })
+ .catch(function (err) {
+ console.error(err.message);
+ });
+
+ }
});
- });
-}
+ }
+
+}());
View
205 lib/googl.js
@@ -1,105 +1,134 @@
-var googl = (function () {
- var _url = require('url'),
- _https = require('https'),
- _querystring = require('querystring'),
- _apikey = '';
+(function() {
+ 'use strict';
+ var request = require('request'),
+ urlParser = require('url').parse,
+ Q = require('q'),
+ API_ENDPOINT = 'https://www.googleapis.com/urlshortener/v1/url',
+ API_KEY = '',
+ VERSION = '0.1.0';
- function _setKey(key) {
- _apikey = key || '';
- module.exports.key = _apikey;
- }
-
+ /**
+ * Send a request to the goo.gl API
+ * @param {string} type - can be 'shorten' or 'expand'
+ * @param {string} url - url to take action on
+ * @returns {promise}
+ */
+ function _googleRequest(type, url) {
+ var deferred = Q.defer(),
+ options = {
+ uri: API_ENDPOINT,
+ qs: {},
+ encoding: 'utf8',
+ json: true
+ };
- function _getKey () {
- return (_apikey ? _apikey : '');
- }
+ if (!url || typeof url !== 'string') {
+ deferred.reject(new Error('Invalid URL specified'));
+ return deferred.promise;
+ }
+ if (!urlParser(url).protocol) {
+ url = 'http://' + url;
+ }
- function _shorten (url, callback) {
- if (!url) {
- console.error('Please specify a valid url.');
- return;
+ if (API_KEY && typeof API_KEY === 'string') {
+ options.qs.key = API_KEY;
}
-
- if (typeof _url.parse(url).protocol === 'undefined') {
- url = 'http://' + url;
+
+ switch(type) {
+ case 'shorten':
+ options.method = 'POST';
+ options.body = { 'longUrl': url };
+ break;
+ case 'expand':
+ options.method = 'GET';
+ options.qs.shortUrl = url;
+ break;
+ default:
+ deferred.reject(new Error('Invalid operation'));
+ return deferred.promise;
}
-
- if (!callback) { callback = false; }
-
- var key = _getKey(),
- options = {
- host: 'www.googleapis.com',
- port: 443,
- path: '/urlshortener/v1/url' + (key ? '?' + _querystring.stringify({'key': key}) : ''),
- method: 'POST',
- headers: {
- 'content-type': 'application/json'
- }
- };
-
- var req = _https.request(options, function(res) {
- res.setEncoding('utf8');
- res.on('data', function (d) {
- d = JSON.parse(d);
- if (callback) {
- callback(d);
- } else {
- console.log(d.id || d.error);
- }
- });
+
+ request(options, function (error, res, body) {
+ if (error) {
+ deferred.reject(error);
+ } else if (res.statusCode !== 200) {
+ error = new Error(res.statusCode + ' - ' + body.error.message);
+ deferred.reject(error);
+ } else {
+ deferred.resolve(body);
+ }
});
-
- req.on('error', function(e) { console.error(e); });
- req.write(JSON.stringify({'longUrl': url}));
-
- req.end();
+ return deferred.promise;
}
+ /**
+ * Shorten a URL
+ * @param {string} url
+ * @returns {promise}
+ */
+ function shorten (url) {
+ var deferred = Q.defer();
- function _expand (url, callback) {
- if (!url) {
- console.error('Please specify a valid url.');
- return;
- }
+ _googleRequest('shorten', url)
+ .then(function (json) {
+ deferred.resolve(json.id);
+ })
+ .catch(function (error) {
+ deferred.reject(error);
+ });
- if (typeof _url.parse(url).protocol === 'undefined') {
- url = 'http://' + url;
- }
-
- if (!callback) { callback = false; }
-
- var key = _getKey(),
- options = {
- host: 'www.googleapis.com',
- path: '/urlshortener/v1/url?' +
- (key ? _querystring.stringify({'key': key, 'shortUrl': url}) :
- _querystring.stringify({'shortUrl': url}))
- };
-
- _https.get(options, function(res) {
- res.setEncoding('utf8');
- res.on('data', function (d) {
- d = JSON.parse(d);
- if (callback) {
- callback(d);
- } else {
- console.log(d.longUrl || d.error);
- }
+ return deferred.promise;
+ }
+
+ /**
+ * Expand a URL
+ * @param {string} url
+ * @returns {promise}
+ */
+ function expand (url) {
+ var deferred = Q.defer();
+
+ _googleRequest('expand', url)
+ .then(function (json) {
+ deferred.resolve(json.longUrl);
+ })
+ .catch(function (error) {
+ deferred.reject(error);
});
-
- }).on('error', function(e) {
- console.error(e);
- });
+
+ return deferred.promise;
}
-
- return {
- 'shorten': _shorten,
- 'expand': _expand,
- 'setKey': _setKey
+
+ /**
+ * Set an API key to use when making requests
+ * @param {string} API key
+ * @returns {string} API key
+ */
+ function setKey (key) {
+ if (typeof key === 'string') {
+ API_KEY = key;
+ }
+
+ return API_KEY;
+ }
+
+ /**
+ * Get currently set API key
+ * @returns {string} API key
+ */
+ function getKey () {
+ return API_KEY;
+ }
+
+ module.exports = {
+ _googleRequest: _googleRequest,
+ shorten: shorten,
+ expand: expand,
+ setKey: setKey,
+ getKey: getKey,
+ VERSION: VERSION
};
}());
-
-module.exports = googl;
View
41 package.json
@@ -1,19 +1,42 @@
{
- "author": "Kai Mallea <kmallea@gmail.com> (http://www.mallea.net/)",
+ "author": "Kai Mallea <kmallea@gmail.com>",
"name": "goo.gl",
- "description": "A url shortener and expander powered by Google's URL shorting service",
- "version": "0.0.2",
+ "description": "A url shortener and expander powered by Google's URL shortening service",
+ "version": "0.1.0",
"homepage": "https://github.com/kaimallea/node-googl",
- "keywords": ["google", "googl", "goo.gl", "urls", "shortner", "expander"],
+ "keywords": [
+ "google",
+ "googl",
+ "goo.gl",
+ "url",
+ "urls",
+ "short",
+ "shorten",
+ "shortener",
+ "expander"
+ ],
"repository": {
"type": "git",
"url": "git://github.com/kaimallea/node-googl.git"
},
"engines": {
- "node": ">= v0.4.9"
+ "node": ">= v0.10.20"
+ },
+ "dependencies": {
+ "request": "~2.34.0",
+ "commander": "~2.2.0",
+ "q": "~1.0.1"
},
- "dependencies": {},
- "devDependencies": {},
"main": "lib/googl.js",
- "bin": { "goo.gl": "./cli.js" }
-}
+ "bin": {
+ "goo.gl": "./cli.js"
+ },
+ "scripts": {
+ "test": "node_modules/.bin/mocha"
+ },
+ "devDependencies": {
+ "mocha": "~1.18.2",
+ "chai": "~1.9.1",
+ "chai-as-promised": "~4.1.1"
+ }
+}
View
56 test/expand.js
@@ -0,0 +1,56 @@
+(function() {
+ 'use strict';
+
+ var googl = require('../lib/googl.js'),
+ chai = require('chai'),
+ chaiAsPromised = require('chai-as-promised'),
+ expect = chai.expect;
+
+ chai.use(chaiAsPromised);
+
+ describe('#expand()', function() {
+ beforeEach(function() {
+ googl.setKey('');
+ });
+
+ it('should expand a goo.gl url', function(done) {
+ var url = 'http://goo.gl/cJFAL',
+ urlExpanded = 'http://www.spotify.com/';
+
+ expect(googl.expand(url))
+ .to.eventually.equal(urlExpanded)
+ .and.notify(done);
+ });
+
+ it('should expand a url with a valid key');
+
+ it('should not expand a url with an invalid key', function(done) {
+ var url = 'http://goo.gl/cJFAL',
+ errMsg = '400 - Bad Request';
+
+ googl.setKey('nope');
+
+ expect(googl.expand(url))
+ .to.be.rejectedWith(errMsg)
+ .and.notify(done);
+ });
+
+ it('should expand a goo.gl url without a protocol', function(done) {
+ var url = 'http://goo.gl/cJFAL',
+ urlExpanded = 'http://www.spotify.com/';
+
+ expect(googl.expand(url))
+ .to.eventually.equal(urlExpanded)
+ .and.notify(done);
+ });
+
+ it('should fail on non goo.gl urls', function(done) {
+ var url = 'http://bit.ly/hello',
+ errMsg = '400 - Invalid Value';
+
+ expect(googl._googleRequest('expand', url))
+ .to.be.rejectedWith(errMsg)
+ .and.notify(done);
+ });
+ });
+}());
View
23 test/getKey.js
@@ -0,0 +1,23 @@
+(function() {
+ 'use strict';
+
+ var googl = require('../lib/googl.js'),
+ chai = require('chai'),
+ chaiAsPromised = require('chai-as-promised'),
+ expect = chai.expect;
+
+ chai.use(chaiAsPromised);
+
+ describe('#getKey()', function() {
+ it('should return an empty key if nothing is set', function() {
+ return expect(googl.getKey()).to.equal('');
+ });
+
+ it('should return the same key that was set', function() {
+ var key = 'abcDEF123456';
+ googl.setKey(key);
+
+ return expect(googl.getKey()).to.equal(key);
+ });
+ });
+}());
View
59 test/googleRequest.js
@@ -0,0 +1,59 @@
+(function() {
+ 'use strict';
+
+ var googl = require('../lib/googl.js'),
+ chai = require('chai'),
+ chaiAsPromised = require('chai-as-promised'),
+ expect = chai.expect;
+
+ chai.use(chaiAsPromised);
+
+ describe('#_googleRequest()', function() {
+ beforeEach(function() {
+ googl.setKey('');
+ });
+
+ it('should fail with no input', function(done) {
+ var errMsg = 'Invalid URL specified';
+
+ expect(googl._googleRequest())
+ .to.be.rejectedWith(errMsg)
+ .and.notify(done);
+ });
+
+ it('should fail with no url', function(done) {
+ var errMsg = 'Invalid URL specified';
+
+ expect(googl._googleRequest('shorten'))
+ .to.be.rejectedWith(errMsg)
+ .and.notify(done);
+ });
+
+ it('should shorten a url', function(done) {
+ var url = 'http://www.spotify.com',
+ urlShortened = 'http://goo.gl/cJFAL';
+
+ expect(googl._googleRequest('shorten', url))
+ .to.eventually.be.fulfilled
+ .and.notify(done);
+ });
+
+ it('should expand a url', function(done) {
+ var url = 'http://www.spotify.com',
+ urlShortened = 'http://goo.gl/cJFAL';
+
+ expect(googl._googleRequest('expand', urlShortened))
+ .to.eventually.be.fulfilled
+ .and.notify(done);
+ });
+
+ it('should fail as invalid operation when shorten or expand not used', function(done) {
+ var errMsg = 'Invalid operation',
+ url = 'https://www.spotify.com/';
+
+ expect(googl._googleRequest('asdf', url))
+ .to.be.rejectedWith(errMsg)
+ .and.notify(done);
+ });
+ });
+}());
View
1  test/mocha.opts
@@ -0,0 +1 @@
+--reporter spec
View
28 test/setKey.js
@@ -0,0 +1,28 @@
+(function() {
+ 'use strict';
+
+ var googl = require('../lib/googl.js'),
+ chai = require('chai'),
+ chaiAsPromised = require('chai-as-promised'),
+ expect = chai.expect;
+
+ chai.use(chaiAsPromised);
+
+ describe('#setKey()', function() {
+ beforeEach(function() {
+ googl.setKey('');
+ });
+
+ it('should return the key that was set', function() {
+ var key = 'abcDEF123456';
+
+ return expect(googl.setKey(key)).to.equal(key);
+ });
+
+ it('should return the key that was set', function() {
+ var key = '';
+
+ return expect(googl.setKey(key)).to.equal(key);
+ });
+ });
+}());
View
81 test/shorten.js
@@ -0,0 +1,81 @@
+(function() {
+ 'use strict';
+
+ var googl = require('../lib/googl.js'),
+ chai = require('chai'),
+ chaiAsPromised = require('chai-as-promised'),
+ expect = chai.expect;
+
+ chai.use(chaiAsPromised);
+
+ describe('#shorten()', function() {
+ beforeEach(function() {
+ googl.setKey('');
+ });
+
+ it('should fail with no input', function(done) {
+ var errMsg = 'Invalid URL specified';
+
+ expect(googl.expand())
+ .to.be.rejectedWith(errMsg)
+ .and.notify(done);
+ });
+
+ it('should fail with an empty string as input', function(done) {
+ var errMsg = 'Invalid URL specified';
+
+ expect(googl.expand(''))
+ .to.be.rejectedWith(errMsg)
+ .and.notify(done);
+ });
+
+ it('should fail as invalid value with bad url', function(done) {
+ var url = 'http:/www.google.com', // one slash
+ errMsg = '400 - Invalid Value';
+
+ expect(googl.expand(url))
+ .to.be.rejectedWith(errMsg)
+ .and.notify(done);
+ });
+
+ it('should shorten a url', function(done) {
+ var url = 'http://www.spotify.com',
+ urlShortened = 'http://goo.gl/cJFAL';
+
+ expect(googl.shorten(url))
+ .to.eventually.equal(urlShortened)
+ .and.notify(done);
+ });
+
+ it('should shorten a url with a valid key');
+
+ it('should not shorten a url with an invalid key', function(done) {
+ var url = 'http://goo.gl/cJFAL',
+ errMsg = '400 - Bad Request';
+
+ googl.setKey('nope');
+
+ expect(googl.shorten(url))
+ .to.be.rejectedWith(errMsg)
+ .and.notify(done);
+ });
+
+ it('should shorten a url without the protocol', function(done) {
+ var url = 'www.spotify.com',
+ urlShortened = 'http://goo.gl/cJFAL';
+
+ expect(googl.shorten(url))
+ .to.eventually.equal(urlShortened)
+ .and.notify(done);
+ });
+
+ it('should shorten a url without a protocol or sub-domain', function(done) {
+ var url = 'spotify.com',
+ urlShortened = 'http://goo.gl/ZZ0D3';
+
+ expect(googl.shorten(url))
+ .to.eventually.equal(urlShortened)
+ .and.notify(done);
+ });
+ });
+}());
View
13 tests/googl-tests.js
@@ -1,13 +0,0 @@
-var googl = require('../lib/googl.js'),
- assert = require('assert');
-
-googl.shorten('http://www.google.com/', function (result) {
- assert.equal(result.id, 'http://goo.gl/fbsS');
-});
-
-googl.expand('http://goo.gl/fbsS', function (result) {
- assert.equal(result.longUrl, 'http://www.google.com/');
-});
-
-googl.setKey('ABCDEFGabcdefg01234567');
-assert.equal(googl.key, 'ABCDEFGabcdefg01234567');
Please sign in to comment.
Something went wrong with that request. Please try again.