How to execute get after post in nodejs? - node.js

I'm executing post from react and after that I have some calculations on my back end. How to execute get to show the result on my front end after post and calculation ?

I think I got your question, albeit vague.
But,
1) You want to post a data to some route. The route maybe gives a success response or an error or maybe some different data, but it internally does some processing maybe adds some row to a db table.
2) You want to fetch the current state of the db table(I am assuming table, may be anything).
If this is the scenario, you can do what you are doing just add a get call in the chain.
axios.post('/api/OddsCalculator', newGame)
.then(games => {
// this means you got your game
this.setState({ games }, () => console.log(), games);
//now add one get request as well
return axios('/api/getSomeData');
})
.then((data)=>{
//this data is from the GET call
this.setState({ data })
})
.catch(err => this.setState({
errors: err.response.data
}))
Hope this is a fair assumption, but feel free to edit the answer when you get your solution.
Refer Promise Chaining here: https://javascript.info/promise-chaining

You call it on the success of the previous method. You use nested calls. Please find below example where there should be two methods : yourPostMethod & yourGetMethod defined before you call them.
function handler () {
return yourPostMethod()
.then(yourGetMethod)
.then((result) => {
console.log(result)
return result
})
}

You have express tag in question, so I am assuming you're using that.
With express, redirect works beautifully. I use it all the time
Say:
app.post('/somePOSTpath', (req, res) => {
// Do Some stuff
res.redirect('/somepath');
})
This will direct your backend to somepath at the end.

Related

res.render() calls promise twice expressjs

Hello I am still a beginner in Nodejs and MongoDB. When I am running res.render() function as shown below I get 2 console logs, first with the correct result from mongodb find query and second with null. If I remove res.render() It works properly with only one console.log() output and not the second null.
router.get('/:areaslug', (req, res) => {
// Query results
let areavar = {}
return client.db("AwesomeApartments")
.collection("areas")
.findOne({slug: req.params.areaslug
})
.then((datadb) => {
// first time shows correct results next it shows null
console.log(" bug-testing : "+JSON.stringify(datadb));
//storing result of first query to my object
areavar = datadb;
return client.db("AwesomeApartments")
.collection("apartments")
.find({area:datadb._id})
.toArray()
})
.then((apartmentdb) => {
// Storing results of second query
areavar.apartments = apartmentdb;
//removing this solves the issue
return res.render('area',areavar);
}).catch(err =>
{
console.log(err);
return;
})
});
To those who find their way here, browser was generating two get requests. First one for query and second one for favicon.ico. Handling favicon.ico request solved this issue.

ExpressJS - function returning undefinded

function checkFamilyStatus() keeps returning undefined for some reason, when it should be returning a boolean value from a mongodb collection.
A bit of context here - I decided to separate the logic part from the router methods like get and post methods, so as to make it look clean and understandable like in functional programming. So I put the logic part in functions and invoke them inside the router methods, but it doesn't work out. Besides, I don't know if this is a good practice or not. Wouldn't it be much easier to read if done like this, instead of say, putting a whole bunch of code in one place?
I've been stuck on this piece of code for a while. I am a bit confused on the working of asynchronous JS as a whole. I did some research, but still don't understand why this wouldn't work. Could someone clarify this up for me?
// post method
router.post("/create", ensureAuthenticated, async(req, res) => {
let userID = req.user.id;
console.log(await checkFamilyStatus(userID)); // but returns undefined
// rest of the code
}
// check family status
checkFamilyStatus = async userID => {
Account.findOne({
_id: userID
}, (err, account) => {
return account.hasFamily; // should return boolean value ?
});
};
Assuming the logic behind account.hasFamily is correct, then you need to await for the return, so it should be return await account.hasFamily;

Recommended pattern to page through API response until exhausted?

I'm new to Node and the async programming model. I'm having problems dealing with a simple requirement that seems pretty basic in synchronous environments: paging through an API response until the response is empty.
More specifically, the API, on a successful call, will return data and a status of 200 or 206 (partial content). If I see the 206 response, I need to keep making calls to the API (also sending a page query param that I increment each time) until I see the 200 response.
In a synchronous language, the task will be a piece of cake:
// pseudocode
data = []
page = 1
do {
response = api.call(page)
data.append(response.data)
page++
} while (response != 200)
return data
Now, in Node, for a single api call, code like this will work:
// fire when '/' has a GET request
app.get('/', (req, res) => {
axios.get('https://api.com/v1/cats')
.then(response => {
// now what??
});
});
});
See the //now what?? comment? That's the point where I'm wondering how to proceed. I came across this somewhat-relevant post but am not able to convert this to a format that will work for me in Node and Axios.
Is it enough to just wrap the axios code in a separate function? I don't think so, because if I do this:
function getData(pageNum) {
axios.get('https://api.com/v1/cats')
.then(response => {
// now what??
});
});
}
I can't rely on a return value because as soon axios.get() gets executed, the function will be over. I can call getData() again after I get the first response, but then, suppose I want to return all the data from these multiple calls as the HTTP response from my Express server . . . how do I do that?
I hope I will not get downvoted for laziness or something. I've really looked around but not found anything relevant.
First, a counter-question: Is the data set so big that you need to worry about using up all the memory? Because if so then it will take more work to structure your code in a way that streams the data all the way through. (In fact I'm not even sure whether express allows streaming... you are using express aren't you?)
From the axios documentation, it looks like response is a readable stream which provides the response body. So reading it is also an asynchronous task. So you should write a function that does that. See the "Stream" page of the nodejs docs for more details. Or I could be persuaded to help with that too, time permitting. But for now, I'll assume you have a function readResponse, which takes an axios response object as an argument and returns a promise, and the promise resolves to an object such as { statusCode: 206, result: ['thing1', 'thing2'] }. I'll also assume that your goal is to get all the result arrays and concatenate them together to get e.g. ['thing1', 'thing2', 'thing3', 'thing4', 'thing5', 'thing6'].
You could write a self-calling version of your getData function. This will retrieve all data from a given page onwards (not just the page itself):
function getData(pageNum) {
axios.get('https://api.com/v1/cats' + (pageNum ? '?page=' + pageNum) : '')
.then(readResponse)
.then(function(parsedResponse) {
if(parsedResponse.statusCode == 200) {
return parsedResponse.result;
} else if(parsedResponse.statusCode == 206) {
return getData(pageNum + 1).then(function(laterData) {
return parsedResponse.result.concat(laterData);
});
} else {
// error handling here, throw an exception or return a failing promise.
}
});
});
}
Then, to get all data, just call this function with pageNum = 0:
// fire when '/' has a GET request
app.get('/', (req, res) => {
getData(0)
.then(function(results) {
// results is now the array you want.
var response = JSON.stringify(results); // or whatever you're doing to serialise your data
res.send(response);
});
});

