React adding new users to SQL database (undefined entries) - sql

I have been making a website in which I am beginning to create a registration process.I have created the registration form and a server.js file using npm express. However this keeps throwing this error and I'm not sure why.
This is the error
TypeError: Cannot destructure property 'email' of 'req.body' as it is undefined.
All I want to do is so that when submit button is clicked it the users are simply added to the database.
This is the server.js (The error occurs within this file from what I can gather)
const express = require("express");
const sql = require("mssql");
const app = express();
const port = process.env.PORT || 5000;
app.listen(port, () => `Server running on port ${port}`);
const config = {
user: "sas",
password: "Mypassword456",
server: "DEVSQL_2014", // You can use 'localhost\\instance' to connect to named instance
database: "TestDBWebsite"
};
app.post("/admin-Add-Users", function(req, res) {
res.set("Access-Control-Allow-Origin", "*");
const { email, password } = req.body;
let connection = new sql.ConnectionPool(config, function(err) {
let request = new sql.Request(connection);
request.query(
"insert into Login (email, password) values ('" +
password +
"', '" +
email +
"')"
);
});
res.send({ message: "Success" });
});
register.js
import React from "react";
import "../bootstrap.min.css";
import logo from "../codestone logo.png";
import { Link } from "react-router-dom";
import Popup from "reactjs-popup";
import { Formik } from "formik";
import * as Yup from "yup";
function Register() {
return (
<div className="App">
<Header />
<DisplayUsersCS />
</div>
);
}
class DisplayUsersCS extends React.Component {
constructor() {
super();
this.state = { users: [] };
this.onSubmit = this.handleSubmit.bind(this);
}
handleSubmit(e) {
e.preventDefault();
var self = this;
// On submit of the form, send a POST request with the data to the server.
fetch("/admin-Add-Users", {
method: "POST",
body: {
email: self.refs.email,
password: self.refs.password
}
})
.then(function(response) {
return response.json();
})
.then(function(body) {
console.log(body);
});
}
render() {
console.log(this.state.users);
return (
<div>
<LoginForm></LoginForm>
<form onSubmit={this.onSubmit}>
<input type="text" placeholder="email" ref="email" />
<input type="text" placeholder="password" ref="password" />
<input type="submit" />
</form>
</div>
);
}
}
const LoginForm = () => (
<Formik
class="form-signin"
action="auth"
method="POST"
initialValues={{ email: "", password: "", passwordConfirm: "" }}
onSubmit={(values, { setSubmitting }) => {
setTimeout(() => {
console.log("Logging in", values);
setSubmitting(false);
}, 500);
}}
validationSchema={Yup.object().shape({
email: Yup.string()
.email()
.required("Required")
.matches(/(?=.*codestone)/, "This is not a Codestone email address."),
password: Yup.string()
.required("No password provided.")
.min(8, "Password is too short - should be 8 chars minimum.")
.matches(/(?=.*[0-9])/, "Password must contain a number."),
passwordConfirm: Yup.string()
.required("No password provided.")
.min(8, "Password is too short - should be 8 chars minimum.")
.matches(/(?=.*[0-9])/, "Password must contain a number.")
})}
>
{props => {
const {
values,
touched,
errors,
isSubmitting,
handleChange,
handleBlur,
handleSubmit
} = props;
return (
<form
onSubmit={handleSubmit}
class="form-signin"
action="auth"
method="POST"
>
<div className="jumbotron">
<label htmlFor="email">Email</label>
<input
name="email"
type="text"
placeholder="Enter your email"
value={values.email}
onChange={handleChange}
onBlur={handleBlur}
className={errors.email && touched.email && "error"}
/>
{errors.email && touched.email && (
<div className="input-feedback">{errors.email}</div>
)}
<label htmlFor="email">Password</label>
<input
name="password"
type="password"
placeholder="Enter your password"
value={values.password}
onChange={handleChange}
onBlur={handleBlur}
className={errors.password && touched.password && "error"}
/>
{errors.password && touched.password && (
<div className="input-feedback">{errors.password}</div>
)}
<label htmlFor="email">Password Confirmation</label>
<input
name="passwordConfirm"
type="passwordConfirm"
placeholder="Confirm Password"
value={values.passwordConfirm}
onChange={handleChange}
onBlur={handleBlur}
className={
errors.passwordConfirm && touched.passwordConfirm && "error"
}
/>
{errors.passwordConfirm && touched.passwordConfirm && (
<div className="input-feedback">{errors.passwordConfirm}</div>
)}
<button type="submit" action="auth">
Sign Up
</button>
<p>
<Link to="/Login"> Login </Link>
</p>
<p>
<Link to="/reset"> Reset Password </Link>
</p>
</div>
</form>
);
}}
</Formik>
);
function Header() {
return (
<div class="jumbotron">
<img
className="profile-image"
alt="icon"
src={logo}
width="450"
height="80"
/>
</div>
);
}
export default Register;

