I need to make 2 http request - the response of the first one will be used in the second. The way I do the request is using the http.get(url, callback) method from the http module. But I assume nodejs spawns another thread for the second http request and responses arrive asynchronously. What I did is it to put the second http request in the callback of the first, it works, but looks like unmaintainable code to me.
Any other ways to do it?
Late to the party but just reiterating what Dhaval Soni said. If you have async / await syntax at your disposal, then the easiest solution is the following:
// inside "async" function
const asyncResult1 = await requestPromise(`${rootUrl}/posts/1`)
const asyncResult2 = await requestPromise(`${rootUrl}/albums/${asyncResult1.id}`)
Notice how the result of the first async request is used to make the second async request.
I made for you quick example in ES6:
const requestPromise = require('request-promise');
const rootUrl = 'https://jsonplaceholder.typicode.com';
const request1 = requestPromise(`${rootUrl}/posts/1`);
const request2 = requestPromise(`${rootUrl}/albums/1`);
Promise.all([request1, request2])
.then(values => {
console.log(values);
});
You need to install two dependencies:
"request": "^2.78.0",
"request-promise": "^4.1.1"
Related
I am trying to make a GET Request to an API and want to store the data it returns in another variable
but Javascript doesn't wait for the request to be complete and log my variable as Undefined
app.get("/", function (req, res) {
const url = "https://animechan.vercel.app/api/random";
let str = "";
let quote;
https.get(url,(resposne)=>{
resposne.on("data",(data)=>{
str+=data;
});
resposne.on("end",()=>{
const info=JSON.parse(str);
quote=info.quote;
});
});
console.log(quote);
res.render("header", {
quote: quote
});
});
I would be glad if someone can tell me how to solve this problem and where can I study about it more as I am a beginner to javascript.
Quick answer is that you need to put that code inside of response.on('end') callback.
resposne.on("end",()=>{
const info=JSON.parse(str);
quote=info.quote;
// now we can use res.render
console.log(quote);
res.render("header", {
quote: quote
});
});
However, following such approach will lead to a callback hell, unreadable and unextendable code of your project. Ideally, you should start using promises. Promises are an essential part of javascript and are a must have knowledge for a developer.
Also, I'd like to note that you don't need to implement http calls functionality from scratch or try to wrap such code into promise. Instead, it is better to use fetch api (if you are using node version 18 or above) or use corresponding libraries, for example, node-fetch.
All you have to do here is call res.send after the HTTP call is complete
app.get("/", function (req, res) {
const url = "https://animechan.vercel.app/api/random";
let str = "";
let quote;
https.get(url,(resposne)=>{
resposne.on("data",(data)=>{
str+=data;
});
resposne.on("end",()=>{
const info=JSON.parse(str);
quote=info.quote;
// Send response _after_ the http call is complete
console.log(quote);
res.render("header", {
quote: quote
});
});
});
});
I would suggest using node's fetch, since the default HTTP client is a bit less ergonomic
Fetch API reference: https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API
Node.js API reference: https://nodejs.org/dist/latest-v18.x/docs/api/globals.html#fetch
Good Evening,
I have a function that contains a route that is a call to the Auth0 API and contains the updated data that was sent from the client. The function runs, but the app.patch() does not seem to run and I am not sure what I am missing.
function updateUser(val) {
app.patch(`https://${process.env.AUTH0_BASE_URL}/api/v2/users/${val.id}`,(res) => {
console.log(val);
res.header('Authorization: Bearer <insert token>)
res.json(val);
})
app.post('/updateuser', (req, ) => {
const val = req.body;
updateUser(val);
})
app.patch() does NOT send an outgoing request to another server. Instead, it registers a listener for incoming PATCH requests. It does not appear from your comments that that is what you want to do.
To send a PATCH request to another server, you need to use a library that is designed for sending http requests. There's a low level library built into the nodejs http module which you could use an http.request() to construct a PATCH request with, but it's generally a lot easier to use a higher level library such as any of them listed here.
My favorite in that list is the got() library, but many in that list are popular and used widely.
Using the got() library, you would send a PATCH request like this:
const got = require('got');
const options = {
headers: {Authorization: `Bearer ${someToken}`},
body: someData
};
const url = `https://${process.env.AUTH0_BASE_URL}/api/v2/users/${val.id}`;
got.patch(url, options).then(result => {
console.log(result);
}).catch(err => {
console.log(err);
});
Note: The PATCH request needs body data (the same that a POST needs body data)
I'm trying to make assertions on XHR, but can't find a right way on how to grab the correct request.
The task is simple: click a button, then wait for network request and make assertions on it's response and request bodies.
The problem is that before I call changePageSize() function in my tests, there are already multiple requests in my network with the exact same URLs and methods. The only difference between them is request and response body, so it happens that my code just grabs the first request that matches url I provided. Is there an any way on how to specify the exact network request that I want to use in my tests?
Here is the function:
static async changePageSize(selector: string): Promise<any> {
const [resp]: any = await Promise.all([
page.waitForResponse(`**${paths.graph}`),
this.setPagination(selector),
]);
return [resp]
}
And then I'm using it in my tests:
const [response] = await myPage.changePageSize(selector);
expect(await response.text()).toContain(`${size}`);
expect(response.request().postData()).toContain(`${size}`);
_
MY CHALLENGE:
I would like to access a third party Rest API from within my Lambda function. (e.g."http://www.mocky.io/v2/5c62a4523000004a00019907").
This will provide back a JSON file which I will then use for data extraction
_
MY CURRENT CODE:
var http = require('http');
exports.handler = function(event, context, callback) {
console.log('start request to Mocky');
http.get('http://www.mocky.io/v2/5c62a4523000004a00019907', function(res) {
console.log(res);
})
.on('error', function(e) {
console.log("Got error: " + e.message);
});
};
This does not throw an error but also does not seem to provide back the JSON
_
MY OPEN QUESTIONS:
1) How can I extract the JSON so that I can work on it
2) I will probably need to also send through an Authentification in the request header (Bearer) in the future. Will this also be possible with this method?
The problem is likely that your lambda function is exiting before logging the response.
We use Authorization headers all the time to call our lambdas. The issue of if you can use one to call the third party API is up to them, not you, so check the documentation.
Since your HTTP call is executed asynchronously, the execution of the lambda continues while that call is being resolved. Since there are no more commands in the lambda, it exits before your response returns and can be logged.
EDIT: the http.get module is difficult to use cleanly with async/await. I usually use superagent, axios, or request for that reason, or even node-fetch. I'll use request in my answer. If you must use the native module, then see EG this answer. Otherwise, npm install request request-promise and use my answer below.
The scheme that many people use these days for this kind of call uses async/await, for example (Requires Node 8+):
var request = require('request-promise')
exports.handler = async function(event, context, callback) {
console.log('start request to Mocky');
try {
const res = await request.get('http://www.mocky.io/v2/5c62a4523000004a00019907')
console.log(res)
callback(null, { statusCode: 200, body: JSON.stringify(res) })
}
catch(err) {
console.error(err.message)
callback('Got error ' + err.message)
}
};
The async/await version is much easier to follow IMO.
Everything inside an async function that is marked with await with be resolved before the execution continues. There are lots of articles about this around, try this one.
There are a lot of guys having an equal problem already solved... Look at that
or that
I want to make the implementation of this https.getSync the wrapper method, so that it calls the api synchronously, same like the readFileSync method which we use for reading file synchronously,
const https = require('https');
How should i implement this method -
https.getSync = (url) => {
let data = '';
https.get(url, resp => {
resp.on('data', (chunk) => {
data += chunk;
});
resp.on('end', () => {
console.log(JSON.parse(data));
});
}).on("error", (err) => {
console.log("Error: " + err.message);
});
return data;
}
I want the below two calls to be made synchronously, without changing the below code where we are calling the getSync method. Here for this calling i don't want to use promises or callback.
let api1 = https.getSync('https://api.nasa.gov/planetary/apod?api_key=DEMO_KEY');
let api2 = https.getSync('https://api.nasa.gov/planetary/apod?api_key=NNKOjkoul8n1CH18TWA9gwngW1s1SmjESPjNoUFo');
You can use npm package sync-request.
It's quite simple.
var request = require('sync-request');
var res = request('GET', 'http://example.com');
console.log(res.getBody());
Here is the link: sync-request
Read this also: An announcement from the package, in case readers would think using it is a good idea. You should not be using this in a production application. In a node.js application you will find that you are completely unable to scale your server. In a client application you will find that sync-request causes the app to hang/freeze. Synchronous web requests are the number one cause of browser crashes.
According to me also you should avoid making http sync request. Instead clear your concepts of using callback, promise, async/await.