Not able to return posts by user id

When trying to fetch all the posts by a user id, cosmos DB only return an empty array, but when using mongo DB through atlas, it returns all the posts by that user. What am i doing wrong.
exports.postsByUser = (req, res) => {
Post.find({ postedBy: req.profile._id })
.populate("postedBy", "_id name")
.select("_id title body created likes")
.sort("_created")
.exec((err, posts) => {
if (err) {
return res.status(400).json({
error: err
});
}
res.json(posts);
});
`enter code here`};
I receive a http status of 200, but with just an empty array. and when i try fetching all the posts by all users it returns.
I know this might not be "the answer" but it is a suggestion which will bring others to the correct answer in their case.
For those who run into bugs like these, the easiest way to find out what is happening and which step is making the unexpected return is to comment out all the pipeline steps, in this case, populate, select and sort. Then debug from there - if it returns anything, if there is no result you can start from your match case (find), if it does return you can move to next pipeline step and so on.
Taking some time debugging yourself will make you understand your code better, and you will find the answer yourself faster than waiting for someone on stackoverflow to give u suggestions.

Node.js DNS Lookup scope error? (POST request)

I'm making a DNS Lookup API using Node.js and Express.js framework such that when it sends a POST request, it should return the addresses of different record types.
app.post('/', (req, res) => {
// Request format
// const l = {
// lookup: 'twitter.com',
// recordTypes: ['A', 'TXT']
// };
// Using destructor to fetch properties
const { lookup, recordTypes } = req.body;
console.log(lookup, recordTypes);
// For each record type
recordTypes.forEach(function(type) {
// setTimeout to get something async
setTimeout(function() {
dns.resolve(lookup.toLowerCase(), type, (err, addresses) => {
console.log(type);
if (err) {
return console.log(`\nType(${type}):\n`, err);
}
result = result + JSON.stringify({ type: `${type}`, response: { addresses } });
console.log(result);
});
}, 2000);
});
res.send(result);
});
It logs the correct stuff in the console but when it comes to the response, it returns an empty string. I used setTimeout to mimic the asynchronous nature of the request but it just does not work.
Please assume that I have declared stuff like result etc. because it is working. Also, please don't to redirect me to the Node.js documentation because I have already read that stuff and that's not the problem here. The problem is that I need to get every record type in an array and send that back as a response.
Here's what I have tried:
Tried to push response for each record type in the result array,
Tried to use a for of loop instead of forEach
Please help!
The way I'm reading your code is that for each item in the array you correctly use callbacks to do each individual bit of processing.
However, remember that forEach itself is not asynchronous. Thus you are setting up a bunch of tasks that will complete sometime, then returning undefined... then your results start to trickle in.
There's a couple ways to correctly. As you are using callbacks here I will use that style. You want to get a callback when all items in an array have been completely processed. The async module does this very well, providing a lot of high quality methods that act on arrays and such and give you a way to have a callback when they are all over.
Your function will look something like:
let res = []
async.each( recordTypes,
( type, done ) => {
dns.resolve(lookup.toLowerCase(), type, (err, addresses) => {
result = result + JSON.stringify({ type: `${type}`, response: { addresses } });
done(err)
} )
},
(allOverError) => {
res.send(result);
}
)
Notice there are two function parameters here: the first one is called for every item in the list, and the last is called when every item in the list has been completely processed.
There are other ways too, promises or the async/await keywords (confusing because of the name of the async module), but callbacks are good.

Resources