On client side (react)
To use fetch to post json data, you need to stringify the data in the body
fetch('https://example.com/profile', {
method: 'POST', // or 'PUT'
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data),
})
.then((response) => response.json())
.then((data) => {
console.log('Success:', data);
})
.catch((error) => {
console.error('Error:', error);
});
https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch
On server side (express.js)
You need to include include middleware in order to read the request body. You can refer to the sample codes here https://github.com/expressjs/body-parser

Related

issues getting data to show on screen from SQL

This is a React Js project that is using Axios, Cors, Express, and Node JS connecting to an SQL database.
I am trying to get the data from an SQL table and have it show on the screen either in a div or p tag each row on its own line. At this time I am able to get it to console.log inside my VS Code terminal from my server.js side as well as console log the data inside my browser console from my frontend of ProductList.js. I do not get any errors in any of my consoles just the data that I would like displayed on the screen.
The below is my server.js
const bodyParser = require('body-parser');
const express = require('express');
cors = require('cors');
const app = express();
app.use(cors());
app.use(express.json());
app.use(express.urlencoded({ extended: true }))
app.use(bodyParser.urlencoded({ extended: true }));
app.get('/collectors', function (req, res) {
var sql = require("mssql");
const config = {
user: 'XXXXXXX',
password: 'XXXXXXX',
server: 'XXXXXXX',
database: 'XXXXXXX',
options: {
trustServerCertificate: true,
trustedConnection: false,
enableArithAbort: true
},
}
sql.connect(config).then(pool => {
return pool.request()
.query('select * from CollectorAssignment.tCollectors ').then(result => {
console.dir(result)
res.send(result)
})
}).catch(err => {
console.log("error at line24: ", err)
})
sql.on('error', err => {
console.log("error at line28: ", err)
})
});
app.listen(5000, () => {
console.log('listening on port 5000')
});
The below is my ProductList.js
import React from "react";
import axios from 'axios';
class ProductList extends React.Component {
state = {
loading: true,
error: "",
data: []
};
componentDidMount() {
this.getCollectorList();
}
getCollectorList = () => {
this.setState({ loading: true });
return axios
.get(
'http://localhost:5000/collectors'
)
.then(result => {
console.log(result);
this.setState({
CollectorList: result.data.items,
loading: false,
error: false
});
})
.catch(error => {
console.error("error: ", error);
this.setState({
error: `${error}`,
loading: false
});
});
};
render() {
const { loading, error, data } = this.state;
if (loading) {
return <p className="productList">Loading ...</p>;
}
if (error) {
return (
<p className="productList">
There was an error loading the collectors.{" "}
<button onClick={this.loadData}>Try again</button>
</p>
);
}
return (
<div className="productList">
<h1>Collector List</h1>
{data.map(result => <p className="productList">{result.CollectorList}</p>)}
</div>
);
}
}
export default ProductList;
Screenshot of my VS Code console data I get the same info in my browser console which is a total of 16 rows of data that I need displayed on the screen
I have gotten this to start working for me here are the changes I have made to the two files I provided. I was calling a few areas improperly and found that I was looking at some ways for SQL and I am using SQL so some connections to the DB were different which caused some issues small syntax things mainly.
Server.js
const express = require('express');
const cors = require('cors');
const bodyParser = require('body-parser');
const config = require('./src/dbfiles/dbConfig')
const app = express();
app.use(cors());
app.use(bodyParser.json({ extended: true }));
var sql = require("mssql");
app.get('/getCollectors', (req, res) => {
sql.connect(config).then(pool => {
return pool.request()
.query('SELECT * FROM CollectorAssignment.tCollectorsTest').then(result => {
res.send(result.recordset)
})
})
})
app.post('/addCollector', function (req, res) {
sql.connect(config).then(pool => {
return pool.request()
.query(`INSERT INTO CollectorAssignment.tCollectorsTest
(
Active,
FirstName,
MiddleInitial,
LastName,
CollectorCode,
CreationDate,
CollectionTeamID
) VALUES (
${req.body.Active},
'${req.body.FirstName}',
'${req.body.MiddleInitial}',
'${req.body.LastName}',
'${req.body.CollectorCode}',
'${req.body.CreationDate}',
1
)`)
.then(result => {
res.send(result)
})
})
});
app.post('/updateCollector', function (req, res) {
sql.connect(config).then(pool => {
return pool.request()
.query(`UPDATE CollectorAssignment.tCollectorsTest
SET ${req.body} = ${req.body}
WHERE ${req.body} = ${req.body}
`)
.then(result => {
res.send(result)
})
})
});
app.delete('/deleteCollector/:CollectorID', (req, res) => {
sql.connect(config).then(pool => {
return pool.request()
.query(`DELETE FROM CollectorAssignment.tCollectorsTest WHERE CollectorID = ${req.params.CollectorID}`).then(result => {
res.send(result.recordset)
})
})
})
app.listen(5000, () => {
console.log('running on port 5000');
})
ProductList.js
import "./userList.css";
import React from "react";
import axios from 'axios';
import { Link } from "react-router-dom";
import { DeleteOutline, Edit } from "#material-ui/icons";
class UserList extends React.Component {
state = {
Collectors: '',
collectorList: []
}
componentDidMount() {
this.getCollectors()
}
getCollectors = () => {
axios.get('http://localhost:5000/getCollectors')
.then((result) => result.data)
.then((result) => {
this.setState({collectorList: result});
});
};
render() {
return (
<div className="userList">
<h3>Collectors</h3>
<table className="blueTableHeaders">
<thead>
<tr>
<th>Active</th>
<td>Collectors</td>
<td>Aging Bucket</td>
<td>Program Code</td>
<td>Finance Company</td>
<td></td>
</tr>
</thead>
</table>
{this.state.collectorList.map((Collectors) => (
<div>
<table className="blueTableData">
<thead>
<tr>
<th><input type="checkbox" name="Active" defaultChecked={Collectors.Active === false ? false : true}/></th>
<td>{Collectors.FirstName} {Collectors.LastName} | {Collectors.CollectorCode}</td>
<td>
<input type="checkbox" />
<input type="checkbox" />
<input type="checkbox" />
<input type="checkbox" />
</td>
<td>
<input type="checkbox" />
<input type="checkbox" />
<input type="checkbox" />
<input type="checkbox" />
</td>
<td>
<input type="checkbox" />
<input type="checkbox" />
<input type="checkbox" />
</td>
<td>
<Link to="/updateUser:CollectorID">
<Edit className="editCollector" />
</Link>
<Link to="/deleteUser:CollectorID">
<DeleteOutline className="deleteCollector"/>
</Link>
</td>
</tr>
</thead>
</table>
</div>
))}
<Link to="/newUser">
<button className="userListAddButton">Add Collector</button>
</Link>
<Link to="/deleteUser">
<button className="userListDeleteButton">Delete Collector</button>
</Link>
</div>
);
}
}
export default UserList;

