Hey guys I am trying to pull some data from a http request in a firebase pub sub function. Here is my current function I have ommited my api key
async function requestPromise(path: string) {
return new Promise((resolve, reject) => {
const options = {
hostname: "pro-api.coinmarketcap.com",
path: "/v1/cryptocurrency/listings/latest?start=1&limit=10&convert=USD",
method:"GET",
headers: {
Authorization: "Omitted",
},
};
http.get(options, (resp) => {
let data = "";
resp.on("data", (chunk) => {
data += chunk;
});
resp.on("end", () => {
resolve(data);
});
}).on("error", (error) => {
reject(error);
});
});
}
exports.updateCoinPrices = functions.pubsub.schedule("every 5 minutes")
.onRun(async (context) => {
await (async function () {
try {
await requestPromise("https://pro-api.coinmarketcap.com/v1/cryptocurrency/listings/latest?start=query=limit=").then((data) => {
console.log("the data is")
console.log(data)
});
} catch (error) {
console.error(error);
}
});
return null;
});
Here is what I get from firebase data is
and here is what the data should be coming in as any ideas ?
when i run my function it gives me error : Resolution method is overspecified. Specify a callback *or* return a Promise; not both. can anyone please check my code, and help to resolve this issue ? here i have placed my full code
it('Get Organizations', async function (done) {
let user_permission = await commonService.getuserPermission(logged_in_user_id,'organizations','findAll');
let api_status = 404;
if(user_permission) {
api_status = 200;
}
let current_token = currentResponse['token'];
old_unique_token = current_token;
chai.request(app)
.post('entities')
.set('Content-Type', 'application/json')
.set('vrc-access-token', current_token)
.send({ "key": "organizations", "operation": "findAll" })
.end(function (err, res) {
currentResponse = res.body;
expect(err).to.be.null;
expect(res).to.have.status(api_status);
done();
});
});
Don't use done when defining an async unit test function, rather simply return as you normally would from an async method, after awaiting the request from chai-http:
it('Get Organizations', async function () {
let user_permission = await commonService.getuserPermission(logged_in_user_id,'organizations','findAll');
let api_status = 404;
if(user_permission) {
api_status = 200;
}
let current_token = currentResponse['token'];
old_unique_token = current_token;
await chai.request(app) // note 'await' here
.post('entities')
.set('Content-Type', 'application/json')
.set('vrc-access-token', current_token)
.send({ "key": "organizations", "operation": "findAll" })
.then(function (err, res) { // not 'then', not 'end'
currentResponse = res.body;
expect(err).to.be.null;
expect(res).to.have.status(api_status);
});
});
The test runner will await your function automatically.
It is an "issue" with mocha. Remove the done() from your code. It is redundant when using Promises like in chai.request.
You are returning a Promise so calling done is redundant as it said in
error message
In the elder versions you had to use callback in case of async methods
like that
it ('returns async', function(done) { callAsync()
.then(function(result) {
assert.ok(result);
done(); }); })
Now you have an alternative of returning a Promise
it ('returns async', function() { return new Promise(function
(resolve) {
callAsync()
.then(function(result) {
assert.ok(result);
resolve();
}); }); })
From: this stack
I have an LdapJS server which implements standard operation and an extended operation to check health:
const server = ldap.createServer();
server.exop('healthcheck', (req, res, next) => {
res.end();
console.log('ended');
return next();
});
...
Then I wrote a simple client script to ping healthcheck service:
const { createClient } = require('ldapjs');
const client = createClient({
url: 'ldap://localhost:1389',
timeout: 2000,
connectTimeout: 2000
});
client.exop('healthcheck', (err, value, res) => {
if (err) {
console.log(`ERROR: ${err.message}`);
process.exit(1);
}
else {
console.log(`STATUS: ${res.status}`);
process.exit(0);
}
});
The problem is that the exop is correctly received by server (I can see the log inside its callback), but the client always logs: ERROR: request timeout (client interrupt).
Why the request is not correctly terminated?
EDIT
I wrote a mocha test for the exop and it works. Seems that the problem is related to the standalone call in healthcheck script.
describe('#healthcheck()', function () {
before(function () {
server = createServer();
server.listen(config.get('port'), config.get('host'), () => {});
});
after(function () {
server.close();
});
it('should return status 0', function (done) {
const { createClient } = require('ldapjs');
const client = createClient({
url: 'ldap://localhost:1389',
timeout: 2000,
connectTimeout: 2000
});
client.exop('healthcheck', (err, value, res) => {
should.not.exist(err);
res.status.should.be.equal(0);
client.destroy();
return done();
});
});
});
I'm trying to wrap http.request into Promise:
new Promise(function(resolve, reject) {
var req = http.request({
host: '127.0.0.1',
port: 4000,
method: 'GET',
path: '/api/v1/service'
}, function(res) {
if (res.statusCode < 200 || res.statusCode >= 300) {
// First reject
reject(new Error('statusCode=' + res.statusCode));
return;
}
var body = [];
res.on('data', function(chunk) {
body.push(chunk);
});
res.on('end', function() {
try {
body = JSON.parse(Buffer.concat(body).toString());
} catch(e) {
reject(e);
return;
}
resolve(body);
});
});
req.on('error', function(err) {
// Second reject
reject(err);
});
req.write('test');
}).then(function(data) {
console.log(data);
}).catch(function(err) {
console.log(err);
});
If I recieve errornous statusCode from remote server it will call First reject and after a bit of time Second reject. How to make properly so it calls only single reject (I think First reject is proper one in this case)? I think I need to close res myself, but there is no close() method on ClientResponse object.
UPD:
Second reject triggers very rarely - why?
Your code is almost fine. To restate a little, you want a function that wraps http.request with this form:
function httpRequest(params, postData) {
return new Promise(function(resolve, reject) {
var req = http.request(params, function(res) {
// on bad status, reject
// on response data, cumulate it
// on end, parse and resolve
});
// on request error, reject
// if there's post data, write it to the request
// important: end the request req.end()
});
}
Notice the addition of params and postData so this can be used as a general purpose request. And notice the last line req.end() -- which must always be called -- was missing from the OP code.
Applying those couple changes to the OP code...
function httpRequest(params, postData) {
return new Promise(function(resolve, reject) {
var req = http.request(params, function(res) {
// reject on bad status
if (res.statusCode < 200 || res.statusCode >= 300) {
return reject(new Error('statusCode=' + res.statusCode));
}
// cumulate data
var body = [];
res.on('data', function(chunk) {
body.push(chunk);
});
// resolve on end
res.on('end', function() {
try {
body = JSON.parse(Buffer.concat(body).toString());
} catch(e) {
reject(e);
}
resolve(body);
});
});
// reject on request error
req.on('error', function(err) {
// This is not a "Second reject", just a different sort of failure
reject(err);
});
if (postData) {
req.write(postData);
}
// IMPORTANT
req.end();
});
}
This is untested, but it should work fine...
var params = {
host: '127.0.0.1',
port: 4000,
method: 'GET',
path: '/api/v1/service'
};
// this is a get, so there's no post data
httpRequest(params).then(function(body) {
console.log(body);
});
And these promises can be chained, too...
httpRequest(params).then(function(body) {
console.log(body);
return httpRequest(otherParams);
}).then(function(body) {
console.log(body);
// and so on
});
I know this question is old but the answer actually inspired me to write a modern version of a lightweight promisified HTTP client. Here is a new version that:
Use up to date JavaScript syntax
Validate input
Support multiple methods
Is easy to extend for HTTPS support
Will let the client decide on how to deal with response codes
Will also let the client decide on how to deal with non-JSON bodies
Code below:
function httpRequest(method, url, body = null) {
if (!['get', 'post', 'head'].includes(method)) {
throw new Error(`Invalid method: ${method}`);
}
let urlObject;
try {
urlObject = new URL(url);
} catch (error) {
throw new Error(`Invalid url ${url}`);
}
if (body && method !== 'post') {
throw new Error(`Invalid use of the body parameter while using the ${method.toUpperCase()} method.`);
}
let options = {
method: method.toUpperCase(),
hostname: urlObject.hostname,
port: urlObject.port,
path: urlObject.pathname
};
if (body) {
options.headers = {'Content-Length':Buffer.byteLength(body)};
}
return new Promise((resolve, reject) => {
const clientRequest = http.request(options, incomingMessage => {
// Response object.
let response = {
statusCode: incomingMessage.statusCode,
headers: incomingMessage.headers,
body: []
};
// Collect response body data.
incomingMessage.on('data', chunk => {
response.body.push(chunk);
});
// Resolve on end.
incomingMessage.on('end', () => {
if (response.body.length) {
response.body = response.body.join();
try {
response.body = JSON.parse(response.body);
} catch (error) {
// Silently fail if response is not JSON.
}
}
resolve(response);
});
});
// Reject on request error.
clientRequest.on('error', error => {
reject(error);
});
// Write request body if present.
if (body) {
clientRequest.write(body);
}
// Close HTTP connection.
clientRequest.end();
});
}
There are other ways as well but here you can find a simple way to make http.request as a promise or async/await type.
Here is a working sample code:
var http = require('http');
function requestAsync(name) {
return new Promise((resolve, reject) => {
var post_options = {
host: 'restcountries.eu',
port: '80',
path: `/rest/v2/name/${name}`,
method: 'GET',
headers: {
'Content-Type': 'application/json'
}
};
let post_req = http.request(post_options, (res) => {
res.setEncoding('utf8');
res.on('data', (chunk) => {
resolve(chunk);
});
res.on("error", (err) => {
reject(err);
});
});
post_req.write('test');
post_req.end();
});
}
//Calling request function
//:1- as promise
requestAsync("india").then(countryDetails => {
console.log(countryDetails);
}).catch((err) => {
console.log(err);
});
//:2- as await
let countryDetails = await requestAsync("india");
After reading all of these and a few articles, I thought I'd post a sort of "general" solution that handles both http and https:
const http = require("http");
const https = require("https");
const url_obj = require("url");
const request = async (url_string, method = "GET", postData = null) => {
const url = url_obj.parse(url_string);
const lib = url.protocol=="https:" ? https : http;
const params = {
method:method,
host:url.host,
port: url.port || url.protocol=="https:" ? 443 : 80,
path: url.path || "/"
};
return new Promise((resolve, reject) => {
const req = lib.request(params, res => {
if (res.statusCode < 200 || res.statusCode >= 300) {
return reject(new Error(`Status Code: ${res.statusCode}`));
}
const data = [];
res.on("data", chunk => {
data.push(chunk);
});
res.on("end", () => resolve(Buffer.concat(data).toString()));
});
req.on("error", reject);
if (postData) {
req.write(postData);
}
req.end();
});
}
You could use like this:
request("google.com").then(res => console.log(res)).catch(err => console.log(err))
This is heavily inspired by this article, but replaces the hacky url parsing with the built in api.
Hope this help.
const request = require('request');
async function getRequest() {
const options = {
url: 'http://example.com',
headers: {
'Authorization': 'Bearer xxx'
}
};
return new Promise((resolve, reject) => {
return request(options, (error, response, body) => {
if (!error && response.statusCode == 200) {
const json = JSON.parse(body);
return resolve(json);
} else {
return reject(error);
}
});
})
}
It's easier for you to use bluebird api, you can promisify request module and use the request function async as a promise itself, or you have the option of using the module request-promise, that makes you to not working to creating a promise but using and object that already encapsulates the module using promise, here's an example:
var rp = require('request-promise');
rp({host: '127.0.0.1',
port: 4000,
method: 'GET',
path: '/api/v1/service'})
.then(function (parsedBody) {
// GET succeeded...
})
.catch(function (err) {
// GET failed...
});
I have this code:
var should = require('should'),
http = require('http'),
apis = {
baseUrl: 'http://11.0.0.20:4000',
listLiveMatches: '/api/blah/'
};
describe('GET ' + apis.baseUrl + apis.listLiveMatches, function () {
'use strict';
var liveListUrl = apis.baseUrl + apis.listLiveMatches;
it('is alive & returning 200', function (done) {
http.get(liveListUrl, function (res) {
res.should.be.ok;
res.should.have.property('statusCode');
res.statusCode.should.equal(200);
done();
});
});
it('is emitting json response', function (done) {
http.get(liveListUrl, function (res) {
res.should.be.ok;
res.should.have.property('headers');
res.headers['content-type'].should.startWith('application/json');
done();
});
});
});
My gulp task looks like this:
gulp.task('test-server', function () {
return gulp.src('test/rest-api.js')
.pipe(mocha({
reporter: 'spec'
}))
.on('error', function(){
console.log('error');
});
});
My only issue is that with every http.get, the console gets the body of the response logged which I want to prevent, google searches for disabling logging on http.get have yielded nothing.