req.body is undefined after post request - javascript

I'm building a contact form using nodemailer.
To post it I'm using the fetch API.
But for some reason, I get req.body as undefined.
Here's the frontend code:
form.onsubmit = function (e) {
// Stop the regular form submission
e.preventDefault();
const name = document.querySelector("form#contactForm #name").value;
const email = document.querySelector("form#contactForm #email").value;
const textarea = document.querySelector("form#contactForm #textarea").value;
// Collect the form data while iterating over the inputs
var data = {};
data = { name, email, textarea };
console.log(data);
fetch("/mail", {
method: "POST", // or 'PUT'
headers: { "Content-Type": "application/json" },
body: JSON.stringify(data),
})
.then(async (response) => {
if (response.ok) {
return response.json();
} else {
const resJson = await response.json();
console.log(resJson);
if (typeof resJson.errors === "undefined") {
formStatus.className += " alert-danger";
formStatus.innerText =
"An error occured, Please refresh the page. Or email us at ravchesed#kehilasbelz.be";
return;
}
let ul = document.createElement("ul");
resJson.errors.forEach((err) => {
const li = document.createElement("li");
li.innerText = `${err.msg}: ${err.param} `;
ul.append(li);
console.log(`${err.msg}: ${err.param} `);
});
formStatus.className += " alert-danger";
formStatus.innerText = "";
formStatus.append(ul);
throw response;
}
})
.then((data) => {
console.log("Success:", data);
})
.catch((error) => {
console.error("Error:", error);
});
};
Here's the backend:
const express = require("express");
const app = express();
const bodyParser = require("body-parser");
const { check, validationResult } = require("express-validator");
const rateLimit = require("express-rate-limit");
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 10, // limit each IP to 100 requests per windowMs
});
//Here we are configuring express to use body-parser as middle-ware.
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
const mail = express.Router();
// app.post("/mail", (req, res) => {
// console.log(req.body);
// const result = {
// hellop: 5
// };
// res.send(JSON.stringify(result));
// });
mail.post(
"/mail",
// limiter,
[
// username must be an email
check("email").trim().isEmail(),
check("textarea").trim().isLength({ max: 6000 }),
check("name").trim().isLength({ min: 2, max: 20 }),
],
(req, res) => {
console.log(req.body); //undefined
// Finds the validation errors in this request and wraps them in an object with handy functions
const errors = validationResult(req);
if (!errors.isEmpty()) {
console.log(errors); //this returns empty values.
return res.status(422).json({ errors: errors.array() });
}
const mailInfo = {
name: req.body.name,
email: req.body.email,
message: req.body.testarea,
};
main(mailInfo).catch(console.error);
res.json({ success: true });
}
);
const nodemailer = require("nodemailer");
// async..await is not allowed in the global scope, must use a wrapper
async function main(data) {
// create reusable transporter object using the default SMTP transport
let transporter = nodemailer.createTransport({
host: "xxx.xxx.com",
port: 587,
secure: false, // true for 465, false for other ports
auth: {
user: "email#example.com", // generated ethereal user
pass: "abc123456", // generated ethereal password
},
});
// send mail with defined transport object
let info = await transporter.sendMail(
{
from: '"John Doe 👍" <robot#Doe.dev>', // sender address
to: "Doe#gmail.com", // list of receivers
subject: `📧 Mail from ${data.name}`, // Subject line
html: `
<b>${data.name}, ${data.email}</b><br>
Phone: ${data.phone}<br>
<br>
Message:
<br>
${data.message}
`, // html body
},
function (err, info) {
if (err) console.log(err);
else console.log(info);
console.log("Message sent: %s", info);
}
);
}
module.exports = mail;
Looked at a lot of posts, but this seems to be a different problem.

after looking at everything again I know where my mistake was but don't understand why.
My file structure is like this:
app.js
mail.js
mail.js was imported to app.js like this:
//handle mail
const mail = require("./mail");
app.use(mail);
in app.js I didn't import body-parser and the middleware because it was already imported in mail.js.
but looks like for some reason that I also have to import it in app.js before mail.js.

