newsapi-wrapper
Version:
A wrapper around the News API (https://newsapi.org/) that exposes a Promise-like interface
178 lines (154 loc) • 4.47 kB
JavaScript
const request = require('request');
const STATUS_OK = 'ok';
const URLS = {
topHeadlines: 'https://newsapi.org/v2/top-headlines'
};
const categories = {
business: true,
entertainment: true,
general: true,
health: true,
science: true,
sports: true,
technology: true
};
const isAllowedCategory = cat => {
return categories[cat] === true;
};
const settings = {
apiKey: true,
country: true,
pageSize: true,
category: true
};
const defaults = {
country: 'de',
category: 'business',
pageSize: 20
};
const setDefault = (settingName, value) => {
if (settings.hasOwnProperty(settingName)) {
defaults[settingName] = value;
} else {
throw new Error(
`Unknown setting "${settingName}". Known setting names: ${Object.keys(
settings
)}`
);
}
};
const setDefaults = obj => {
for (let p of Object.keys(obj)) {
setDefault(p, obj[p]);
}
};
const getCategories = () => {
return Object.keys(categories);
};
class Request {
constructor(opts = {}) {
this.options = {};
Object.assign(this.options, defaults, opts);
return this;
}
setApiKey(value) {
if (typeof value !== 'string') {
throw new Error('NewsApi Key must be a string');
}
this.options.apiKey = value;
return this;
}
setCountry(value) {
this.options.country = value;
return this;
}
setCategory(value) {
if (isAllowedCategory(value)) {
this.options.category = value;
return this;
} else {
throw new Error(`Illegal category "${value}".`);
}
}
setPageSize(num) {
if (Number.isInteger(num)) {
this.options.pageSize = num;
}
return this;
}
send(cb) {
if (!this.options.apiKey) {
throw new Error(
"Request should be sent but no API key given for News API. Please use setApiKey(key) or setDefault('apiKey', key) to provide it."
);
}
let requestOptions = {
url: URLS.topHeadlines,
qs: {
country: this.options.country,
apiKey: this.options.apiKey,
category: this.options.category,
pageSize: this.options.pageSize
}
};
return new Promise((resolve, reject) => {
request(requestOptions, (error, response, body) => {
if (cb && cb.call) {
cb(error, response, body);
}
if (error) {
reject(error);
return;
}
let obj;
try {
obj = JSON.parse(body);
} catch (e) {
reject(new Error('Could not parse News API response'));
return;
}
if (response.statusCode === 200) {
if (obj.status === STATUS_OK) {
resolve(obj);
} else {
reject(
new Error(
'News API request failed. Reason: ' +
obj.message
)
);
}
} else {
let msg =
'News API request failed. HTTP code: ' +
response.statusCode +
', message: ';
msg +=
obj && obj.message
? obj.message
: response.statusMessage;
reject(new Error(msg));
}
});
});
}
}
const createRequest = options => {
return new Request(options);
};
const setApiKey = apiKey => createRequest().setApiKey(apiKey);
const setCategory = category => createRequest().setCategory(category);
const setPageSize = pageSize => createRequest().setPageSize(pageSize);
const setCountry = country => createRequest().setCountry(country);
const send = options => createRequest(options).send();
module.exports = {
setDefault,
setDefaults,
getCategories,
request: createRequest,
setApiKey,
setCategory,
setPageSize,
setCountry,
send
};