Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
160 changes: 140 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,28 +1,148 @@
# News API SDK for Node (javascript)
Coming soon... this is where our officially supported SDK for Node JS is going to live.
# newsapi

***
A node interface for NewsAPI.

News API is a simple HTTP REST API for searching and retrieving live articles from all over the web. It can help you answer questions like:
[![npm](https://img.shields.io/npm/v/newsapi.svg)](https://www.npmjs.com/package/newsapi)
[![npm](https://img.shields.io/npm/dt/newsapi.svg)](https://www.npmjs.com/package/newsapi)
[![Build Status](https://travis-ci.org/bzarras/newsapi.svg?branch=master)](https://travis-ci.org/bzarras/newsapi)

- What top stories is the NY Times running right now?
- What new articles were published about the next iPhone today?
- Has my company or product been mentioned or reviewed by any blogs recently?
- How many social shares has an article received? (Coming soon!)
Up-to-date news headlines and metadata in JSON from 70+ popular news sites. Powered by NewsAPI.org.

You can search for articles with any combination of the following criteria:
You will need an API key from [https://newsapi.org](https://newsapi.org).

- Keyword or phrase. Eg: find all articles containing the word 'Microsoft'.
- Date published. Eg: find all articles published yesterday.
- Source name. Eg: find all articles by 'TechCrunch'.
- Source domain name. Eg: find all articles published on nytimes.com.
- Language. Eg: find all articles written in English.
Please look at their [documentation](https://newsapi.org/docs) to see how to use the API. The convenience functions provided by this module
simply pass their options along as querystring parameters to the REST API, so the [documentation](https://newsapi.org/docs)
is totally valid. There are some usage examples below to see how these options should be passed in.

You can sort the results in the following orders:
If you use this in a project, add a 'powered by' attribution link back to NewsAPI.org

- Date published
- Relevancy to search keyword
- Popularity of source
- Social shares (Coming soon!)
## Add to your project
```shell
$ npm install newsapi --save
```

You need an API key to use the API - this is a unique key that identifies your requests. They're free for development, open-source, and non-commercial use. You can get one here: [https://newsapi.org](https://newsapi.org).
## Test
```shell
$ API_KEY=<your api key> npm test
```

## Example usage of v2 API
All methods support promises and node-style callbacks.
```js
const NewsAPI = require('newsapi');
const newsapi = new NewsAPI('YOUR_API_KEY');

// To query top headlines
// All options passed to topHeadlines are optional, but you need to include at least one of them
newsapi.v2.topHeadlines({
sources: 'bbc-news,the-verge',
q: 'trump',
category: 'politics',
language: 'en',
country: 'us'
}).then(response => {
console.log(response);
/*
{
status: "ok",
articles: [...]
}
*/
});

// To query everything
// You must include at least one q, source, or domain
newsapi.v2.everything({
q: 'trump',
sources: 'bbc-news,the-verge',
domains: 'bbc.co.uk, techcrunch.com',
from: '2017-12-01',
to: '2017-12-12',
language: 'en',
sortBy: 'relevancy',
page: 2
}).then(response => {
console.log(response);
/*
{
status: "ok",
articles: [...]
}
*/
});

// To query sources
// All options are optional
newsapi.v2.sources({
category: 'technology',
language: 'en',
country: 'us'
}).then(response => {
console.log(response);
/*
{
status: "ok",
sources: [...]
}
*/
});
```

## Example usage of v1 legacy API
```js
const NewsAPI = require('newsapi');
const newsapi = new NewsAPI('YOUR_API_KEY');

// To query articles:
newsapi.articles({
source: 'associated-press', // required
sortBy: 'top' // optional
}).then(articlesResponse => {
console.log(articlesResponse);
/*
{
status: "ok",
source: "associated-press",
sortBy: "top",
articles: [...]
}
*/
});

// To query sources:
newsapi.sources({
category: 'technology', // optional
language: 'en', // optional
country: 'us' // optional
}).then(sourcesResponse => {
console.log(sourcesResponse);
/*
{
status: "ok",
sources: [...]
}
*/
});

// For both methods you can also use traditional Node callback style:
newsapi.articles({
source: 'associated-press',
sortBy: 'top'
}, (err, articlesResponse) => {
if (err) console.error(err);
else console.log(articlesResponse);
});
```

## Caching
[NewsAPI's caching behavior](https://newsapi.org/docs/caching).
You can disable caching on a request level by adding the `noCache: true` option to your queries.
```js
newsapi.v2.everything({
sources: 'bbc-news'
}, {
noCache: true
}).then(response => {
...
});
```
147 changes: 147 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
'use strict';
/**
* This module provides access to the News API
* https://newsapi.org/
*
* The API provides access to recent news headlines
* from many popular news sources.
*
* The author of this code has no formal relationship with NewsAPI.org and does not
* claim to have created any of the facilities provided by NewsAPI.org.
*/

const Promise = require('bluebird'),
request = require('request'),
qs = require('querystring'),
host = 'https://newsapi.org';

let API_KEY; // To be set by clients

class NewsAPI {
constructor (apiKey) {
if (!apiKey) throw new Error('No API key specified');
API_KEY = apiKey;
this.v2 = {
topHeadlines (...args) {
const { params = { language: 'en' }, options, cb } = splitArgsIntoOptionsAndCallback(args);
const url = createUrlFromEndpointAndOptions('/v2/top-headlines', params);
return getDataFromWeb(url, options, API_KEY, cb);
},

everything (...args) {
const { params, options, cb } = splitArgsIntoOptionsAndCallback(args);
const url = createUrlFromEndpointAndOptions('/v2/everything', params);
return getDataFromWeb(url, options, API_KEY, cb);
},

sources (...args) {
const { params, options, cb } = splitArgsIntoOptionsAndCallback(args);
const url = createUrlFromEndpointAndOptions('/v2/sources', params);
return getDataFromWeb(url, options, API_KEY, cb);
}
}
}

sources (...args) {
const { params, options, cb } = splitArgsIntoOptionsAndCallback(args);
const url = createUrlFromEndpointAndOptions('/v1/sources', params);
return getDataFromWeb(url, options, null, cb);
}

articles (...args) {
const { params, options, cb } = splitArgsIntoOptionsAndCallback(args);
const url = createUrlFromEndpointAndOptions('/v1/articles', params);
return getDataFromWeb(url, options, API_KEY, cb);
}
}

class NewsAPIError extends Error {
constructor(err) {
super();
this.name = `NewsAPIError: ${err.code}`;
this.message = err.message;
}
}

/**
* Takes a variable-length array that represents arguments to a function and attempts to split it into
* an 'options' object and a 'cb' callback function.
* @param {Array} args The arguments to the function
* @return {Object}
*/
function splitArgsIntoOptionsAndCallback (args) {
let params;
let options;
let cb;
if (args.length > 1) {
const possibleCb = args[args.length - 1];
if ('function' === typeof possibleCb) {
cb = possibleCb;
options = args.length === 3 ? args[1] : undefined;
} else {
options = args[1];
}
params = args[0];
} else if ('object' === typeof args[0]) {
params = args[0];
} else if ('function' === typeof args[0]) {
cb = args[0];
}
return { params, options, cb };
}

/**
* Creates a url string from an endpoint and an options object by appending the endpoint
* to the global "host" const and appending the options as querystring parameters.
* @param {String} endpoint
* @param {Object} [options]
* @return {String}
*/
function createUrlFromEndpointAndOptions (endpoint, options) {
const query = qs.stringify(options);
const baseURL = `${host}${endpoint}`;
return query ? `${baseURL}?${query}` : baseURL;
}

/**
* Takes a URL string and returns a Promise containing
* a buffer with the data from the web.
* @param {String} url A URL String
* @param {String} apiKey (Optional) A key to be used for authentication
* @return {Promise<Buffer>} A Promise containing a Buffer
*/
function getDataFromWeb(url, options, apiKey, cb) {
let useCallback = 'function' === typeof cb;
return new Promise((resolve, reject) => {
const req = { url, headers: {} };
if (apiKey) {
req.headers['X-Api-Key'] = apiKey;
}
if (options && options.noCache === true) {
req.headers['X-No-Cache'] = 'true';
}
request.get(req, (err, res, body) => {
if (err) {
if (useCallback) return cb(err);
return reject(err);
}
try {
const data = JSON.parse(body);
if (data.status === 'error') throw new NewsAPIError(data);
// 'showHeaders' option can be used for clients to debug response headers
// response will be in form of { headers, body }
if (options && options.showHeaders) {
if (useCallback) return cb(null, { headers: res.headers, body: data });
return resolve({ headers: res.headers, body: data });
}
if (useCallback) return cb(null, data);
return resolve(data);
} catch (e) {
if (useCallback) return cb(e);
return reject(e);
}
});
});
}

module.exports = NewsAPI;
Loading