Related

How do I send form data from frontend to backend so when user is at login they can login

I'm very new to backend development and I'm trying to figure out how to send my form data from front to backend. I watched a youtube tutorial on how and this is my code for server.js:
const express = require("express");
const app = express();
const port = 2009;
app.use(express.static("public"));
app.use(express.json());
app.get("/", (req, res) => {
res.status(200).json({info: "something"});
});
app.post("/", (req, res) => {
const { parcel } = req.body;
if (!parcel) {
return res.status(400).send({status: "failed"});
}
res.status(200).send({status: "recieved"});
});
app.listen(port, () => console.log(`server.js running on port: ${port}`));
And here is the code for script.js for my form:
const submit = document.getElementById("submit");
const userName = document.getElementById("user");
const password = document.getElementById("pass");
const email = document.getElementById("mail");
const baseUrl = "http://localhost:2009/"
async function post(e) {
e.preventDefault();
const res = await fetch(baseUrl + "website?key=hello", {
method: "POST"
})
}
Like I said I basically have no clue what I am doing could someone help me?
I haven't tested it yet because I'm afraid it won't work if would be very helpful if someone could show me some code or point me to some documentation so that I can work in the right direction.
you seem to be on the right track just a few changes and additions.
const registerForm = document.getElementById('register_form');
async function post(e) {
const form = document.forms.register_form;
const email = form.email.value;
const password = form.password.value;
const username = form.username.value;
try {
const res = await fetch(baseUrl + "website?key=hello", {
method: "POST",
body: JSON.stringify({
email,
username,
password,
}),
headers: { "Content-Type": "application/json" },
});
// handle the response here
} catch (error) {
// handle error here
}
}
registerForm.addEventListener('submit', post, false);
on the backend, you will need a route to handle this request
app.post("/", (req, res) => {
const { username, email, password } = req.body;
// validate the data from the request
if (!username || !email || !password) {
return res.status(400).send({
status: "failed",
message: "fields are required"
});
}
res.status(201).send({status: "recieved"});
});
StatusCode 201 indicates a new resource has been created
References:Using Fetch Api statusCode
I hope this helps.

Javascript Fetching failing for no reason

I'm trying to make a login form where it fetches from another website, although, it keeps erroring with Error: Failed to Fetch
I don't really notice anything wrong with the code, but maybe its something related to CORS
Here is my code (HTML, CSS, JavaScript)
// Values: UsernameVal is being tested as "Developer"
// PasswordVal is being tested as "AccessTest"
if (User.value != "") {
if (Password.value != "") {
setFormMessage(loginForm, "info", "Checking account credentials..") // Set form message is just a basic function to set a login status message
var UsernameVal = User.value
var PasswordVal = Password.value
function a(data) {
console.log(data)
if (data.success == true) {
setFormMessage(loginForm, "success", "Logging in..")
} else {
setFormMessage(loginForm, "error", "Invalid username or password")
}
}
try {
console.log(`https://mysite.repl.co/check?username=${UsernameVal}&password=${PasswordVal}/`)
fetch(`https://mysite.repl.co/check?username=${UsernameVal}&password=${PasswordVal}/`, {
method: 'GET',
headers: {
accept: 'application/json',
},
})
.then(data => {
a(data)
}).catch((error) => {
throw new Error(error)
})
} catch (e) {
throw new Error(`Error setting login form message: ${e}`)
}
} else {
setFormMessage(loginForm, "error", "No password input provided")
}
} else {
setFormMessage(loginForm, "error", "No username input provided")
}
});
This is the code on the other side (nodejs)
const express = require('express');
const app = express();
const router = express.Router();
const bodyParser = require("body-parser")
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
const fs = require('fs')
app.post('/user', function(req,res) {
res.set("Access-Control-Allow-Origin", "OriginForGettingData")
const username = req.body.username
const password = req.body.password
res.send(`Added to login (${username}: ${password}}) list`)
const table = require('./values.json').Logins;
table[username] = password;
const fileName = './values.json';
const file = require(fileName);
file.Logins = table;
fs.writeFile(fileName, JSON.stringify(file)).done(function writeJSON(err) {
if (err) return console.log(err);
});
console.log(`Post recieved from ${insert}. New table: ${table}`)
})
app.get('/check', function(req,res){
res.set("Access-Control-Allow-Origin", "OriginForGettingData")
const username = req.param("username")
const password = req.param("password")
const table = require('./values.json').Logins;
res.json({"success": table[username] === password})
})
app.listen(3000, () => {
console.log('server started');
});
/user and /check work fine, its just the fetching that fails
After modifying the CORS for Access-Control-Allow-Origin from OriginForGettingData to *, it allowed the request to go through