Cant´t get cookie - Express

I created a server with express and have some get/post routes.
In the login page, I have a page that shows the form to login:
app.get("/login", (req, res) => {
res.send(`<h1>Iniciar sesión</h1>
<form method='post' action='/login'>
<input type='email' name='email' placeholder='Email' required />
<input type='password' name='password' placeholder='Contraseña' required />
<input type='submit' value='Ingresar' />
</form>
<a href='/register'>Registrarse</a`);
});
Then I have a Post method in which I set the cookies:
app.post("/login", (req, res) => {
const { email, password } = req.body;
const user = users.filter(
(e) => e.email === email && e.password === password
);
if (user.length >= 1) {
res.cookie("userId", user.id);
res.cookie("password", user.password);
res.redirect("/home");
} else {
console.log("contraseña incorrecta");
res.redirect("/login");
}
});
The problem is that when I go to this route, the user.name and user.email are undefined. In other words, I can´t acces to the cookie:
app.get("/home", (req, res) => {
const id = req.cookies.userId;
console.log(id); //this is undefined
const user = users.filter((u) => u.id === id);
//console.log(user);
res.send(`
<h1>Bienvenido ${user.name}</h1>
<h4>${user.email}</h4>
<a href='/'>Inicio</a>
`);
});
Advices?
Here is the complete code:
const express = require("express");
const morgan = require("morgan");
const cookieparser = require("cookie-parser");
const bodyparser = require("body-parser");
const app = express();
const users = [
{ id: 1, name: "Franco", email: "Franco#mail.com", password: "1234" },
{ id: 2, name: "Toni", email: "Toni#mail.com", password: "1234" },
];
app.use(morgan("dev"));
app.use(cookieparser());
app.use(bodyparser.urlencoded({ extended: true }));
app.use((req, res, next) => {
console.log(req.cookies);
next();
});
app.get("/", (req, res) => {
res.send(`
<h1>Bienvenidos a Henry!</h1>
${
req.cookies.userId
? `<a href='/home'>Perfil</a>
<form method='post' action='/logout'>
<button>Salir</button>
</form>
`
: `
<a href='/login'>Ingresar</a>
<a href='/register'>Registrarse</a>`
}
`);
});
app.get("/register", (req, res) => {
res.send(`<h1>Registrarse</h1>
<form method='post' action='/register'>
<input name='name' placeholder='Nombre' required />
<input type='email' name='email' placeholder='Email' required />
<input type='password' name='password' placeholder='Contraseña' required />
<input type='submit' value='Registrarse' />
</form>
<a href='/login'>Iniciar sesión</a>`);
});
app.get("/login", (req, res) => {
res.send(`<h1>Iniciar sesión</h1>
<form method='post' action='/login'>
<input type='email' name='email' placeholder='Email' required />
<input type='password' name='password' placeholder='Contraseña' required />
<input type='submit' value='Ingresar' />
</form>
<a href='/register'>Registrarse</a`);
});
app.post("/login", (req, res) => {
const { email, password } = req.body;
const user = users.filter(
(e) => e.email === email && e.password === password
);
if (user.length >= 1) {
res.cookie("userId", user.id);
res.cookie("password", user.password);
res.redirect("/home");
} else {
console.log("contraseña incorrecta");
res.redirect("/login");
}
});
app.get("/home", (req, res) => {
const id = req.cookies;
console.log(id);
const user = users.filter((u) => u.id === id);
//console.log(user);
res.send(`
<h1>Bienvenido ${user.name}</h1>
<h4>${user.email}</h4>
<a href='/'>Inicio</a>
`);
});
app.listen(3000, (err) => {
if (err) {
console.log(err);
} else {
console.log("Listening on localhost:3000");
}
});
Part of your problem is that this code:
const user = users.filter(
(e) => e.email === email && e.password === password
);
produces an Array. So, user is an array.
Therefore when you do this:
res.cookie("userId", user.id);
res.cookie("password", user.password);
Both user.id and user.password are ignoring the match you got in user[0] and are referring to non-existent properties on the user array object. They will end up undefined and thus why res.cookie() is not setting a meaningful value.
You should, instead be doing this:
res.cookie("userId", user[0].id);
res.cookie("password", user[0].password);
But, please don't put a password in a user's cookie. There should be no reason to ever do that. Even more so when it's in plain text. If you want to know if the previous user is logged in or not, then use a cryptographically secure token in the cookie (like something express-session uses). Don't put their password in a cookie.

