├── .gitignore ├── .jshintrc ├── .npmignore ├── README.md ├── bin └── node-ddg.js ├── index.js ├── lib └── ddg.js ├── package.json └── test └── ddg-test.js /.gitignore: -------------------------------------------------------------------------------- 1 | npm-debug.log 2 | node_modules 3 | test.js -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "node": true, 3 | "strict": true 4 | } -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | test.js 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # node-ddg-api - DuckDuckGo instant answer API node module 2 | 3 | > Access the [DuckDuckGo](https://duckduckgo.com/api) API with [Nodejs](http://nodejs.org). 4 | 5 | ## Dependencies 6 | 7 | Only depends on [optimist](https://npmjs.org/package/optimist) for the cli but the core has no dependencies. 8 | 9 | ## Installation 10 | 11 | To install via NPM type the following: `npm install node-ddg-api` 12 | 13 | (use `npm install -g node-ddg-api` to add node-ddg bin script to your path) 14 | 15 | You can also install via git by cloning: 16 | 17 | ```shell 18 | git clone https://github.com/lukewendling/ddg-api.git /path/to/project 19 | ``` 20 | 21 | ## Usage 22 | 23 | ```js 24 | var DDG = require('node-ddg-api').DDG; 25 | 26 | var ddg = new DDG('my-app-name'); 27 | 28 | ddg.instantAnswer('superman', {skip_disambig: '0'}, function(err, response) { 29 | console.log(response); 30 | }); 31 | ``` 32 | 33 | ```shell 34 | node-ddg superman -t my-app-name --skip_disambig 0 35 | ``` 36 | 37 | ## Running tests (after cloning) 38 | 39 | ```shell 40 | npm install 41 | npm test 42 | ``` 43 | -------------------------------------------------------------------------------- /bin/node-ddg.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | 'use strict'; 4 | 5 | var DDG = require('../index').DDG, 6 | argv = require('optimist') 7 | .usage('Query DuckDuckGo Instant Answer API\nPass exact options as shown: https://duckduckgo.com/api\nUsage: $0 --t appname --pretty 1 --skip_disambig 1') 8 | .demand('t') 9 | .describe('t', 'Tell DDG the name of your app') 10 | .argv, 11 | ddg = new DDG(argv.t); 12 | 13 | ddg.instantAnswer(argv._[0], argv); -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | exports.DDG = require('./lib/ddg'); -------------------------------------------------------------------------------- /lib/ddg.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var url = require('url'); 4 | var http; 5 | 6 | // Constructor 7 | // appName: tell DDG the name of your app 8 | // opts (optional): 'session' options. change the value to 443 for SSL 9 | var DDG = function (appName, opts) { 10 | var config; 11 | 12 | this.appName = appName; 13 | 14 | if (opts === undefined || opts === null) { 15 | opts = {}; 16 | } 17 | 18 | config = { 19 | hostname: opts.hostname || 'api.duckduckgo.com', 20 | port: opts.port || 80 21 | }; 22 | 23 | http = require(config.port === 443 ? 'https' : 'http'); 24 | 25 | this.config = config; 26 | 27 | return this; 28 | }; 29 | 30 | // query instant answer api 31 | // term: search term 32 | // opts (optional): per-request options like 'skip_disambig' 33 | // callback (optional) 34 | DDG.prototype.instantAnswer = function (term, opts, callback) { 35 | if (opts === undefined || opts === null) { 36 | opts = {}; 37 | } 38 | 39 | // log response to console by default 40 | if (callback === undefined || callback === null) { 41 | callback = function (err, response) { console.log(response); }; 42 | } 43 | 44 | this.searchTerm = term; 45 | 46 | return this.query(this.buildReqParams(opts), callback); 47 | }; 48 | 49 | DDG.prototype.buildReqParams = function (opts) { 50 | return { 51 | hostname: this.config.hostname, 52 | port: this.config.port, 53 | path: this.buildQueryString(opts) 54 | }; 55 | }; 56 | 57 | DDG.prototype.buildQueryString = function (opts) { 58 | var pathParts, params, queryString; 59 | 60 | // per-request params 61 | params = { 62 | q: this.searchTerm, 63 | pretty: opts.pretty || '1', 64 | no_html: opts.no_html || '0', 65 | no_redirect: opts.no_redirect || '0', 66 | skip_disambig: opts.skip_disambig || '0' 67 | }; 68 | 69 | // per 'session' params 70 | params.format = 'json'; 71 | params.t = this.appName; 72 | 73 | pathParts = { 74 | pathname: '/', 75 | query: params 76 | }; 77 | 78 | this.queryString = url.format(pathParts); 79 | return this.queryString; 80 | }; 81 | 82 | DDG.prototype.query = function (params, callback) { 83 | var req = http.request(params, function (res) { 84 | var data = []; 85 | res 86 | .on('data', function (chunk) { data.push(chunk); }) 87 | .on('end', function () { 88 | data = data.join('').trim(); 89 | var result; 90 | try { 91 | result = JSON.parse(data); 92 | } catch (exp) { 93 | result = {'status_code': 500, 'status_text': 'JSON Parse Failed'}; 94 | } 95 | callback(null, result); 96 | }); 97 | }); 98 | req.end(); 99 | 100 | req.on('error', function (e) { 101 | callback(e); 102 | }); 103 | }; 104 | 105 | module.exports = DDG; -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-ddg-api", 3 | "version": "0.1.4", 4 | "main": "./index.js", 5 | "author": "Luke Wendling ", 6 | "license": "BSD", 7 | "description": "A Node.JS module to query the duckduckgo instant answers API.", 8 | "keywords": ["duckduckgo", "search", "answer"], 9 | "dependencies": { 10 | "optimist": "~0.6" 11 | }, 12 | "devDependencies": { 13 | "nodeunit": ">=0.7" 14 | }, 15 | "bin": { 16 | "node-ddg": "./bin/node-ddg.js" 17 | }, 18 | "scripts": { 19 | "test": "./node_modules/.bin/nodeunit test --reporter nested" 20 | }, 21 | "repository": { 22 | "type": "git", 23 | "url": "git://github.com/lukewendling/ddg-api.git" 24 | } 25 | } -------------------------------------------------------------------------------- /test/ddg-test.js: -------------------------------------------------------------------------------- 1 | var DDG = require('../lib/ddg'); 2 | 3 | exports.testConstructor = { 4 | 5 | setUp: function (callback) { 6 | this.ddg = new DDG('test-app'); 7 | callback(); 8 | }, 9 | 10 | 'constructor sets app name' : function (test) { 11 | test.equal(this.ddg.appName, 'test-app'); 12 | test.done(); 13 | }, 14 | 15 | 'constructor sets default config' : function (test) { 16 | test.deepEqual(this.ddg.config, { hostname: 'api.duckduckgo.com', port: 80 }); 17 | test.done(); 18 | }, 19 | 20 | 'constructor sets custom config' : function (test) { 21 | var ddg = new DDG('test-app', { port: 443 }); 22 | test.deepEqual(ddg.config, { hostname: 'api.duckduckgo.com', port: 443 }); 23 | test.done(); 24 | } 25 | 26 | }; 27 | 28 | exports.testInstantAnswer = { 29 | 30 | setUp: function (callback) { 31 | this.ddg = new DDG('test-app'); 32 | callback(); 33 | }, 34 | 35 | 'returns result of request' : function (test) { 36 | this.ddg.query = function () { return 'super' }; 37 | 38 | test.equal(this.ddg.instantAnswer('superman'), 'super'); 39 | test.done(); 40 | }, 41 | 42 | 'builds query string' : function (test) { 43 | var opts = {skip_disambig: '1', pretty: '0', no_html: '1', no_redirect: '1'}; 44 | 45 | this.ddg.query = function () { return 'super' }; 46 | this.ddg.instantAnswer('superman', opts); 47 | 48 | test.equal(this.ddg.queryString, "/?q=superman&pretty=0&no_html=1&no_redirect=1&skip_disambig=1&format=json&t=test-app"); 49 | test.done(); 50 | } 51 | }; --------------------------------------------------------------------------------