Problem with async/await and http client requests - node.js

Not sure what I'm missing here but the console.log() line prints "Promise { }" instead of the JSON body from the response.
I believe that I'm doing something wrong with async/await.
My code (Express):
async function axiosPost(url, payload) {
try {
const res = await axios.post(url, payload);
const data = await res.data;
return data;
} catch (error) {
console.error(error);
}
}
app.get('/data', (req, res) => {
data = axiosPost('http://localhost:8080', {
userpass: 'XXX',
method: 'getdata'
});
console.log(data)
res.status(200).send({
message: data
})
});
Any help is appreciated.

replace your router with this. you were not using await while making an API call. Hope it helps.
app.get('/data', async (req, res) => {
let data = await axiosPost('http://localhost:8080', {
userpass: 'XXX',
method: 'getdata'
});
console.log(data)
res.status(200).send({
message: data
})
});

You get that result because you didn't resolve the call to axiosPost() which is asynchronous. This can be solved in 2 ways, one by appending .then() to the axiosPost() call or simply awaiting it using the await keyword. See below:
async function axiosPost(url, payload) {
try {
const res = await axios.post(url, payload);
const data = await res.data; // this is not required but you can leave as is
return data;
} catch (error) {
console.error(error);
}
}
// I converted the callback to an async function and
// also awaited the result from the call to axiosPost(),
// since that is an async function
app.get('/data', async (req, res) => {
data = await axiosPost('http://localhost:8080', {
userpass: 'XXX',
method: 'getdata'
});
console.log(data)
res.status(200).send({
message: data
})
});
// OR using `then()`
app.get('/data', (req, res) => {
axiosPost('http://localhost:8080', {
userpass: 'XXX',
method: 'getdata'
}).then((data) => {
console.log(data);
res.status(200).send({
message: data
});
});
})

Related

Correct Async/Await usage with Axios

I'm working with axios to post user responses to a database. I'm using this set up shown below to handle many posts back to back. I'm wanting to make sure that this is the correct set up to avoid backing up requests.
Is this the correct way to use async and await when using Axios?
// Frontend React Code
// Posting conclusionInput to Mongodb
const postConclusion = async () => {
await axios({
method: "POST",
data: {
conclusion: conclusionInput,
},
withCredentials: true,
url: "http://localhost:4000/conclusion",
}).then((res) => console.log(res));
};
//Backend Node / Express code
app.post("/conclusion", (req, res) => {
console.log("Attempting to post the conclusion");
User.findOne({ username: req.user.username }, async (err, user) => {
if (err) throw err;
if (user) {
(user.conclusion = req.body.conclusion), await user.save();
res.send();
}
});
});
Frontend
In an async function use await and try/catch. Any .then calls can be rolled out into const x = await y variables.
Return values from promise functions, in case you want to use them.
const postConclusion = async () => {
const res = await axios({
method: "POST",
data: {
conclusion: conclusionInput,
},
withCredentials: true,
url: "http://localhost:4000/conclusion",
})
console.log(res)
return res
};
Backend
Again, if you are going with async use that API consistently.
Mongoose provides a promise API, so use that too.
app.post("/conclusion", async (req, res) => {
try {
console.log("Attempting to post the conclusion");
const user = await User.findOne({ username: req.user.username })
if (!user) {
return res.send('not found')
}
user.conclusion = req.body.conclusion
await user.save()
return res.send('saved')
}
catch (error) {
console.error(error)
return res.send('error')
}
});
When using async await, setting an await call to a variable is equal to the parameter in a .then callback
// Frontend React Code
// Posting conclusionInput to Mongodb
const postConclusion = async () => {
// Set the await call to a variable.
const res = await axios({
method: "POST",
data: {
conclusion: conclusionInput,
},
withCredentials: true,
url: "http://localhost:4000/conclusion",
})
// Now no need for .then()!! This is why async/await is so nice.
console.log(res)
};
//Backend Node / Express code
app.post("/conclusion", (req, res) => {
console.log("Attempting to post the conclusion");
User.findOne({ username: req.user.username }, async (err, user) => {
// You need to send the error to the request. Otherwise, the
// request will keep waiting for a response until it times out.
if (err) {
console.error(err)
res.status(500).send(err)
}
if (user) {
// Side note: these should all be on separate lines:
user.conclusion = req.body.conclusion
await user.save();
// You should also send a status code and a response message
res.status(200).send({status: "Success}");
}
});
});
I recommended have a folder called "services" and inside it has yours services by backend.
services/
getData.js
import axios from "axios";
export const getData = () => {
axios.post("http://localhost:4000/conclusion");
};
App.js
import { useEffect, useState } from "react";
import { getData } from "./services/getData";
export default function App() {
const [data, setData] = useState([]); // save the value of service
useEffect(() => {
try {
getData().then((res) => {
setData(res?.data);
});
} catch (e) {
console.error(e);
}
}, []); // execute once
return <div className="App">{data}</div>;
}

Stubbing function with jest to test Internal error

I'm trying to test a controller function using jest, and i want to test all three status return
const messagesSender = async (req, res) => {
try {
const { message } = req.body;
if (!message) {
return res.status(400).send({ message: 'Message cannot be null' });
}
return res.status(200).send(message);
} catch (error) {
return res.status(500).json({ error: 'Internal Error' });
}
};
module.exports = { messagesSender };
Test file:
const messages = require('../controller/messagesController');
describe('Testing Messages Controller', () => {
it('should return internal error', async () => {
const req = {
body: {
message: 'testing',
},
};
const res = {
send: jest.fn(),
status: jest.fn(() => res),
};
const messageResponse = await messages.messagesSender(req, res);
messageResponse.mockImplementation(() => {
throw new Error('User not found');
});
expect(res.status).toBeCalledWith(500);
});
});
But i'm receiving the error:
TypeError: Cannot read property 'mockImplementation' of undefined
How can i fix this and test the 500 result?
it('should return internal error', async () => {
const req = {
body: {
message: 'testing',
},
};
const res = {
send: jest.fn().mockImplementation(() => {
throw new Error('User not found');
}),
status: jest.fn(() => res),
};
await messages.messagesSender(req, res);
expect(res.status.mock.calls[1][0]).toBe(500);
});
In your case send function returning nothing and causing this problem. In this case status method have been called twice, so you need to check the second call.

Why mongo query is showing undefined in node js

I'm trying to check the data with findOne when im trying with the postman getting undefined in console.log , i checked with the same query in roboMongo and its showing the data
this is the result:-
Here is the code:-
exports.signIn = async( req, res ) => {
const {
userEmailPhone,
} = req.body;
await User.findOne ({ email : userEmailPhone}).then((err, user)=> {
console.log("user..", user)
if (user){
res.status(200).send({
message: "sucess"
});
}
})
}
the postman response:-
Since you are already using async - await, I believe there is no need of using the .then() block.
Your code should be updated to use async and await as below:
exports.signIn = async( req, res ) => {
const { email } = req.body;
const user = await User.findOne ({ email : userEmailPhone})
console.log("user..", user)
if (user){
res.status(200).send({
message: "sucess"
});
}
}
If you still want to use the .then() block, I would recommend making the following changes in the code:
exports.signIn = async ( req, res ) => {
const {email} = req.body;
User.findOne ({ email : email}).then((user, err)=> {
console.log("user..", user)
if (user){
res.status(200).send({
message: "sucess"
});
}
})
}
Since the promise callback for MongoDb queries has the following callback format:
.then( (res, err) => {
// do stuff
})
Reference : https://docs.mongodb.com/drivers/node/fundamentals/promises/
You are sending raw json data. First you should use app.use(bodyParser.json());. Only app.use(bodyParser()); is deprecated.
This should fix it assuming you have a json body-parser
exports.signIn = async( req, res ) => {
const {email} = req.body;
User.findOne ({ email : email}).then((err, user)=> {
console.log("user..", user)
if (user){
res.status(200).send({
message: "sucess"
});
}
})
}

Why does my register user post request fail with a 500 error?

I'm building an app with React and Node/Express, and I'm having trouble with my register user function. The data I am passing in is correct, and other endpoints work fine. The register one keeps returning a 500 error and I can't figure out why.
This is my request:
console.log(values)
axios
.post(
'https://foodtrackr-backend.herokuapp.com/api/register',
values
)
.then(res => {
console.log('res.data', res.data);
})
.catch(error => {
console.log('nope');
console.error(error);
});
};
and this is my endpoint:
router.post('/register', async (req, res) => {
let user = req.body;
const newUser = await Users.add(user);
try {
if (newUser) {
res.status(201).json(user);
} else res.status(404);
} catch (error) {
res.status(500).json('noooooo');
}
});
and this is my model:
function findById(id) {
return (
db('users')
.where({ id })
.first()
);
}
async function add(user) {
const [id] = await db('users').insert(user, 'id');
return findById(id);
}
Any help would be appreciated!