Vuejs Passing dynamic data from parent to child component

I've got a view and a component. I'm trying to do auth here.
As a user, I input username and password, click login. This emits the information to the parent component, which makes a fetch request to API gateway in AWS. This fetch response has a header X-Session-Id that I'm interested in.
I've got the emit bit working fine.
However, I'm unable to pass the header value back to the component, and I'm unable to set new_password_required to true, which would add a new input field for a new password, as well as replace the login button with a reset password button.
I feel like I need to do this with props, but I'm unable to successfully pass the values from parent to child.
Also, should the reset password bit have its own component?
Here's my code below. This is my first frontend, so I'm not familiar with how I am supposed to share it (e.g. with a playground). Also, I'm trying to stick to vanilla vue for now since I'm learning (I've only get vue-router installed I think)
parent:
<template>
<div id="app" class="small-container">
<login-form #login:user="loginUser($event)" />
</div>
</template>
<script>
import LoginForm from "#/components/LoginForm.vue";
export default {
name: "Login",
components: {
LoginForm
},
data() {
return {
session_id: String,
new_password_required: Boolean
};
},
methods: {
async loginUser(loginEvent) {
try {
const response = await fetch(
process.env.VUE_APP_API_GATEWAY_ENDPOINT + "/login/user",
{
method: "POST",
body: JSON.stringify(loginEvent)
}
);
const data = await response.json();
console.log(data);
if (data.headers["X-Session-Id"] != null) {
this.session_id = data.headers["X-Session-Id"];
this.new_password_required = true;
}
} catch (error) {
console.error(error);
}
},
async resetPassword(resetPasswordEvent) {
try {
const response = await fetch(
process.env.VUE_APP_API_GATEWAY_ENDPOINT + "/reset/user/password",
{
method: "POST",
body: JSON.stringify(resetPasswordEvent)
}
);
const data = await response.json();
console.log(data);
} catch (error) {
console.error(error);
}
}
}
};
</script>
Component:
<template>
<div id="login-form">
<h1>Serverless App</h1>
<form>
<label for="email_address">Email Address:</label><br />
<input
v-model="login_details.email_address"
type="text"
id="email_address"
name="email_address"
/><br />
<label for="password">Password:</label><br />
<input
v-model="login_details.password"
type="password"
id="password"
name="password"
/>
<label v-if="new_password_required" for="new_password"
>New Password:</label
><br />
<input
v-if="new_password_required"
v-model="login_details.new_password"
type="password"
id="new_password"
name="new_password"
/>
</form>
<button v-if="!new_password_required" #click="loginUser($event)">
Login
</button>
<button v-if="new_password_required" #click="resetPassword($event)">
Reset Password
</button>
</div>
</template>
<script>
export default {
name: "LoginForm",
props: {
session_id: String,
new_password_required: {
type: Boolean,
default: () => false
}
},
data() {
return {
login_details: {
email_address: "",
password: "",
new_password: ""
}
};
},
methods: {
loginUser() {
console.log("testing loginUser...");
const loginEvent = {
email_address: this.login_details.email_address,
password: this.login_details.password
};
this.$emit("login:user", loginEvent);
},
resetPassword() {
console.log("testing resetPassword...");
const resetPasswordEvent = {
email_address: this.login_details.email_address,
password: this.login_details.password,
new_password: this.login_details.new_password,
session_id: this.login_details.sessionId
};
this.$emit("reset:Password", resetPasswordEvent);
}
}
};
</script>
Your child component looks good, however, you need to pass the props through in the parent component as shown here:
<login-form #login:user="loginUser($event)" :session-id="xidhere"
:new-password-required="newPasswordRequired"/>
As these values are updated in the parent component, the child component should be updated.
As a note, name your props using camel case, and then use kebab-case in your HTML.
So your login-form props should be updated to:
props: {
sessionId: String,
newPasswordRequired: {
type: Boolean,
default: () => false
}
},
Also, as you are emitting the event to parent, there may be no need to send the session id to the child, just add this to your api call before you send it.
Figured it out. I created a new child component for resetting password. Perhaps it can be dry'd up a bit? I'm new at this. Happy for any pointers :)
PARENT
<template>
<div id="app" class="small-container">
<login-form v-if="!new_password_required" #login:user="loginUser($event)" />
<reset-password-form
v-if="new_password_required"
:session_id="session_id"
#reset:password="resetPassword($event)"
/>
</div>
</template>
<script>
import LoginForm from "#/components/LoginForm.vue";
import ResetPasswordForm from "#/components/ResetPasswordForm.vue";
export default {
name: "Login",
components: {
LoginForm,
ResetPasswordForm
},
data() {
return {
session_id: "",
new_password_required: false
};
},
methods: {
async loginUser(loginEvent) {
try {
const response = await fetch(
process.env.VUE_APP_API_GATEWAY_ENDPOINT + "/login/user",
{
method: "POST",
body: JSON.stringify(loginEvent)
}
);
const data = await response.json();
console.log(data);
if (data.headers["X-Session-Id"] != null) {
this.session_id = data.headers["X-Session-Id"];
this.new_password_required = true;
}
} catch (error) {
console.error(error);
}
},
async resetPassword(resetPasswordEvent) {
try {
const response = await fetch(
process.env.VUE_APP_API_GATEWAY_ENDPOINT + "/reset/user/password",
{
method: "POST",
body: JSON.stringify(resetPasswordEvent)
}
);
const data = await response.json();
console.log(data);
} catch (error) {
console.error(error);
}
}
}
};
</script>
CHILD: login-form
<template>
<div id="login-form">
<h1>Serverless Release Dashboard</h1>
<form>
<label for="email_address">Email Address:</label><br />
<input
v-model="login_details.email_address"
type="text"
id="email_address"
name="email_address"
/><br />
<label for="password">Password:</label><br />
<input
v-model="login_details.password"
type="password"
id="password"
name="password"
/>
</form>
<button #click="loginUser($event)">
Login
</button>
</div>
</template>
<script>
export default {
name: "LoginForm",
data() {
return {
login_details: {
email_address: "",
password: ""
}
};
},
methods: {
loginUser() {
console.log("testing loginUser...");
const loginEvent = {
email_address: this.login_details.email_address,
password: this.login_details.password
};
this.$emit("login:user", loginEvent);
}
}
};
</script>
CHILD: reset-password-form
<template>
<div id="reset-password-form">
<h1>Serverless Release Dashboard</h1>
<form>
<label for="email_address">Email Address:</label><br />
<input
v-model="login_details.email_address"
type="text"
id="email_address"
name="email_address"
/><br />
<label for="password">Password:</label><br />
<input
v-model="login_details.password"
type="password"
id="password"
name="password"
/>
<label for="new_password">New Password:</label><br />
<input
v-model="login_details.new_password"
type="password"
id="new_password"
name="new_password"
/>
</form>
<button #click="resetPassword($event)">
Reset Password
</button>
</div>
</template>
<script>
export default {
name: "ResetPasswordForm",
props: {
email_address: String,
password: String,
session_id: String
},
data() {
return {
login_details: {
email_address: "",
password: "",
new_password: "",
session_id: ""
}
};
},
methods: {
resetPassword() {
console.log("testing resetPassword...");
const loginEvent = {
email_address: this.email_address,
password: this.password,
new_password: this.login_details.new_password,
session_id: this.session_id
};
this.$emit("reset:password", loginEvent);
}
}
};
</script>

