I am using a promise to get my response.
but he value is not coming in my console.
can you tell me whats the problem.
providing my code below
const https = require('https');
/*
* Complete the function below.
* Use console.log to print the result, you should not return from the function.
*/
function getMovieTitles(substr) {
return new Promise((resolve,reject) => {
https.get('https://jsonmock.hackerrank.com/api/movies/search/?Title=spiderman&page=1', (res) =>{
// var {statusCode} = res;
//var contentType = res.headers['content-type'];
console.log('res---->', res);
})
})
}
Here you go,
new Promise(function(resolve, reject) {
https.get('your_url_here', (res) =>{
// var {statusCode} = res;
// var contentType = res.headers['content-type'];
resolve(res);
})
}).then(function(res){
console.log("Response",res);
})
To Test Please Follow - https://jsfiddle.net/qdjkreo5/3741/
Alternatives :
You can deal with the data returned by https module in its callback itself as https also returns a callback.
const https = require('https');
https.get('https://encrypted.google.com/', (res) => {
console.log('response', res);
}).on('error', (e) => {
console.error(e);
});
Apart from that To Combine REST API calls with JavaScript Promises in node.js you can make use of the npm module request-promise.
var request = require('request-promise');
request({
"method":"GET",
"uri": "https://api.github.com/",
"json": true,
"headers": {
"User-Agent": "My little demo app"
}
}).then(console.log, console.log);
Building on the prior answers, here's a promise framework that handles both resolve (response, but not necessarily 200) and reject (no response). The axios package does this but hides the details. I like this a little better because it gives me more control over the logic.
const p1 = new Promise((resolve, reject) => {
https.get(url, (res) => {
let {statusCode} = res;
let contentType = res.headers['content-type'];
resolve(`status=${statusCode} type=${contentType}`); // response, so resolve
}).on('error', (err) => {
reject(err); // no response, so reject
});
});
p1.then(res => console.log(`${url}: ${res}`)) // resolve
.catch(err => console.log(err)) // reject
.finally(console.log('Finally')); // always
Test on the following URLs,
https://google.com
https://x.com
http://x.com
Related
I'm new to coding and Promises are somewhat of an abstract concept for me. I know that in order to return a Promise you must use .then and .catch , but I'm unsure how exactly they should be used in the following code.
/**
* Make an HTTPS request to the MTA GTFS API for a given feed.
* #param {String} baseUrl - base URL for MTA GTFS API
* #param {String} feedId - identifier for which realtime feed
* #param {String} apiKey - key for MTA GTFS API
* #return {<Object>} - Promise of parsed feed.
*/
function makeRequest(baseUrl, feedId, apiKey) {
const feedUrl = baseUrl + feedId;
return new Promise((resolve, reject) => {
const req = https.request(feedUrl,
{ headers: { 'x-api-key': apiKey } },
(res) => {
if (res.statusCode < 200 || res.statusCode >= 300) {
return reject(new Error('statusCode=' + res.statusCode));
}
var data;
data = [];
res.on('data', (chunk) => {
return data.push(chunk);
});
return res.on('end', function() {
var msg;
data = Buffer.concat(data);
try {
msg = nstrDecoder.decode(data);
} catch (err) {
try {
console.log(err.message);
msg = nsssDecoder.decode(data);
} catch (err) {
console.log(err.message);
msg = "";
}
}
resolve(msg);
});
}
);
req.on('error', (e) => {
reject(e.message);
});
req.end();
});
}
return console.log(makeRequest(baseUrl, feedId, apiKey));
After running this code I get a message saying the Promise is pending. Thoughts??
When calling a function that returns a promise, you're going to get the promise in a pending state being it hasn't resolve or rejected yet. You have two options.
Option one.
node 10+ you can use async await.
async function main(){
const res = await makeRequest(baseUrl, feedId, apiKey)
return res
}
Pre node 10
makeRequest(baseUrl, feedId, apiKey)
.then(data => {
console.log(data)
})
.catch(err => {
console.log(err)
})
Essentially if you have to wait for the data, you have to have the code that relies on that data after the await, or in the .then block.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function
Your makeRequest() function returns a promise. To use that promise, you use .then() or await to get the resolved value from the promise.
Using .then():
makeRequest(baseUrl, feedId, apiKey).then(result => {
console.log(result);
}).catch(err => {
console.log(err);
});
or using await:
async function someFunction() {
try {
let result = await makeRequest(baseUrl, feedId, apiKey);
console.log(result);
} catch(e) {
console.log(err);
}
}
FYI, a lot of what makeRequest() is doing can be done simpler using an http request library that already supports promises. There is a list of competent libraries to choose from here.
My favorite is got(), but you can review the list to decide which one you like. The main advantages are that they already collect the whole response for you, already support promises, support a wide variety of authentication schemes with built-in logic and can often decode or parse the response for you - all things which https.request() does not know how to do by itself.
This question already has answers here:
nodejs - How to promisify http.request? reject got called two times
(6 answers)
Closed 1 year ago.
const http = require("http");
async function sendRequest(url) {
url = new URL(url);
const requestDetails = {
'hostname': url.hostname,
'port': url.port || 80,
'path': url.pathname,
'method': 'GET'
};
const req = await new Promise((resolve, reject) => {
const request = http.request(requestDetails, response => {
const status = response.statusCode;
if (status === 200 || status === 201) {
console.log("SUCCESS");
resolve(request);
} else {
console.log("ERROR");
reject(`Status code returned was ${status}`);
}
});
});
req.end();
}
sendRequest('http://httpbin.org/get');
It works when req.end() is inside the promise, but after passing the request out then execute req.end(), the console is just holding without any response. I tried to compare "req === request" by a middle variable, it returned true. Why doesn't moving end() out work? Shouldn't these two object the same?
The purpose of the req.end() is to finish the request. We might be cautious that if any body part is unsent or might in progress, it will flush them in the stream, or if any request is chunked, this will send to terminating.
I have implemented your same code in a bit different and cleaner way. Below way might help to reuse the same code for multiple apis.
const http = require("http");
/**
* #description call the http request
*/
async function doHttp(requestDetails){
return new Promise((resolve, reject)=>{
http.request(requestDetails, response => {
const status = response.statusCode;
response.setEncoding("utf-8");
if (status === 200 || status === 201) {
console.log("SUCCESS");
response.on('data', data => {
return resolve(data);
});
} else {
console.error("ERROR");
return reject(new Error("emptyData"));
}
}).on('error', (err) => {
// Catch the error if occured in request
console.error(`problem with request: ${e.message}`);
return reject(err);
}).end();
});
}
/**
* #description sending the request
*/
async function doSend(url) {
url = new URL(url);
const requestDetails = {
'hostname': url.hostname,
'port': url.port || 80,
'path': url.pathname,
'method': 'GET'
};
const data = await doHttp(requestDetails)
console.log(data);
}
doSend('http://httpbin.org/get');
At last, we could say req.end() is required to finish up any request. It completely depends on us, how we can implement a method.
An alternate solution might be this native https module is such as Axios, superagent, got, node-fetch. They provide a wrapper over the native nodejs code which might help us to control to handle an error and response.
You should move the request.end call inside the promise otherwise it just newer gets called because you will be waiting for a promise that is newer resolved because the request is not send.
Also you should reject the promise in case request object emits error event.
INTRODUCTION
I am implementing a function for making any kind of https request to any endpoint (using the https native module). When I make a request to a specific API I get an error response in JSON format. Like this:
{
"error": {
"code": 404,
"message": "ID not found"
}
}
How can I handle this kind of errors? At a first moment, I supposed that they were handled in
request.on("error", (err) => {
reject(err);
});
HTTPs Request function code
I have comment '<---------' in the relevant parts of the code
const https = require("https");
exports.httpsRequest = function (options, body = null) {
/*
This function is useful for making requests over the HTTPs protocol
*/
return new Promise((resolve, reject) => {
const request = https.request(options, (response) => {
// Get the response content type
const contentType =
response.headers["content-type"] &&
response.headers["content-type"].split(";")[0];
// Cumulate data
let chuncks = [];
response.on("data", (chunck) => {
chuncks.push(chunck);
});
response.on("end", () => {
// Concat all received chunks
let response = Buffer.concat(chuncks);
// Some responses might be in JSON format...
if (contentType === "application/json") {
// Jsonify the response
response = JSON.parse(response);
}
// (For the future) TODO - Check and parse more content types if needed.
// Resolve the promise with the HTTPs response
resolve(response); // <--------- The JSON format error responses are resolved too!!
});
});
// Reject on request error
request.on("error", (err) => {
// <------------- At a first moment, I supposed that all error responses were handled in this part of the code
reject(err);
});
// Write the body
if (body) {
request.write(body);
}
// Close HTTPs connection.
request.end();
});
};
Question
Why the error response is not handled in request.on("error", ...) ?
Thank you. I would appreciate any help or suggestion.
You need to create a different code path for when the content type isn't what you were expecting in which you call reject() and you also need to try/catch around JSON parsing errors so you can properly catch them and reject on them too. You can solve those issues with this code:
exports.httpsRequest = function (options, body = null) {
/*
This function is useful for making requests over the HTTPs protocol
*/
return new Promise((resolve, reject) => {
const request = https.request(options, (response) => {
// Get the response content type
const contentType =
response.headers["content-type"] &&
response.headers["content-type"].split(";")[0];
// Cumulate data
let chuncks = [];
response.on("data", (chunck) => {
chuncks.push(chunck);
});
response.on("end", () => {
// Concat all received chunks
let response = Buffer.concat(chuncks);
// Some responses might be in JSON format...
if (contentType === "application/json") {
try {
// Jsonify the response
response = JSON.parse(response);
resolve(response);
return;
} catch(e) {
reject(e);
return;
}
}
reject(new Error("Not JSON content-type"))
});
});
// Reject on request error
request.on("error", (err) => {
reject(err);
});
// Write the body
if (body) {
request.write(body);
}
// Close HTTPs connection.
request.end();
});
};
FYI, libraries such as got() and others listed here, all do this work for you automatically and have a lot of other useful features. You don't really need to build this yourself.
I am a total newbie to Javascript and trying to set up a bridge between two of the services I use. The goal is simply take body or the request, do a promise api call to another service to respond with the body of that api call. I have been able to take the body of the request and send it to the service, but I'm having trouble receiving that response and making body of that response as a response of the function. Please help me out. Thank you.
var moment = require('moment');
var CryptoJS = require("crypto-js");
const fetch = require('node-fetch');
var unixtime = moment().unix();
var apiUser = process.env.apiUser;
var secret = process.env.apiKey;
var url = process.env.url;
exports.test = (req, res) => {
var message = req.body;
message = JSON.stringify(message);
var body = "{\n \"ops\": [{\n \"conv_id\": \"679690\",\n \"type\": \"create\",\n \"obj\": \"task\",\n \"data\": message\n }]\n}\n"
body = body.replace(/message/ig, message);
var signature = CryptoJS.enc.Hex.stringify(CryptoJS.SHA1(unixtime + secret + body + secret));
function request1() {
return new Promise((resolve, reject) => {
var options = fetch(url+apiUser+'/'+unixtime+'/'+signature, {
method: 'post',
body: body,
headers: { 'Content-Type': 'application/json' },
});
options.then(res => {
var result = res.json;
console.log(result);
resolve(result);
})
.catch(() => { // if .then fails
console.log('Promise rejected');
let rejectMessage = 'Sorry, an error occurred.';
reject(rejectMessage); // Promise rejected
});
});
}
request1();
};
you can retrieve result object easily because function request1 returns a promise resolving that object, so this should work:
request1().then((resultObject)=>{
//resultObject === result
return res.send(resultObject);
});
Also, res.json() returns a promise, so you should do:
options.then(res => res.json()).then(result => {
console.log(result);
resolve(result);
})
i'm working with an API that allows me to sync data to a local DB. There is a syncReady API that I'm calling recursively until the sync batch is ready to start sending data. The recursion is working correctly and the .then callback is called, but the resolve function never resolves the response.
const request = require('request-promise');
const config = require('../Configs/config.json');
function Sync(){}
Sync.prototype.syncReady = function (token, batchID) {
return new Promise((res, rej) => {
config.headers.Get.authorization = `bearer ${token}`;
config.properties.SyncPrep.id = batchID;
request({url: config.url.SyncReady, method: config.Method.Get, headers: config.headers.Get, qs: config.properties.SyncPrep})
.then((response) => {
console.log(`The Response: ${response}`);
res(response);
}, (error) => {
console.log(error.statusCode);
if(error.statusCode === 497){
this.syncReady(token, batchID);
} else rej(error);
}
);
});
};
I get the 497 logged and the "The Response: {"pagesTotal";0}" response but the res(response) never sends the response down the chain. I've added a console.log message along the entire chain and none of the .then functions back down the chain are firing.
I hope I've explained this well enough :-). Any ideas why the promise isn't resolving?
Thanks!
First, you don't need to wrap something that returns a promise with a new Promise. Second, for your error case you don't resolve the promise if it is 497.
const request = require('request-promise');
const config = require('../Configs/config.json');
function Sync(){}
Sync.prototype.syncReady = function (token, batchID) {
config.headers.Get.authorization = `bearer ${token}`;
config.properties.SyncPrep.id = batchID;
return request({url: config.url.SyncReady, method: config.Method.Get, headers: config.headers.Get, qs: config.properties.SyncPrep})
.then((response) => {
console.log(`The Response: ${response}`);
return response;
})
.catch((error) => {
console.log(error.statusCode);
if(error.statusCode === 497){
return this.syncReady(token, batchID);
} else {
throw error;
}
})
);
};
Maybe something like the above will work for you instead. Maybe try the above instead. As a general rule of thumb, it's you almost always want to return a Promise.