Rest API, take request fields. handle

I stood in a stupor. And I need help.
I do rest full api on express
I want to do this if a request comes in type: reset_password -> I sent an email to reset my password.(it can be both registration and auth)
But I don't know how to pass it into a query. And that is, how to do it.
I trimmed the code.
const send = async (req, res) => {
const key = req.query.apiKey;
const type = req.query.type;
const to = req.query.to;
if (err) {
console.log(err);
} else if (rows.length == 0) {
res.status(401).json({"apiKey":"error"})
} else {
if (email.validate(to)) {
sendmail(type, to)
} else {
res.status(422)
}
}
}
sendmail:
const nodemailer = require("nodemailer");
const ejs = require('ejs')
const path = require('path')
const sendmail = async (type, to, url) => {
try {
const reset_password = path.join(__dirname, "../template/resetpassword.ejs")
const signup_auth = path.join(__dirname, "../template/signupauth.ejs")
const sign_in_auth = path.join(__dirname, "../template/signinauth.ejs")
const data = await ejs.renderFile(reset_password,signup_auth,sign_in_auth, { to, url } )
let testAccount = await nodemailer.createTestAccount();
// create reusable transporter object using the default SMTP transport
let transporter = nodemailer.createTransport({
host: "smtp.ethereal.email",
port: 587,
secure: false, // true for 465, false for other ports
auth: {
user: testAccount.user, // generated ethereal user
pass: testAccount.pass, // generated ethereal password
},
});
const send = await transporter.sendMail({
from: 'dev#test.io',
to: to,
text: "Hello world?",
subject: "test",
html: ???
})
console.log("Success send: %s", nodemailer.getTestMessageUrl(send));
}catch (err) {
console.log('Error send: ' + err.message);
}
}
module.exports = sendmail;
Now I have a question. How do I send a request: reset_password,signup_auth,sign_in_auth
That is, how do I pass it on to the type: reset_password,signup_auth,sign_in_auth
http://localhost:3000/api?apiKey=key&type=reset_password,signup_auth,sign_in_auth
How do I take it and process it?
I need to accept type=auth signup reset to api rest
I'm sorry, maybe I didn't make my point correctly.

Test a POST Http request from a local node server in REACT