nodejs how to do multiple requests

i need to know how i can write my request to make multiple delete.
the second thing is how can i put async function on my code.
i want to delete a campus and in the same time dele the builings with the same id campus in the JSON
app.delete('/campuses/:id', (req, res)=> {
const id = req.params.id;
const details = { 'campusid': new ObjectID(id) };
db.db('').collection('buildings').remove(details, (err, result)=> {
if (err) {
res.send({ 'error': 'en error has occured' });
} else {
res.send(result);
}
});
const details2 = { '_id': new ObjectID(id) };
db.db('').collection('campuses').remove(details2, (err, result)=> {
if (err) {
res.send({ 'error': 'en error has occured' });
} else {
res.send(result);
}
}
);
})
You can delete like this.
app.delete('/campuses/:id', async (req, res)=> {
try {
const id = req.params.id;
const details = { 'campusid': new ObjectID(id) };
await db.db('').collection('buildings').remove(details);
const details2 = { '_id': new ObjectID(id) };
await db.db('').collection('campuses').remove();
res.send(result);
} catch(err) {
return res.json({
success: false,
message: 'error'
});
}
})
You could make sequential functions where the first one calls the second one. You could then pass on variables to the seconds function (ie. your campus ID).
It could look something like this:
const Query1 = (res, query) => {
const request = new sql.Request();
request.query(query, (err, result) => {
if (err) {
return res.json({
success: false,
message: 'error'
});
} else if (result.recordset[0]) {
let campusID = result.recordset;
Query2(res, campusID, query = 'SELECT bla bla')
}
})
}
const Query2 = (res, campusID, query) => {
const request = new sql.Request();
request.query(query, (err, result) => {
if (err) {
return res.json({
success: false,
message: 'error'
});
} else {
return res.json({
success: true
});
}
})
}
There are various ways to make async call.
You can use promises.
Async Functions.
Sending response without waiting for other tasks.
If you want to make parallel calls you can use bluebird join function
I like the syntax of async functions better than promises, but I use both depending on the situation.
Here is an example of running functions in order before moving to the next function:
async.waterfall([
function(callback1) {
//Do some work, then callback
if (error) {
callback1(errorGoesHere,null);
} else {
callback1(null,successMessageGoesHere);
}
},
function(callback2) {
//Do some work, then callback
if (error) {
callback2(errorGoesHere,null);
} else {
callback2(null,successMessageGoesHere);
}
}
], function (error, success) {
if (error) {
//show an error
}
//all good return the response, etc.
});
If anything in these functions fail, it automatically call the end function to catch the error.

Resources