I am making an xhr request in nodejs using Axios. And I am trying to save a value from this response to a variable, but it isn't working and I am not sure why.
Code:
let redirectUrl = 'placeholder'
axios.get(url)
.then(res => {
redirectURL = res.url
console.log(res.url, "HERE")
})
.catch(err => console.log(err))
return res.render('index',{url: redirectURL})
I have tried declaring redirectUrl in both global as var and local scope, but the value isn't changing, on index when I console log this value, it logs placeholder. index is index.jsx as I am using jsx as the template engine.
Please let me know if I should provide any more information.
Thank You in advance.
axios.get is an async call, so your return will use the original (placeholder) value instead of the new one. Normally to solve this kind of asynchronicities i use async/await
async function getRedirectURL(url) {
try {
const res = await axios.get(url);
// Note that if you want some return value from axios call you access it by res.data
console.log('res.url :', res.url, ". res.data:", res.data);
return res.render('index',{url: res.data.url});
} catch (err) {
console.log(err);
throw err;
}
}
Axios is a promise-based HTTP client, So when javascript engine executes your code, it moves axios call to web API from callstack (line# 2) and then it starts to execute the last line return res.render('index',{url: redirectURL}) where redirectURL value is placeholder. You have to write all the logic in promise then method, like
axios
.get(url)
.then((data) => res.render("index", { url: data.url }))
.catch((err) => {
// error response
console.log(err);
});
Related
I am using this <res.write()> ==> https://nodejs.org/api/http.html#responsewritechunk-encoding-callback (in nodejs)
and using this fetch ==> https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch
My situation is that I didn't see any response when using the res.write() function inside of the fetch function. for example, in the below backend code, I tried to put res.write("456") inside of the first then function below fetch, but I only see 123 returned in the frontend, no 456.
res.write("123");
fetch('http://example.com/movies.json')
.then((response) => {response.json(), res.write("456")})
.then((data) => console.log(data));
I have searched Google for a while, but didn't see anything related. My guess is that this could be because of async usage.
appreciate if someone can give suggestions.
===== update =====
res is express's res obj
async sendText(res: Response){
res.write("123")
fetch('http://example.com/movies.json')
.then((response) => {return response.json()})
.then((data) => {
console.log(data);
res.write('456');
res.end();
});
}
seeing behavior: only see 123 in the frontend.
VS
async sendText(res: Response){
res.write("123")
await fetch('http://example.com/movies.json')
.then((response) => {return response.json()})
.then((data) => {
console.log(data);
res.write('456');
res.end();
});
}
seeing behavior: can see both 123 and 456 in the frontend.
I never use await and .then together before, not fully understand the difference. searching the web rn.
You aren't checking for any errors or an unsuccessful response so response.json() may be failing, preventing anything after it from executing.
Something like this should work better for you
async sendText (res: Response) {
res.write("123");
const response = await fetch("http://example.com/movies.json");
// check for an unsuccessful response
if (!response.ok) {
const error = new Error(`${response.status} ${response.statusText}`);
error.text = await response.text();
throw error;
}
const data = await response.json();
res.write("456");
res.end(); // finalise the HTTP response
console.log(data); // log data for some reason ¯\_(ツ)_/¯
};
This will return a promise that resolves with undefined or rejects with either a networking error, HTTP error or JSON parsing error.
When calling it, you should handle any rejections accordingly
app.get("/some/route", async (res, res, next) => {
try {
await sendText(res);
} catch (err) {
console.error(err, err.text);
next(err); // or perhaps `res.status(500).send(err)`
}
});
I never use await and .then together before
Nor should you. It only leads to confusing code.
I am currently writing a route which allows me to recieve information from a stored procudre I have in a database. I have written a request in AngularJS and a route in NodeJS but I am just recieving a pending request in the chrome Network developer window. I can see that the console.log in the NodeJs app has the data I require so it has retrieved it but there is nothing coming back in any of the console logs in the the AngularJS app.
Here is the code for the both the angularJS app and the Node App:
AnglaurJS:
checkForReplenishmentEmptyTrolley = async () => {
LIBRIS.extensions.openLoadingModal();
console.log('in checkForReplenishmentEmptyTrolley');
try {
const varPromise = await $http.get(`${LIBRIS.config.stockService}stockMovement/checkForUnattachedTrolley`)
.then((response) => {
console.log(response);
// Request completed successfully
}, (error) => {
// Request error
console.log(error);
});
console.log(varPromise.data);
// 1. check that there are no ghost replenish - lines 1-15
console.log('in try/catch');
console.log('promise', varPromise);
} catch (error) {
console.log(error);
}
},
NodeJS code:
app.get(`${ROUTE}/attachTrolley`, async function(req, res){
const newRequest = await DB.newRequest();
console.log('we have made it to the route');
try {
console.log('we have made it to the Try/Catch route');
newRequest.input();
const record = await newRequest.execute('dbo.usp_STK_CheckForUnattachedTrolley');
res.json(record)
console.log(record, 'record');
} catch (err){
handleError(res, err);
console.log(err);
}
});
The problem is that you are doing a .then on a awaited promises and not returning anything from that. You have two choice here
Either return response from then so when you try to access the value here console.log(varPromise.data); it works.
Or remove the .then alltogather as it is not required because you are awaiting it any ways.
Basically just do this
checkForReplenishmentEmptyTrolley = async () => {
LIBRIS.extensions.openLoadingModal();
console.log("in checkForReplenishmentEmptyTrolley");
try {
const varPromise = await $http.get(`${LIBRIS.config.stockService}stockMovement/checkForUnattachedTrolley`);
console.log(varPromise.data);
// 1. check that there are no ghost replenish - lines 1-15
console.log("in try/catch");
console.log("promise", varPromise);
} catch (error) {
console.log(error);
}
};
Hope this fixes your issue.
Solved it! I had no return statement in my route!
The Problem
I deployed a create-react-app webapp to aws ec2. It's used to display data from a database and send data to it. I use ExpressJS, CORS and MySQL.
With the following code i fetch the corresponding URL and the server.js sends back the database content. Until here, everything works fine.
getBets = _ => {
fetch("http://ec2***.amazonaws.com
.then(response => response.json())
.then(response => this.setState({bets: response.data}))
.catch(err => console.error(err))
};
The problem begins when sending data to the database with the following code:
addBet = _ => {
const { bet } = this.state;
fetch(`http://ec2***.amazonaws.com/bets/add?name=${bet.person_name}&bet=${bet.time_bet}`)
.then(response => response.json())
.then(this.getBets)
.catch(err => console.error(err))
};
On click the addBet-function populates the db, but in chrome I following error:
GET http://ec2***.amazonaws.com/bets/add?name=Peter%20Pan5&bet=10:17%205 net::ERR_EMPTY_RESPONSE
and
TypeError: Failed to fetch
Regarding chrome dev-tools, the first error corresponds to the fetch in the addBet function and the second error to the catch part.
On the server side I've the following code for processing the fetch:
app.get("/bets/add", (req, res) => {
const {name, bet} = req.query;
const INSERT_BET = `INSERT INTO bets (name, bet, timestamp) VALUES("${name}", "${bet}", CURTIME())`;
connection.query(INSERT_BET, (err, res) => {
if (err) {
return res.send(err);
}
else {
return res.send("succesfully added your bet");
}
})
});
I want to mention, that the res paramter in the app.get part is unused. That tells me my IDE.
After a lot of hours digging deeper in the topics of expressJS and the fetch api, I guess, that the app.get part doesn't send a response to the server. But the fetch need some response.
My Question
How do I have to change the code in the app.get part to send a proper response back to the server?
AND
Am I right with my guess?
In MYSQL when you do an insert query you get back err,results and fields in the callback function like this:
connection.query('INSERT INTO posts SET ?', {title: 'test'}, function (error,
results, fields) {
if (error) throw error;
console.log(results.insertId);
});
You have used the parameter res for result and then you have used res.send() which now corresponds to that res parameter in the callback function and not the res object.Rewrite it like this:
app.get("/bets/add", (req, res) => {
const {name, bet} = req.query;
const INSERT_BET = `INSERT INTO bets (name, bet, timestamp) VALUES(?,?,?)`;
connection.query(INSERT_BET,[name,bet,CURTIME()] ,(err, result) => {
if (err) {
return res.send(err);
}
else {
return res.send("succesfully added your bet");
}
})
});
I have also used prepared statement in place of normal sql queries. These are used to prevent sql injections. I hope it will work now.
I have some promise
getSomeInfo(data) {
return new Promise((resolve, reject) => {
/* ...some code... */
someObject.getData((err, info) => {
if (info) {
resolve(info)
}
else {
reject("Error")
}
})
})
}
I use this promise and want to send response to client from Controller (AdonisJS):
async create ({ request, response }) {
this.getSomeInfo(data).then(info => {
console.log(info) // It's work, i get the data from promise
response.status(201).json({ // but this is not work
code: 201,
message: "Data received!",
data: info
})
})
}
Why response is not work?
Simply do this.
async create ({ request, response }) {
const info = await this.getSomeInfo(data)
console.log(info)
response.status(201).json({
code: 201,
message: "Data received!",
data: info
})
}
When marking a function as async the function must return a Promise, this can be done explicitly.
async create({ request, response }) {
return this.getSomeInfo(data).then(info => {
console.log(info) // It's work, i get the data from promise
response.status(201).json({ // but this is not work
code: 201,
message: "Data received!",
data: info
})
})
}
Or implicitly using the await keyword.
async create({ request, response }) {
const info = await this.getSomeInfo(data)
console.log(info) // It's work, i get the data from promise
response.status(201).json({ // but this is not work
code: 201,
message: "Data received!",
data: info
})
}
If your console.log(info) inside of create() works and shows the data you want, but the response.status(201).json(...) does not send a response, then I can see the following possibilities:
You've already sent a response to this request (and thus cannot send another one)
The .json() method is having trouble converting info to JSON (perhaps because of circular references) and throwing an exception.
You aren't passing the arguments request and response properly and thus response isn't what it is supposed to be.
You can test for the second case like this:
create ({ request, response }) {
this.getSomeInfo(data).then(info => {
console.log(info) // It's work, i get the data from promise
response.status(201).json({ // but this is not work
code: 201,
message: "Data received!",
data: info
});
}).catch(e => {
console.log("Error in create()", e);
response.sendStatus(500);
});
}
Also, there is no reason for this method to be declared async as you don't show that you're using await or any of the features of an async function.
In the comments, you say that this function is called directly by a router (I assume an Express router). If that's the case, then the function arguments are not declared properly as they come as two separate arguments, not as properties of an object. Change the function declaration to this:
create (request, response) { ... }
I'm trying to pipe a file from service A trough service B into my Postman cliente. Service A builds an delivers a CSV file, and service B (nodejs) has to pipe into my client.
After researching a lot I have managed to successfully pipe the files into service B and then into Postman. Now I want to handle the ugly cases: what if the request token is invalid? What if I can't find the file?
As of this moment, I have found zero documentation or examples on how successfully handle errors while piping a request using superagent.
This is what I have so far
router.post("/csv", (req, res) => {
download_csv(req.get("Authorization"), req.body.ids)
.then((response) => {
res.sendFile(path.resolve(response));
})
.catch((err) => {
res.status(error.status).json(error.response.body);
})
});
function download_csv(token, ids) {
const stream = fs.createWriteStream("filters.csv")
let request = agent
.post(`${profiles}/api/documents/csv`)
.set("authorization", token)
.send({
ids: ids,
action: DOWNLOAD_CSV_PROFILES
})
request.on("response", res => {
// Maybe I can use abort to handle this thing, but can't figure out how!
// if (res.status !== 200) request.abort()
console.log(res.status)
})
request.on("abort", () => {
console.log("aborted")
return new Promise((resolve, reject) => {
resolve("request aborted")
})
})
request.pipe(stream)
return streamToPromise(stream);
}
function streamToPromise(stream) {
return new Promise((resolve, reject) => {
stream.on("error", (err) => {
console.log("error in error")
})
stream.on("finish", () => {
console.log("File saved")
resolve(stream.path);
});
});
}
This code handles the creation of the files correctly. When I fake the token or misspell the Authorization header, I get a correct 401 response, but a file gets written anyway with its contents being the authentication error.
Can anyway give me a hint on how to:
actually catch and manage the request when fails
in such case, how to escape the piping by going back to the express context and just returning a failed express request?
Many thanks!
If I understand you correctly, simply create the fs write stream in on('response') and make a small fix on the resultion.
function download_csv(token, ids) {
return new Promise((resolve, reject) => {
let request = agent
.post(`${profiles}/api/documents/csv`)
.set("authorization", token)
.send({
ids: ids,
action: DOWNLOAD_CSV_PROFILES
})
request.on("response", res => {
// Maybe I can use abort to handle this thing, but can't figure out how!
if (res.status === 200) {
res
.on("end", resolve)
.pipe(fs.createWriteStream("filters.csv"));
} else {
reject();
}
})
request.on("abort", reject);
});
}
I'm not sure what is the "request" you're using - but assuming it's actually the request npm module that will help.
Ideally, upload the file to a temporary directory and move it when the promise is resolved, delete on rejected. This way you'll solve the issue of partial downloads.
If you want to make any on-the-fly transforms, check out my "scramjet". It'll make everything easier with promises.