I need to make unit tests for some post requests but i dont understand how.I tried with mswjs but the test passes because i'm missing something and i dont know what.I tried to test the requests in an usual way but i wasnt able to put my conditions there and it was sending only 200 status code..
To start with,this is my folder structure:
+main folder
++nodeServer
+++public
+++routes
++public
++src
+++tests
This is my try for testing the post request to /subscribe endpoint,where i should send an email as a payload and get the response that the payload was received succesefully.
subscribeFetch.test.js:
import {setupServer} from 'msw/node'
import {rest} from 'msw'
const handlers = [
rest.post("/api/subscribe",(req,res,context)=>{
if (!req.body || !req.body.email) {
return res(context.status(400).json({ error: "Wrong payload" }));
}
if (req.body.email === 'forbidden#email.com') {
return res(context.status(422).json({ error: "Email is already in use" }));
}
return res(
context.status(200),
context.json({email:'gigi#gmail.com'})
)
})
]
const server = setupServer(...handlers)
beforeAll(()=>server.listen())
afterAll(()=>server.close())
afterEach(()=>server.resetHandlers())
test('should send post request to the server',async()=>{
server.use(
rest.post('/api/subscribe',(req,res,ctx)=>{
return res(
expect (ctx.status()).toBe(200)
)
}
)
)
})
//export {handlers,rest}
This is the subscribe post request function that i need to test:
import { validateEmail } from './email-validator.js'
export const sendSubscribe = (emailInput) => {
const isValidEmail = validateEmail(emailInput)
if (isValidEmail === true) {
sendData(emailInput)
}
}
export const sendHttpRequest = (method, url, data) => {
return fetch(url, {
method: method,
body: JSON.stringify(data),
headers: data
? {
'Content-Type': 'application/json'
}
: {}
}).then(response => {
if (response.status >= 400) {
return response.json().then(errResData => {
const error = new Error('Something went wrong!')
error.data = errResData
throw error
})
}
return response.json()
})
}
const sendData = (emailInput) => {
sendHttpRequest('POST', '/api/subscribe', {
email: emailInput
}).then(responseData => {
return responseData
}).catch(err => {
console.log(err, err.data)
window.alert(err.data.error)
})
}
Files from the server:
app.js:
const express = require('express');
const path = require('path');
const cookieParser = require('cookie-parser');
const logger = require('morgan');
const indexRouter = require('./routes/index');
const communityRouter = require('./routes/community');
const analyticsRouter = require('./routes/analytics');
const app = express();
global.appRoot = path.resolve(__dirname);
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', indexRouter);
app.use('/community', communityRouter);
app.use('/analytics', analyticsRouter);
module.exports = app;
index.js from routes folder in the server folder:
const express = require('express');
const router = express.Router();
const FileStorage = require('../services/FileStorage');
/* POST /subscribe */
router.post('/subscribe', async function (req, res) {
try {
if (!req.body || !req.body.email) {
return res.status(400).json({ error: "Wrong payload" });
}
if (req.body.email === 'forbidden#email.com') {
return res.status(422).json({ error: "Email is already in use" });
}
const data = {email: req.body.email};
await FileStorage.writeFile('user.json', data);
await res.json({success: true})
} catch (e) {
console.log(e);
res.status(500).send('Internal error');
}
});
/* GET /unsubscribe */
router.post('/unsubscribe', async function (req, res) {
try {
await FileStorage.deleteFile('user.json');
await FileStorage.writeFile('user-analytics.json', []);
await FileStorage.writeFile('performance-analytics.json', []);
await res.json({success: true})
} catch (e) {
console.log(e);
res.status(500).send('Internal error');
}
});
module.exports = router;
Please guys,help me write unit test for subscribe endpoint to match the conditions from index.js file from routes folder in the server folder,thank you in advance!
So,i got the expected result without any library,but i dont know if its a good aproach,but at least it works :
const app = require('../../../personal-website-server/app')
const request = require('supertest')
describe('POST /subscribe', () => {
it('should give 400 status code when email is empty', async () => {
const email = { email: '' }
const response = await request(app).post('/subscribe').send(email)
if (!request.body || !request.body.email) {
expect(response.status).toBe(400)
}
})
it('should give 422 status code when email is forbidden', async () => {
const email = { email: 'forbidden#gmail.com' }
const response = await request(app).post('/subscribe').send(email)
if (request.body === 'forbidden#gmail.com') {
expect(response.status).toBe(422)
}
})
it('should give 200 status code when email is valid', async () => {
const email = { email: 'gigi#gmail.com' }
const response = await request(app).post('/subscribe').send(email)
expect(response.error).toBe(false)
expect(response.status).toBe(200)
expect(response.body.body).not.toBeNull()
})
})

Passport authentication is causing an issue with access to API call

