I am working on simple user login in ReactJs with Nodejs and Express-session. I got problem that my front end (React login page) not working. here is the Fetch API that I used in Login.js:
SubmitLogin (event) {
event.PreventDefault();
debugger;
fetch('http://localhost:4000/login', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type' : 'application/json'
},
body : JSON.stringfy (this.state)
}).then((Response) => Response.json())
.then((result) => {
console.log(result);
if (result.Status === 'Invalid')
alert('Invalid User');
else
this.props.history.push({Home});
alert('Login Sucessfull');
})
console.log(this.state);
alert("test input login")
}
for connecting to backend, I added server.js with coded like this :
app.post('/login', jsonParser, (req, res) => {
var username = req.body.username;
var password = req.body.password;
if (username && password) {
dbConn.query(`SELECT * FROM user_tbl WHERE username = ? AND password = ?`, [username, password], (err, results, fields) => {
if (results.length > 0) {
req.session.loggedin = true;
req.session.username = username;
res.redirect('/home');
console.log(results)
} else {
res.send('Incorrect Username and/or Password!');
}
res.end();
});
} else {
res.send('Please enter Username and Password!');
res.end();
}
});
app.get('/home', (req, res) => {
if (req.session.loggedin) {
res.send('Welcome back, ' + req.session.username + '!');
} else {
res.send('Please login to view this page!');
}
res.end();
});
I already tested back end using postman, and it's working. Please help me with some suggestion and how I can put console.log to find the error in Login.js. Thanks for help
the result in postman :
Change the Response.json() to Response.text() as you are returning text in response not json, and you could add the catch block to handle the errors.
I can see in your code that you are using Content-Type application/x-www-form-urlencoded in the Postman and application/json in the fetch call. use same Content-Type in both request.
SubmitLogin(event) {
event.PreventDefault();
fetch('http://localhost:4000/login', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringfy(this.state)
}).then((Response) => Response.text())
.then((result) => {
console.log(result);
if (result.Status === 'Invalid')
alert('Invalid User');
else
this.props.history.push({ Home });
alert('Login Sucessfull');
}).catch(error => {
console.error(error)
})
console.log(this.state);
alert("test input login")
}
You could change your code to use async/await for better readability.
async SubmitLogin(event) {
event.PreventDefault();
try {
let response = await fetch('http://localhost:4000/login', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringfy(this.state)
});
let result = await response.text();
console.log(result);
if (result.Status === 'Invalid')
alert('Invalid User');
else
this.props.history.push({ Home });
alert('Login Sucessfull');
} catch (error) {
console.error(error.message);
}
console.log(this.state);
alert("test input login")
}
Related
I am new to React so there might be a lot of mistakes around. Also, I know there are similar questions, but none helped with my problem so far.
I'm working on a project (using a template) that is using Java Spring (back-end) and ReactJS (front-end).
At the moment I am trying to make a login form, and verify the credentials.
These are the functions that I use when I press Login:
onSubmit(){
let login = {
username: this.state.username,
password: this.state.password
};
this.checkLogin(login);
}
checkLogin(login){
return this.sendRequest(login, (result, status) => {
console.log("AICI NU AJUNG CRED");
if (result !== null && (status === 200 || status === 201)) {
console.log("Successfully inserted person with id: " + result);
this.reloadHandler();
} else {
console.log("There was an error " + result);
}
});
}
sendRequest(login, callback){
let request = new Request(HOST.backend_api + endpoint.login + "/login", {
method: 'POST',
headers : {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify(login)
});
console.log(request.url);
console.log(login);
RestApiClient.performRequest(request, callback);
}
function performRequest(request, callback){
fetch(request)
.then(
function(response) {
if (response.ok) {
response.json().then(json => callback(json, response.status,null));
}
else {
response.json().then(err => callback(null, response.status, err));
}
})
.catch(function (err) {
//catch any other unexpected error, and set custom code for error = 1
callback(null, 1, err)
});
}
I try it with a "test" username and "test" password I have in my database.
And this is the result:
dev console result 1
dev console result 2
I have created a backend middleware which checks if a user is logged in or not.
This functions handle the login route and initialise the req.session.
router.post("/login", upload.none(), async function (req, res) {
console.log("API");
const curr_email = req.body.email
const curr_password = req.body.password
let login_res = await User_functions.loginUser(req, curr_email, curr_password)
if (login_res == -1 || login_res == false) {
return res.send({error:"Wrong username or password"})
}
req.session.LoggedIn = true
req.session.user_id = login_res['user_id']
console.log("Successfully logged in !!!")
return res.redirect("/users")
});
This is the middleware which helps with authentication.
const requiresLogin = (req, res, next) => {
console.log("req.session",req.session)
if (req.session && req.session.user_id) {
return next();
} else {
console.log("User not logged in")
return res.status(400).json({error:'You must be logged in to view this page.'})
}
}
Now, using postman, this works as expected. User can only access specific URL's when logged in. But when I fetch the same URL using React js, after login in it fails. I can't figure out the reason for this.
This is my react js login control.
handleSubmit(event) {
event.preventDefault();
const requestOptions = {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email: this.state.username,password : this.state.password })
};
let first = process.env.REACT_APP_URL
let second_arg = "login"
let url = first + second_arg
fetch(url, requestOptions)
.then(response => response.json())
.then(data => {
if('error' in data){
alert("Failed");
}
else{
// let history = useHistory();
// this.history.push("/dashboard");
this.props.history.push('/dashboard');
}
})
}
After redirecting if I try to access a protected route, I get alert that user is not logged in.
componentDidMount(){
const requestOptions = {
method: 'GET',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify()
};
const userId = this.props.match.params["user_id"];
let first = process.env.REACT_APP_URL
const url = first + "users/" + userId
console.log(url)
fetch(url, requestOptions)
.then(response => response.json())
.then(data => {
if('error' in data){
alert(data['error']);
}
else{
console.log(data)
this.setState({ user: data })
}
})
}
Stuck on this problem for 2 days now. Don't know what I am missing here. Can't find a reason for this anywhere on the internet also. Most folks have used JWT.
The complete frontend code is here :- https://github.com/dhruvdesmond/nutrify_frontend.
And backend is at :- https://github.com/dhruvdesmond/nutrify_backend
My client is Vue.js using a Vuex store. I am using passport.js for authentication on the server side. Login and account registration is working. Checking mongodb shows new data. But express is sending an undefined response to the client. This is my first major javascript project so I'm hoping it's something simple my eyes just can't see yet.
client: api.js
export async function registerUser(user) {
console.log("api to register user");
console.log(user);
const route = `${api}/register`;
return fetch(route, {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(user)
})
.then(response => {
console.log(response.json());
return response.json();
})
.then(json => {
console.log(json);
return json;
})
.catch(err => {
console.error(err);
});
}
client: index.js (vuex store where res is undefined)
actions: {
async register(state, user) {
apis.registerUser(user).then(res => {
if (res.success) {
this.dispatch("loadUser");
alert("successfully registered");
}
});
},
async loadUser() {
apis.getUser().then(res => {
this.commit("setUser", res.user);
});
}
}
server: app.js
app.post('/api/v1/register', function(req, res) {
const success = true;
Users=new User({email: req.body.email, username : req.body.username});
console.log(req.body);
User.register(Users, req.body.password, function(err, user) {
if (err) {
console.log('account could not be saved');
success = false;
} else {
console.log('account saved');
}
})
res.send({success: success});
});
fetch error printing to console
The server console.logs in the app.js route indicate the req.body has the right data and user account is saved successfully. No errors occur on res.send but the client gets an undefined response.
After much banging my head against the table and some outside assistance, I found a solution. I had two main issues.
I was not preventing the default on the submit button so the form was refreshing before the request was properly handled.
Mishandling of javascript promises.
Working code below:
api.js
export function registerUser(user) {
console.log("api to register user");
console.log(user);
const route = `${api}/register`;
return fetch(route, {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(user)
})
.then(response => {
console.log(response.json());
return response.json();
})
}
index.js (vuex store)
actions: {
register(state, user) {
apis.registerUser(user).then(res => {
if (res.success) {
alert("successfully registered");
}
}).catch(err => {
console.error(err);
});
}
}
app.js code remained the same
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 want to use received data from server on client . I use a NodeJS Server with NextJS and React.
I use this function on the server:
function addEmailToMailChimp(email, callback) {
var options = {
method: 'POST',
url: 'https://XXX.api.mailchimp.com/3.0/lists/XXX/members',
headers:
{
'Postman-Token': 'XXX',
'Cache-Control': 'no-cache',
Authorization: 'Basic XXX',
'Content-Type': 'application/json'
},
body: { email_address: email, status: 'subscribed' },
json: true
};
request(options, callback);
}
The function will be run from this point:
server.post('/', (req, res) => {
addEmailToMailChimp(req.body.email, (error, response, body) => {
// This is the callback function which is passed to `addEmailToMailChimp`
try {
var respObj = {}; //Initial response object
if (response.statusCode === 200) {
respObj = { success: `Subscribed using ${req.body.email}!`, message: JSON.parse(response.body) };
} else {
respObj = { error: `Error trying to subscribe ${req.body.email}. Please try again.`, message: JSON.parse(response.body) };
}
res.send(respObj);
} catch (err) {
var respErrorObj = { error: 'There was an error with your request', message: err.message };
res.send(respErrorObj);
}
});
})
The try method is used to verify that an email address could be successfully saved to MailChimp. An appropriate message is sent to the client.
On the Client-Side, i use this function to receive and display the data from the server:
handleSubmit() {
const email = this.state.email;
this.setState({email: ""});
fetch('/', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({email:email}),
}).then(res => {
if(res.data.success) {
//If the response from MailChimp is good...
toaster.success('Subscribed!', res.data.success);
this.setState({ email: '' });
} else {
//Handle the bad MailChimp response...
toaster.warning('Unable to subscribe!', res.data.error);
}
}).catch(error => {
//This catch block returns an error if Node API returns an error
toaster.danger('Error. Please try again later.', error.message);
});
}
The problem: The email address is saved successfully at MailChimp, but the message is always displayed: 'Error. Please try again later.'from the .catch area. When i log the error from the catch area i get this:
TypeError: Cannot read property 'success' of undefined
Where is my mistake? I have little experience in Node.js environments. I would be very grateful if you could show me concrete solutions. Thank you for your replies.
With fetch theres no data property on the response. You have to call res.json() and return that promise. From there the response body will be read and deserialized.
handleSubmit() {
const email = this.state.email;
this.setState({email: ""});
fetch('/', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({email:email}),
})
.then(res => {
console.log(res); //to make sure the expected object is returned
if(res.data.success) {
//If the response from MailChimp is good...
toaster.success('Subscribed!', res.data.success);
this.setState({ email: '' });
} else {
//Handle the bad MailChimp response...
toaster.warning('Unable to subscribe!', res.data.error);
}
}).catch(error => {
//This catch block returns an error if Node API returns an error
toaster.danger('Error. Please try again later.', error.message);
});
}
Two things you need to change:
Call and wait for res.json() to get the response body as json object.
The result of 1. is your 'data' object that you can use directly
handleSubmit() {
//...
fetch('/', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({email:email}),
})
.then(res => res.json())
.then(data => {
if(data.success) {
//...
toaster.success('Subscribed!', data.success);
} else {
toaster.warning('Unable to subscribe!', data.error);
}
}).catch(error => {
//...
});
}