React Login form throws error "Cannot set headers after they are sent to the client"

Hi I am making a full stack login form. The error I am receiving is ": Cannot set headers after they are sent to the client" see full log at the bottom.
All i want to do is create a login form that will redirect me to the home page in which I can then start work upon the jwt tokens.
Any idea why this is happening?
Any suggestions on how to get this form fully working?
Thanks for all your help :)
app.post("/auth", function(req, response) {
sql.connect(config, function(err) {
if (err) {
console.log(err + "initial connection");
console.log(config.server);
} else {
try {
var request = new sql.Request();
var body = req.body;
//console.log(body);
var email = body.email;
var password = body.password;
console.log(email, password);
try {
request.input("email", sql.VarChar, email);
request.input("password", sql.VarChar, password);
request.query(
"SELECT * FROM TestLogin WHERE email = 'email' AND password = 'password'",
function(error, results, fields) {
if (results.length > 0) {
req.session.loggedin = true;
req.session.email = email;
response.redirect("/home");
} else {
response.send("Incorrect email and/or Password!");
}
response.end();
}
);
response.send("Please enter email and Password!");
response.end();
} catch (e) {
console.log(e);
response.status(400);
response.send(e);
}
} catch (e) {
console.log(e);
response.status(400);
response.send(e);
}
}
});
});
Login class
class Login extends React.Component {
constructor() {
super();
this.state = { email: "", password: "" };
this.onSubmit = this.handleSubmit.bind(this);
}
handleSubmit(e) {
e.preventDefault();
if (this.state.email.length < 8 || this.state.password.length < 8) {
alert(`please enter the form correctly `);
} else {
const data = { email: this.state.email, password: this.state.password };
fetch("/auth", {
method: "POST", // or 'PUT'
headers: {
Accept: "application/json, text/plain, */*",
"Content-Type": "application/json"
},
body: JSON.stringify(data)
})
.then(response => response.json())
.then(data => {
console.log("Success:", data);
})
.catch(error => {
console.error("Error:", error);
});
}
}
catch(e) {
console.log(e);
}
render() {
console.log(this.state.email);
console.log(this.state.password);
return (
<div>
<Formik
class="form-signin"
action="auth"
method="POST"
initialValues={{ email: "", password: "" }}
onSubmit={(values, { setSubmitting }) => {
setTimeout(() => {
console.log("Logging in", values);
setSubmitting(false);
}, 500);
}}
validationSchema={Yup.object().shape({
email: Yup.string()
.email()
.required("Required")
.matches(
/(?=.*codestone)/,
"This is not a Codestone email address."
),
password: Yup.string()
.required("No password provided.")
.min(8, "Password is too short - should be 8 chars minimum.")
.matches(/(?=.*[0-9])/, "Password must contain a number.")
})}
>
{props => {
const {
values,
touched,
errors,
isSubmitting,
handleChange,
handleBlur,
handleSubmit
} = props;
return (
<form
onSubmit={handleSubmit}
class="form-signin"
action="auth"
method="POST"
>
<div className="jumbotron">
<h2>Login </h2>
<div className="help">
<Popup trigger={<Link> Help?</Link>} className="center">
<div>
Enter Codestone Email address and Password connected to
the account.
</div>
</Popup>
</div>
<label htmlFor="email">Email</label>
<input
name="email"
type="email"
placeholder="Enter your email"
value1={values.email}
value={this.state.email}
onInput={handleChange}
onChange={e => this.setState({ email: e.target.value })}
onBlur={handleBlur}
className={errors.email && touched.email && "error"}
/>
{errors.email && touched.email && (
<div className="input-feedback">{errors.email}</div>
)}
<label htmlFor="email">Password</label>
<input
name="password"
type="password"
placeholder="Enter your password"
value2={values.password}
value={this.state.password}
onInput={handleChange}
onChange={e => this.setState({ password: e.target.value })}
onBlur={handleBlur}
className={errors.password && touched.password && "error"}
/>
{errors.password && touched.password && (
<div className="input-feedback">{errors.password} </div>
)}
<button class="button" type="submit" onClick={this.onSubmit}>
Login
</button>
<p>
<Link to="/login"> Login Page </Link>
</p>
<p>
<Link to="/reset"> Reset Password </Link>
</p>
</div>
</form>
);
}}
</Formik>
</div>
);
}
}
Error
undefined undefined
[0] _http_outgoing.js:535
[0] throw new ERR_HTTP_HEADERS_SENT('set');
[0] ^
[0]
[0] Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
[0] at ServerResponse.setHeader (_http_outgoing.js:535:11)
[0] at ServerResponse.header (C:\Users\Henry Peters\Desktop\Vault\Newfolder(3)\Codestone-Desk-branch1\node_modules\express\lib\response.js:771:10)
at ServerResponse.send (C:\Users\Henry Peters\Desktop\Vault\Newfolder(3)\Codestone-Desk-branch1\node_modules\express\lib\response.js:170:12)
[0] at C:\Users\Henry Peters\Desktop\Vault\Newfolder(3)\Codestone-Desk-branch1\server.js:183:26
[0] at C:\Users\Henry Peters\Desktop\Vault\Newfolder(3)\Codestone-Desk-branch1\node_modules\mssql\lib\base\request.js:395:9
[0] at Request.userCallback (C:\Users\Henry Peters\Desktop\Vault\Newfolder(3)\Codestone-Desk-branch1\node_modules\mssql\lib\tedious\request.js:471:15)
[0] at Request.callback (C:\Users\Henry Peters\Desktop\Vault\Newfolder(3)\Codestone-Desk-branch1\node_modules\tedious\lib\request.js:56:14)
[0] at Connection.endOfMessageMarkerReceived (C:\Users\Henry Peters\Desktop\Vault\Newfolder(3)\Codestone-Desk-branch1\node_modules\tedious\lib\connection.js:2402:20)
[0] at Connection.dispatchEvent (C:\Users\Henry Peters\Desktop\Vault\Newfolder(3)\Codestone-Desk-branch1\node_modules\tedious\lib\connection.js:1274:15)
[0] at Parser.<anonymous> (C:\Users\Henry Peters\Desktop\Vault\Newfolder(3)\Codestone-Desk-branch1\node_modules\tedious\lib\connection.js:1067:14) {
[0] code: 'ERR_HTTP_HEADERS_SENT'
Update after suggested changes. This still does not redirect user to the hpome page or even show any signs of logging in in user. No errors are displayed in console or withing chrome dev tools. Please advise if you can
app.post("/auth", function(req, response) {
sql.connect(config, function(err) {
if (err) {
console.log(err + "initial connection");
console.log(config.server);
} else {
try {
var request = new sql.Request();
var body = req.body;
//console.log(body);
var Email = body.email;
var Password = body.password;
//console.log(email, password);
try {
request.input("email", sql.VarChar, Email);
request.input("password", sql.VarChar, Password);
request.query(
"SELECT * FROM TestLogin WHERE email = Email AND password = Password",
function(error, results, fields) {
if (results.length > 0) {
req.session.loggedin = true;
req.session.email = email;
response.redirect("/home");
} else if (results.length < 0) {
response.send("Incorrect email and/or Password!");
}
}
);
// response.send("Please enter email and Password!");
// response.end();
} catch (e) {
console.log(e);
response.status(400);
response.send(e);
}
} catch (e) {
console.log(e);
response.status(400);
response.send(e);
}
}
});
});
try {
request.input("email", sql.VarChar, email);
request.input("password", sql.VarChar, password);
request.query(
"SELECT * FROM TestLogin WHERE email = 'email' AND password =
'password'",
function(error, results, fields) {
if (results.length > 0) {
req.session.loggedin = true;
req.session.email = email;
response.redirect("/home");
} else {
response.send("Incorrect email and/or Password!");
}
response.end();
}
);
//response.send("Please enter email and Password!");
//response.end();
The response ends response.send("Please enter email and Password!");response.end();, thus the handler once resolved gives that error.

Formatting authentication request object from VueJS properly

I have a VueJS/Vuex frontend consuming an express/postgres api.
In Postman, both registration and login work with a request like:
{ "user": { "email": "user#gmail", "password":...}}
From the Vue app, registration works as expected, but for login, instead of sending a request object like
{ "user": { "email": "user#gmail", "password":...}}
, which is what the api is expecting, it is sending only,
{ "email": "user#gmail", "password":...}
This results in the api throwing:
TypeError: Cannot read property 'email' of undefined
Here is my Login component:
<template>
<div class="ui stackable three column centered grid container">
<div class="column">
<h2 class="ui dividing header">Log In</h2>
<Notification
:message="notification.message"
:type="notification.type"
v-if="notification.message"
/>
<form class="ui form" #submit.prevent="login">
<div class="field">
<label>Email</label>
<input type="email" name="email" v-model="email" placeholder="Email" required>
</div>
<div class="field">
<label>Password</label>
<input type="password" name="password" v-model="password" placeholder="Password" required>
</div>
<button class="fluid ui primary button">LOG IN</button>
<div class="ui hidden divider"></div>
</form>
<div class="ui divider"></div>
<div class="ui column grid">
<div class="center aligned column">
<p>
Don't have an account? <router-link to="/signup">Sign Up</router-link>
</p>
</div>
</div>
</div>
</div>
</template>
<script>
import Notification from '#/components/Notification'
export default {
name: 'LogIn',
components: {
Notification
},
data () {
return {
email: '',
password: '',
notification: {
message: '',
type: ''
}
}
},
// beforeRouteEnter (to, from, next) {
// const token = localStorage.getItem('tweetr-token')
// return token ? next('/') : next()
// },
methods: {
login () {
this.$store
.dispatch('login', {
email: this.email,
password: this.password
})
.then(() => {
console.log(this.$store.user)
// redirect to user home
this.$router.push('/')
})
.catch(error => console.log(error))
}
}
}
</script>
And this is my store.js:
import Vue from 'vue'
import Vuex from 'vuex'
import axios from 'axios'
// import SubscriptionsService from './services/SubscriptionsService'
Vue.use(Vuex)
const VUE_APP_ROOT_API = 'http://localhost:8000'
export default new Vuex.Store({
state: {
status: '',
user: JSON.parse(localStorage.getItem('user'))
},
mutations: {
auth_request (state) {
state.status = 'Signing in...'
},
set_user (state, user) {
state.user = user
localStorage.setItem('user', JSON.stringify(user))
console.log(user)
},
auth_success (state) {
state.status = 'success'
},
auth_error (state) {
state.status = 'Invalid credentials'
},
logout (state) {
state.status = ''
state.user = null
localStorage.removeItem('user')
}
},
actions: {
register ({ commit }, user) {
return new Promise((resolve, reject) => {
commit('auth_request')
console.log(process.env.VUE_APP_ROOT_API)
axios({ url: VUE_APP_ROOT_API + '/api/auth', data: user, method: 'POST' })
.then(async resp => {
const user = resp.data.user
commit('auth_success')
commit('set_user', user)
resolve(resp)
})
.catch(err => {
commit('auth_error', err)
localStorage.removeItem('token')
reject(err)
})
})
},
login ({ commit }, user) {
return new Promise((resolve, reject) => {
commit('auth_request')
console.log(user);
axios({ url: VUE_APP_ROOT_API + '/api/auth/login', data: user, method: 'POST' })
.then(resp => {
const user = resp.data.user
// console.log(user)
// console.log(resp)
commit('auth_success')
commit('set_user', user)
resolve(resp)
})
.catch(err => {
commit('auth_error')
commit('logout')
reject(err)
})
})
},
logout ({ commit }) {
return new Promise((resolve) => {
commit('logout')
localStorage.removeItem('token')
delete axios.defaults.headers.common['authorization']
resolve()
})
}
},
getters: {
isAuthenticated: state => !!state.user,
authStatus: state => state.status,
user: state => state.user
}
})
for comparison, here is my working SignUp component:
<template>
<div class="ui stackable three column centered grid container">
<div class="column">
<h2 class="ui dividing header">Sign Up, it's free!</h2>
<form class="ui form" #submit.prevent="signup">
<div class="field">
<label>Username</label>
<input type="username" name="username" v-model="username" placeholder="Username">
</div>
<div class="field">
<label>Email</label>
<input type="email" name="email" v-model="email" placeholder="Email">
</div>
<div class="field" >
<label>Password</label>
<input type="password" name="password" v-model="password" placeholder="Password">
</div>
<button class="fluid ui primary button">SIGN UP</button>
<div class="ui hidden divider"></div>
</form>
<div class="ui divider"></div>
<div class="ui column grid">
<div class="center aligned column">
<p>
Got an account? <router-link to="/login">Log In</router-link>
</p>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'SignUp',
data () {
return {
email: '',
password: '',
username: '',
notification: {
message: '',
type: ''
}
}
},
methods: {
signup: function () {
let data = {
user: {
email: this.email,
password: this.password,
username: this.username
}
}
this.$store.dispatch('register', data)
.then(() => this.$router.push('/'))
.catch(err => console.log(err))
},
}
}
</script>
How do I format the request object to match what the api expects?
Try sending the payload in a similar structure you have for your sign up function:
.dispatch('login', {
user: {
email: this.email,
password: this.password
}
})