I am not able to clearly Identify the bug, data is send in JSON Format still it is showing unusual error
Forgot Password Route
exports.forgotPassword = catchAsyncErrors(async (req, res, next) => {
const user = await User.findOne({ email: req.body.email });
if (!user) {
return next(new ErrorHandler("User not found", 404));
}
// Get ResetPassword Token
const resetToken = user.getResetPasswordToken();
await user.save({ validateBeforeSave: false });
const resetPasswordUrl = `${req.protocol}://${req.get(
"host"
)}/password/reset/${resetToken}`;
const message = `Your password reset token is :- \n\n ${resetPasswordUrl} \n\nIf you have not requested this email then, please ignore it.`;
try {
await sendEmail({
email: JSON.stringify(user.email),
subject: `Ecommerce Password Recovery`,
message
});
res.status(200).json({
success: true,
message: `Email sent to ${user.email} successfully`
});
} catch (error) {
user.resetPasswordToken = undefined;
user.resetPasswordExpire = undefined;
await user.save({ validateBeforeSave: false });
return next(new ErrorHandler(error.message, 500));
}
});
forgotPassword Action.js
export const forgotPassword = (email) => async(dispatch)=>{
try{
dispatch({type: FORGOT_PASSWORD_REQUEST});
const config = {headers : {"Content-Type": "application/json"}};
const {data} = await axios.post(
"/api/v1/password/forgot",
email,
config
);
dispatch({
type: FORGOT_PASSWORD_SUCCESS,
payload : data.message,
})
}catch(error) {
dispatch({
type: FORGOT_PASSWORD_FAIL,
payload: error.response.data.message,
});
}
}
As mentioned in some answers online available I have made few changes but Error is still their,
In Action.js I have written content type as "application/json".
in forgotPassword Route while sending email to function, I have used a method JSON.stringify.
Your axios.post statement sends a request whose body is an email address (i.e., plain text), but the Content-Type: application/json wrongly claims it to be JSON. That leads to the observed error.
Correct would be
const data = await axios.post(
"/api/v1/password/forgot",
{email},
config
);
(Note the absence of braces around data.)
Related
I am trying to fetch the currently logged-in user's data using the jwt tokens. The API routing for the token verification is working fine but the data I think the (rootUser) from auth.js sent as response might have a problem although it is giving correct values on console.log(rootUser) but when i tried to access the about page on the browser it gave the error
SyntaxError: Unexpected end of JSON input
at callAboutPage (About.js:25:1) that is at line 25 for the About.js file. How to solve this issue?
This is code to About.js where i have defined a callabout page function to behave necessarily on accessing the about page on browser:
const About = ()=>{
const navigate = useNavigate();
const [userData, setUserData] = useState({});
const callAboutPage = async() =>{
try {
const res = await fetch("/about",{
method: "GET",
headers: {
Accept: "application/json",
"Content-Type" : "application/json"
},
credentials: "include"
});
const data = await res.json();
console.log(data);
// setUserData(data);
if(res.status === 401 || res.status===403){
const error = new Error(res.error);
throw error;
}
} catch (err) {
console.log(err);
navigate("/login");
}
}
useEffect(()=>{
callAboutPage();
}, []);
}
This is authenticate.js file where tokens are verified and corresponding user data is finded
const Authenticate = async(req, res, next) => {
const accessToken = req.cookies.jwt;
if(!accessToken) {
return res.status(401).json({error: "Unauthorized: No token provided"});
}
try {
const user = jwt.verify(accessToken, process.env.TOKEN_KEY);
const rootUser = await User.findOne({_id: user.user_id, "tokens.token": accessToken});
if(user) {
req.user = rootUser;
return next();
}
} catch (error) {
return res.status(403).json({error: "Forbidden token error"})
}
}
This is auth.js file to call /about at backend
router.get("/about", Authenticate, function (req, res) {
console.log("about running");
res.send(req.rootUser);
});
So I'm passing user entered data to the backend, but req.body is coming back undefined and i'm not sure why. I've set up my middleware beforehand, yet I still get undefined. I have also checked the the value being sent by axios and has checked out to be correct.
app.use(Cors());
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({extended: true}));
app.post('/signup', (req, res) => {
//const { email } = req.body;
console.log(req.body.email);
if(!req.body.email) {
console.log("No email, failed");
return;
}
const data = {
members: [
{
email_address: req.body.email,
status: "subscribed"
}
]
}
const postData = JSON.stringify(data);
const options = {
url: 'https://us4.api.mailchimp.com/3.0/lists/xxxxxx',
method: 'POST',
headers: {
Authorization: 'xxxxxxx'
},
body : postData
}
request(options, (err, response, body) => {
if(err) {
console.log(err);
} else {
if(response.statusCode === 200) {
console.log("Success!");
}else {
console.log("Error Accessing")
res.send("Error");
}
}
});
});
Here is my axios post method:
handleSubmit = e => {
e.preventDefault();
const { email } = this.state;
axios
.post('http://localhost:5000/signup', email)
.then(() => console.log("Email Added"))
.catch(err => {
console.log(err);
})
};
You have confirmed that what is being POSTed by axios (this.state.email) is not undefined?
The fact that the req body is coming back undefined points to either the data being entered incorrectly or the request for that data being invalid.
What does the entire req.body look like?
My problem was that I was that I was not passing email as an object, hence the object was coming back empty.
I'm having a problem using Axios with my backend. It's probably a very simple fix as I'm new to this.
Postman: The correct response is received for both valid and invalid credentials.
Axios: The correct response is received for valid crendentials, but the axios method's catch block is run when invalid credentials are entered.
authController.js:
exports.login = (req, res, next) => {
const email = req.body.email;
const pass = req.body.password;
let loadedUser;
User.findOne({ where: { email: email } })
.then(user => {
if(!user) {
const error = new Error('Incorrect username or password');
error.statusCode = 401;
throw error;
} else {
loadedUser = user;
return bcrypt.compare(pass, user.password);
}
})
.then(isEqual => {
if(!isEqual) {
const error = new Error('Incorrect username or password');
error.statusCode = 401;
throw error;
} else {
const token = jwt.sign(
{
email: loadedUser.email,
userId: loadedUser.id
},
process.env.JWT_SECRET,
{ expiresIn: '1hr' }
);
res.status(200).json({ token: token, userId: loadedUser.id });
}
})
.catch(err => {
if (!err.statusCode)
err.statusCode = 500;
next(err);
});
};
The error handler in app.js. It seems to log the error correctly when incorrect credentials are entered, even with axios:
app.use((error, req, res, next) => {
const status = error.statusCode || 500;
const message = error.message;
const data = error.data || 'No Data';
console.log(status, message, data);
res.status(status).json({message: message, data: data});
});
But then the axios catch block runs, so instead of receiving the json message, I get the following error
login(email, password) {
const headers = {
'Content-Type': 'application/json'
};
const data = JSON.stringify({
email: email,
password: password
});
axios.post('http://127.0.0.1:8080/auth/login', data, { headers })
.then(res => console.log(res))
.catch(err => console.log(err));
}
The error in the console for invalid credentials:
Clicking the link highlighted opens a new page stating: "Cannot GET /auth/login", but I'm obviously making a post request, & I've added post to the form (just in case)
Any ideas what I could be missing?
Thanks
Actually your code works fine but Axios will reject the promise of the call if you have the status 401. If you have a status between 200 to 300 it will resolve the promise.
There two ways to deal with this.
Check status in the catch block.
axios.post('http://127.0.0.1:8080/auth/login', data, {
headers
})
.then(res => console.log(res))
.catch(err => {
if (err.response.status === 401) {
//Auth failed
//Call reentry function
return;
}
return console.log(err)
});
or change the validateStatus option;
axios.post('http://127.0.0.1:8080/auth/login', data, {
headers,
validateStatus: function (status) {
return status >= 200 && status < 300 || (status === 401);
},
})
.then(res => console.log(res))
.catch(err => return console.log(err));
I am running a react app with nodejs acting as an api to connect to my database.
For my log in I am sending data to the server, and it is returning a pass or fail.
However I am not sure how to extract this json object.
I have looked at the request and response, and as I have manipulated the json object the response content-length has been changing so I believe it must be there somewhere.
SERVER CODE:
app.post('/api/checkLogin', async (req,res) => {
console.log(req.body);
const {username, password} = req.body;
try{
let state = await DB.checkPassword(username, password);
console.log(state);
if(!state){
res.status(401).json({
error: 'Incorrect username or password',
yay: 'idk work?'
});
}
else if(state){
res.status(200).json({
message: 'we in boys'
});
} else {
res.status(6969).json({
err: 'idk mane'
});
}
} catch(e) {
console.log(e);
}
})
CLIENT CODE:
onSubmit = (event) => {
event.preventDefault();
fetch('/api/checkLogin', {
method:'POST',
body: JSON.stringify({username: this.state.username, password: md5(this.state.password)}),
headers: {
'Content-Type':'application/json'
}
}).then(res => {
if(res.status ===200) {
this.props.loggedIn();
} else if(res.status ===401){
console.log(res.status);
alert('wrong username or password');
}else{
const error = new Error(res.error);
throw error;
}
}).catch(err => {
console.log(err);
alert(err);
});
}
What I was sort of expecting as a way to extract the data would be.
On the server:
res.status(200).json({ message : 'mssg'});
On the client:
console.log(res.status.message) // 'mssg'
Thanks Jin and this post I found for the help Fetch API get raw value from Response
I have found that both
res.status(xxx).json({ msg: 'mssg'}) and res.status(xxx).send({msg: 'mssg'}) work.
The json, or sent message can then be interpreted on the client side with a nested promise. This is done with...
fetch('xxx',headers n stuff).then(res => {
res.json().then((data) => {console.log(data.message)});
//'mssg'
res.text().then((data) => { let data1 = JSON.parse(data); console.log(data1.message);});
//'mssg'
});
According to my experience, using res.status(200).send({message: 'mssg'}) is better.
And you can get data after calling api by using res.data.
Then you can get result as below:
{
message: 'mssg'
}
Here is something that may help.
onSubmit = (event) => {
event.preventDefault();
const userData = {
username: this.state.username, // I like to store in object before passing in
password: md5(this.state.password)
}
fetch('/api/checkLogin', {
method:'POST',
body: JSON.stringify(userData), //stringify object
headers: {
'Content-Type':'application/json'
}
}).then(res => res.json()) // convert response
.then(responseData => {
let status = responseData.whatObjectWasPassedFromBackEnd;
status === 200 ? do something on pass: do something on fail
})
.catch(err => {
console.log(err);
alert(err);
});
}
I can't seem to get the correct response headers when my code enters bcrypt.compare. I thought it was a cors issue at first but I still get the correct response if I entered the wrong and "user does not exist" is displayed.
Here's my api server side code in express
router.post("/api/signIn", (req, res) => {
const { user, password } = req.body;
const queryString = "SELECT * FROM users WHERE user_id = ?";
db.query(queryString, [user])
.then(result => {
if (result.length > 0) {
const hash = result[0].password;
//here bcrypt.compare works server side or with cURL but won't set the response headers in the browser
bcrypt
.compare(password, hash)
.then(same => {
if (same === true) {
console.log("correct password");
res.status(200).json({
code: 200,
message: "correct password"
});
} else {
res.status(401).json({
code: 401,
message: "incorrect password"
});
}
})
.catch(err => console.log(err));
} else {
//this one works though and i can get the response in the browser so it can't be a cors issue
console.log("user does not exist");
res.status(200).json({
code: 401,
message: "User does not exist"
});
}
})
.catch(err => {
console.log("error" + err.message);
});
});
and this is the test function i use in react
const signIn = () => {
fetch("http://localhost:5000/api/signIn", {
method: "POST",
body: JSON.stringify({
user: userName,
password: password
}),
headers: {
"Content-Type": "application/json"
},
})
.then(res => res.json())
.then(response => alert(response.code + response.message))
.catch(err => alert(err));
};
so if i entered the wrong username that is not in the database, the alert function would show (code401User does not exist) but if i entered the correct user bcrypt.compare() doesn't seem to set the response for both correct and incorrect passwords and i would get (TypeError: failed to fetch). testing the api in cURL works though.
Got it, I forgot to put event.preventDefault() on the fetch function.