Trying to create a login authentication system as an entry into web development but the fetch I have to access my login functionality doesn't work. Morgan shows "POST -- ms --". (Works through Postman). As far as I can see my cors system is set up as expected. The API will respond if the passport.authenticate('local') is removed.
authenticate.js
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
var User = require('./models/user');
var JwtStrategy = require('passport-jwt').Strategy;
var ExtractJwt = require('passport-jwt').ExtractJwt;
var jwt = require('jsonwebtoken'); // used to create, sign, and verify tokens
var config = require('./config.js');
exports.local = passport.use(new LocalStrategy(User.authenticate()));
passport.serializeUser(User.serializeUser());
passport.deserializeUser(User.deserializeUser());
exports.getToken = function(user) {
return jwt.sign(user, config.secretKey,
{expiresIn: 3600});
};
var opts = {};
opts.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken();
opts.secretOrKey = config.secretKey;
exports.jwtPassport = passport.use(new JwtStrategy(opts,
(jwt_payload, done) => {
console.log("JWT payload: ", jwt_payload);
User.findOne({_id: jwt_payload._id}, (err, user) => {
if (err) {
return done(err, false);
}
else if (user) {
return done(null, user);
}
else {
return done(null, false);
}
});
}));
routes
var express = require('express');
var UserRouter = express.Router();
var passport = require('passport');
var User = require('../models/user')
var authenticate = require('../authenticate');
const cors = require('./cors');
const bodyParser = require('body-parser');
UserRouter.use(bodyParser.json());
UserRouter.route('/login')
.options(cors.corsWithOptions, (req, res) => { res.sendStatus(200); })
.post(cors.cors, passport.authenticate('local'), (req, res) => {
console.log(req.body);
var token = authenticate.getToken({_id: req.user._id});
res.setHeader('Content-Type', 'application/json');
res.json({success: true, token: token, status: 'You are successfully logged in!'});
res.status(200).send()
});
module.exports = UserRouter;
mongoose schema file
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var passportLocalMongoose = require('passport-local-mongoose');
var User = new Schema ({
firstname : {
type: String,
default: ""
},
lastname: {
type: String,
default: ''
},
admin: {
type: Boolean,
default: false
}
});
User.plugin(passportLocalMongoose);
module.exports = mongoose.model('User', User);
cors file
const express = require('express');
const cors = require('cors');
var whitelist = ['http://localhost:3000', 'http://localhost:3443']
var corsOptionsDelegate = (req, callback) => {
var corsOptions;
console.log("Validating origin");
console.log(req.header('Origin'));
if(whitelist.indexOf(req.header('Origin')) !== -1) {
corsOptions = { origin: true };
}
else {
corsOptions = { origin: false };
}
callback(null, corsOptions);
};
exports.cors = cors();
exports.corsWithOptions = cors(corsOptionsDelegate);
Front end API call
export const loginUser = (creds) => (dispatch) => {
console.log("test")
dispatch(requestLogin(creds))
console.log("attempting login")
return fetch('http://localhost:3443/users/login', {
method: 'POST',
headers: {
'Content-Type':'application/json',
},
body: JSON.stringify(creds)
})
.then(response => {
console.log("got response 1");
if(response.ok) {
return response
} else {
console.log("response errored");
var error = new Error('Error ' + response.status + ': ' + response.statusText);
error.response = response;
throw error;
}
},
error => {
console.log("errored")
throw error;
})
.then(response => response.json())
.then(response => {
console.log("got response 2");
if(response.success) {
// Successful login
localStorage.setItem('token', response.token);
localStorage.setItem('creds', JSON.stringify(creds));
// TODO dispatch success
dispatch(receiveLogin(response));
} else {
var error = new Error('Error ' + response.status);
error.response = response;
throw error;
}
})
.catch(error => dispatch(loginError(error.message)))
}
Does anyone know where I'm going wrong with this? I'm not really getting any useful error messages from my front-end so haven't included.
Terminal output upon login attempt
OPTIONS /users/login 204 3.287 ms - 0
POST /users/login - - ms - -

Categories