how do i call controller from a click button?
i tried into postman it works well.. but i cannot call it into button on my front-end.
i am using nodemailer and node express to send email..
here's my code..
is this correct? - thanks in advance.
i am figuring out if my code is in correct or not.
mailController.js
// mail controller routes
var express = require('express');
var router = express.Router();
var nodemailer = require('nodemailer');
// get /api/mail/
router.get('/send-email', (req,res) => {
res.send('GET response');
});
// post /api/mail/
router.route('/send-email').post((req,res) => {
let transporter = nodemailer.createTransport({
service: 'gmail',
auth: {
type: 'OAuth2',
user: 'dev.xxx#gmail.com',
clientId: 'xxx-xxx.apps.googleusercontent.com',
clientSecret: 'SY0-xxxx',
refreshToken: '1/xxx',
accessToken: 'ya29.xxx-xxx-xxx-xxx'
}
})
let mailOptions = {
from: 'FReyes <dev.xxx#gmail.com>',
to: 'xxx#gmail.com',
subject: 'Nodemailer test',
text: 'Hello World!!'
}
transporter.sendMail(mailOptions, function (err, res) {
if(err){
console.log('Error');
} else {
console.log('Email Sent');
}
})
});
// put /api/mail/
router.put('/send-email',(req,res) => {
res.send('PUT response');
});
// delete /api/mail/
router.delete('/send-email',(req,res) => {
res.send('DELETE response');
});
module.exports = router;
server.js
var express = require('express');
var bodyParser = require('body-parser');
var nodemailer = require('nodemailer');
var app = express(); // Please do not remove this line, since CLI uses this line as guidance to import new controllers
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.use(function(req, res, next) {
// console.log(req);
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Credentials', 'true');
res.setHeader('Access-Control-Allow-Methods', 'GET,HEAD,OPTIONS,POST,PUT,DELETE');
res.setHeader('Access-Control-Allow-Headers', 'Access-Control-Allow-Headers, Origin,Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers');
//and remove cacheing so we get the most recent comments
res.setHeader('Cache-Control', 'no-cache');
next();
});
var mailController = require('./controllers/mailController');
app.use('/api/mail', mailController);
app.listen(process.env.PORT || 5015, () => {
console.log('Server is running');
});
contact.component.ts
sendMail() {
const data = {
to: 'xxx#gmail.com',
subject: 'Subject',
txt: 'hello world'
};
console.log('asd');
return this.http.post('localhost:5015/api/mail/send-email', data).map((response: Response) =>{
console.log (response.json());
});
}
html
<input type="button" value="test" (click)="sendMail(data)">
don't forget to add protocol name and return value in the map function
sendMail() {
const data = {
to: 'xxx#gmail.com',
subject: 'Subject',
txt: 'hello world'
};
console.log('asd');
return this.http.post('http://localhost:5015/api/mail/send-email', data).subscribe(data => console.log(data));
}
Related
I created simple react + express app for fetching data from Strava.
Authorization is done by passport.js and there aren't any problems when I run it locally (on separate ports client/server: 3000/8080 or using only server to provide production build) although when deployed the app on render.com I'm getting 401 unauthorised when making calls to my API.
I have two environments:
(client) static site for react app: https://statz.onrender.com
(server) web service for my express API: https://statz-api.onrender.com
For instance - to get logged athlete data client makes request to the server and then server is requesting that data from Strava API and returns the data to the client.
For now I have only two endpoints and both throw error 401 when called from client side.
Authentication is done server side and at the end the user is redirected back to the client. After all every request from client to API throws 401 but when calling endpoint directly from the browser eg: (https://statz-api.onrender.com/api/athlete) I'm getting complete data. Demo: https://share.getcloudapp.com/NQu4J7YL
Probably it's worth to mention there is no cookie in the request headers when calling from client.
I had some CORS errors first but probably I sorted them out since there is nothing about it on the console.
I would be grateful if somebody could look at this and show me what I'm still missing in my configs.
Link to github: https://github.com/PatrykJamroz/StravaStats/tree/deploy-1
server:
const express = require("express");
const passport = require("passport");
const cors = require("cors");
const logger = require("morgan");
const StravaStrategy = require("passport-strava-oauth2").Strategy;
const cookieParser = require("cookie-parser");
const bodyParser = require("body-parser");
const cookieSession = require("cookie-session");
const app = express();
app.use(
cors({
credentials: true,
origin: "https://statz.onrender.com",
exposedHeaders: ["Set-Cookie"],
})
);
app.use(function (req, res, next) {
res.header("Access-Control-Allow-Credentials", true);
res.header(
"Access-Control-Allow-Headers",
"Origin, X-Requested-With, Content-Type, Accept"
);
next();
});
require("dotenv").config();
const fetch = (...args) =>
import("node-fetch").then(({ default: _fetch }) => _fetch(...args));
const STRAVA_CLIENT_ID = process.env.STRAVA_CLIENT_ID;
const STRAVA_CLIENT_SECRET = process.env.STRAVA_CLIENT_SECRET;
passport.serializeUser(function (user, done) {
done(null, user);
});
passport.deserializeUser(function (obj, done) {
done(null, obj);
});
passport.use(
new StravaStrategy(
{
clientID: STRAVA_CLIENT_ID,
clientSecret: STRAVA_CLIENT_SECRET,
callbackURL: "/auth/strava/callback",
},
function (accessToken, refreshToken, profile, done) {
process.nextTick(function () {
return done(null, profile);
});
}
)
);
app.use(logger("combined"));
app.use(cookieParser());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(express.methodOverride());
app.use(cookieSession({ secret: "keyboard cat" }));
app.use(passport.initialize());
app.use(passport.session());
app.use(app.router);
const SCOPES = "read,activity:read_all,read_all";
app.get(
"/auth/strava",
passport.authenticate("strava", { scope: SCOPES }),
function (req, res) {
// The request will be redirected to Strava for authentication, so this
// function will not be called.
}
);
app.get(
"/auth/strava/callback",
passport.authenticate("strava", {
scope: SCOPES,
failureRedirect: "/login",
}),
function (req, res) {
res.redirect("https://statz.onrender.com");
}
);
app.get("/api/athlete", async (req, res) => {
fetch(
`https://www.strava.com/api/v3/athlete?access_token=${
req.user?.token ?? ""
}`
)
.then((response) => {
if (response.ok) {
return response.json();
}
res.status(response.status).json({ error: response.statusText });
throw new Error(`${response.status} - ${response.statusText}`);
})
.then((data) => res.json(data))
.catch((error) => console.error({ error }));
});
app.get("/api/activities", async function (req, res) {
if (!req.user) {
res.json({ error: "Not authenticated" });
}
let page = 1;
let activities = [];
while (true) {
const activitiesPromise = await fetch(
`https://www.strava.com/api/v3/athlete/activities?per_page=30&page=${page}&access_token=${req.user.token}`
);
const activitiesData = await activitiesPromise.json();
page += 1;
activities = [...activities, ...activitiesData];
logger({ page });
if (activitiesData.length < 30) {
return res.json(activities);
}
}
});
app.get("/api/ping", function (req, res) {
res.send("pong");
});
const listener = app.listen(process.env.PORT || 8080, () => {
console.log(`Your app is listening on port ${listener.address().port}`);
});
Client API calls:
import axios from 'axios';
import { Activity, Athlete } from '../models/Strava';
const BASE_URL = 'https://statz-api.onrender.com';
export const getAthlete = async (): Promise<Athlete> => {
return axios.get(`${BASE_URL}/api/athlete`, { withCredentials: true }).then(({ data }) => data);
};
export const getActivities = async (): Promise<Activity[]> => {
return axios
.get(`${BASE_URL}/api/activities`, { withCredentials: true })
.then(({ data }) => data);
};
Authorization component:
export function Authorization() {
const login = () => {
window.open('https://statz-api.onrender.com/auth/strava', '_self');
};
return (
<Button onClick={login} variant="outlined">
<img alt="authorize" src="/btn_strava_auth.png" />
</Button>
);
}
I have a Node.js/Express REST API I have made to be accessed by a front end React app for an inventory management system to use for a garage sale. When trying to add a new Product, I try to access the POST route http://localhost:3001/api/new. However, when I try to access it, it retures a 404 Not Found error, despite being confident that I've done what has to be done for the route to be seen to the server, in order for the client to be able to fetch it. Could anyone shed some light on what I might be missing if anyting?
Accessing the endpoint from the client:
const addNewItemHandler = async () => {
setIsLoading(true);
const REQUEST_BASE_URL = "http://localhost:3001";
const REQUEST_ROUTE = "/api/new";
const REQUEST_URL = `${REQUEST_BASE_URL}${REQUEST_ROUTE}`;
const REQUEST_CONFIG = {
method: "POST",
body: JSON.stringify({
"productID": productID,
"name": productName,
"quantity": quantity,
"price": parseFloat(`${priceDollar}.${priceCents.split("")[0]}${priceCents.split("")[1]}`)
}),
headers: {
'Content-Type': 'application/json'
}
};
try {
await fetch(REQUEST_URL, REQUEST_CONFIG);
setIsLoading(false);
const currentItems = JSON.parse(localStorage.getItem('all-items'));
const newItem = {
id: productID,
title: productName,
quantity: quantity,
price: parseFloat(`${priceDollar}.${priceCents.split("")[0]}${priceCents.split("")[1]}`)
};
localStorage.setItem('all-items', JSON.stringify([...currentItems, newItem]));
history.push('/');
} catch (err) {
console.error(err);
setIsLoading(false);
}
};
server.js:
const bodyParser = require('body-parser');
const express = require('express');
const app = express();
const sequelize = require('./db-config');
const apiRoutes = require('./routes/APIRoutes');
app.use(bodyParser.urlencoded({ extended: false }));
app.use(express.json());
app.use((req, res, next) => {
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader(
'Access-Control-Allow-Headers',
'Origin, X-Requested-With, Content-Type, Accept, Authorization'
);
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PATCH, DELETE');
next();
});
app.use('/api', apiRoutes);
sequelize.sync().then(result => {
app.listen(3001, console.log("Staring on port 3001"));
}).catch(error => {
console.error(error);
});
APIRoutes.js
const express = require('express');
const router = express.Router();
const controller = require('../controller/Controller');
router.get('/all-items', controller.allitems);
router.get('/search/:term', controller.search);
router.get('/summary', controller.viewSummary);
router.post('/api/new', controller.createNewProduct);
router.patch('/sell-item', controller.sellProduct);
router.delete('/delete-all', controller.deleteAllProducts);
router.delete('/delete/:id', controller.deleteProduct);
module.exports = router;
Controller.js
const Sequelize = require('sequelize');
const Product = require('../models/Product');
const SoldProduct = require('../models/SoldProduct');
const Op = Sequelize.Op;
const allItems = (request, response) => {
// ...
};
const search = (request, response) => {
// ...
};
const viewSummary = (request, response) => {
// ...
};
const createNewProduct = (request, response) => {
const { productID, name, quantity, price } = request.body;
Product.create({
productID: productID,
name: name,
quantity: quantity,
price: price
}).then(() => {
response.json({ message: "Successfully created a new product" });
}).catch(error => {
response.json({ message: "Something went wrong" });
});
};
const sellProduct = (request, response) => {
// ...
};
const deleteAllProducts = (request, response) => {
// ...
};
const deleteProduct = (request, response) => {
// ...
};
exports.allitems = allItems;
exports.search = search;
exports.viewSummary = viewSummary;
exports.createNewProduct = createNewProduct;
exports.sellProduct = sellProduct;
exports.deleteAllProducts = deleteAllProducts;
exports.deleteProduct = deleteProduct;
In server.js file, you mount all the routes in APIRoutes.js file to /api path:
app.use('/api', apiRoutes);
With this configuration, the URL should be: http://localhost:3001/api/api/new.
You can mount your routes to '/' path, then you can access your routes like you did.
app.use('/', apiRoutes);
or in the APIRoute.js file, you change from /api/new to just /new
router.post('/new', controller.createNewProduct);
I am using passport.js specifically the local-strategy for authentication with my next.js application.
Making requests to my data store is fine, and auth, authorization works as well. But I'd like access to the req.user for another route so I can have access to that users._id.
As the passport docs indicate:
By default, if authentication fails, Passport will respond with a 401
Unauthorized status, and any additional route handlers will not be
invoked. If authentication succeeds, the next handler will be invoked
and the req.user property will be set to the authenticated user.
This is my Next.js app's server.js file:
var express = require('express');
require('dotenv').config();
var morgan = require('morgan');
var cookieParser = require('cookie-parser');
var cors = require('cors');
var nextJS = require('next');
var session = require('express-session');
var mongoose = require('mongoose');
var MongoStore = require('connect-mongo')(session);
var path = require('path');
var bodyParser = require('body-parser');
var auth = require('./lib/auth');
var HttpStatus = require('http-status-codes');
var compression = require('compression');
var helmet = require('helmet');
var PORT = process.env.PORT || 8016;
var { isBlockedPage, isInternalUrl } = require('next-server/dist/server/utils');
function NODE_ENVSetter(ENV) {
var environment,
environments = {
production: () => {
environment = process.env.MONGODB_URI;
console.log(`We are currently in the production environment: ${environment}`);
return environment;
},
test: () => {
environment = process.env.TEST_DB_DSN;
console.log(`We are currently in the test environment: ${environment}`);
return environment;
},
default: () => {
environment = process.env.DEVELOPMENT_DB_DSN;
console.log(`We are currently in the development environment: ${environment}`);
return environment;
}
};
(environments[ENV] || environments['default'])();
return environment;
}
var db = NODE_ENVSetter('development');
function start() {
const dev = process.env.NODE_ENV !== 'production';
const app = nextJS({ dev });
const server = express();
// const proxy = createProxyMiddleware(options);
app
.prepare()
.then(() => {
mongoose.connect(db, {
useNewUrlParser: true,
useUnifiedTopology: true
});
mongoose.Promise = global.Promise;
mongoose.connection
.on('connected', () => {
console.log(`Mongoose connection open on ${db}`);
})
.on('error', err => {
console.log(`Connection error: ${err.message}`);
});
})
.catch(err => {
console.error(err);
});
server.use((req, res, next) => {
res.setHeader('Access-Control-Allow-Origin', '*');
res.header(
'Access-Control-Allow-Headers',
'Origin, X-Requested-With, Content-Type, Accept'
);
res.header('Access-Control-Allow-Credentials', true);
res.header('Access-Control-Allow-Methods', '*'); // enables all the methods to take place
return next();
});
server.use(function(req, res, next) {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Credentials', true);
res.header(
'Access-Control-Allow-Headers',
'Origin, X-Requested-With, Content-Type, Accept'
);
next();
});
server.use(morgan('dev'));
server.set('view engine', 'html');
server.use(express.static(path.join(__dirname + 'uploads')));
server.use('/uploads', express.static('uploads'));
server.use(cors());
server.use(cookieParser());
server.use(bodyParser.json());
server.use(
session({
secret: 'very secret 12345',
resave: true,
saveUninitialized: false,
store: new MongoStore({ mongooseConnection: mongoose.connection })
})
);
server.use(bodyParser.urlencoded({ limit: '50mb', extended: false }));
server.use(auth.initialize);
server.use(auth.session);
server.use(compression());
server.use(helmet());
server.use('/users', require('./users'));
Here I've included a log to check the req.user object
server.use((req, res, next) => {
console.log('req.user', req.user);
next();
});
// Redirect all requests to main entrypoint pages/index.js
server.get('/*', async (req, res, next) => {
try {
// #NOTE code duplication from here
// https://github.com/zeit/next.js/blob/cc6fe5fdf92c9c618a739128fbd5192a6d397afa/packages/next-server/server/next-server.ts#L405
const pathName = req.originalUrl;
if (isInternalUrl(req.url)) {
return app.handleRequest(req, res, req.originalUrl);
}
if (isBlockedPage(pathName)) {
return app.render404(req, res, req.originalUrl);
}
// Provide react-router static router with a context object
// https://reacttraining.com/react-router/web/guides/server-rendering
req.locals = {};
req.locals.context = {};
const html = await app.renderToHTML(req, res, '/', {});
// Handle client redirects
const context = req.locals.context;
if (context.url) {
return res.redirect(context.url);
}
// Handle client response statuses
if (context.status) {
return res.status(context.status).send();
}
// Request was ended by the user
if (html === null) {
return;
}
app.sendHTML(req, res, html);
} catch (e) {
next(e);
}
});
// eslint-disable-next-line func-names
class AppError extends Error {
constructor(message, statusCode) {
super(message);
this.statusCode = statusCode;
this.status = `${statusCode}`.startsWith('4') ? 'fail' : 'error';
this.isOperational = true;
Error.captureStackTrace(this, this.constructor);
}
}
server.all('*', (req, res, next) => {
next(new AppError(`Can't find ${req.originalUrl} on this server!`, 404));
});
if (process.env.NODE_ENV === 'production') {
server.use(express.static('.next/static'));
server.get('*', (req, res) => {
res.sendFile(path.resolve(__dirname, '.next/static', 'index.html'));
});
server.listen(PORT, err => {
if (err) throw err;
console.log(
`> Ready and listening on PORT:${PORT} in the ${process.env.NODE_ENV} environment`
);
});
} else {
server.listen(PORT, err => {
if (err) throw err;
console.log(`> Ready and listening on http://localhost:${PORT}`);
});
}
}
start();
And this is my auth file:
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
var UserModel = require('../models/UserModel');
passport.use(
new LocalStrategy(
{ usernameField: 'username', passwordField: 'password' },
async (username, password, done) => {
try {
const user = await UserModel.findOne({ username: username }).exec();
if (!user) {
return done(null, false, { message: 'Invalid username!' });
}
const passwordOk = await user.comparePassword(password);
if (!passwordOk) {
return done(null, false, {
message: 'Invalid password!'
});
}
return done(null, user);
} catch (err) {
return done(err);
}
}
)
);
// eslint-disable-next-line no-underscore-dangle
passport.serializeUser((user, done) => done(null, user._id));
passport.deserializeUser(async (id, done) => {
try {
const user = await UserModel.findById(id).exec(); //exec is used to get a real Promise
console.log('user deserialUser', user);
return done(null, user);
} catch (err) {
return done(err);
}
});
module.exports = {
initialize: passport.initialize(),
session: passport.session()
};
And it my /login route:
router.route('/login').post((req, res, next) => {
passport.authenticate('local', (err, user) => {
console.log('user 60', req.user);
console.log('user ', user);
// console.log('res.locals.user ', res.locals.user);
if (!user) {
return res.status(404).send({
msg: [
`We were unable to find this user.`,
`This email and/or password combo may be incorrect.
Please confirm with the "Forgot password" link above or the "Register" link below!`
]
});
}
if (user.isVerified === false) {
return res.status(401).send({
msg: [
'Your username has not been verified!',
'Check your email for a confirmation link.'
]
});
} else {
I made a log to see if user would be on the req object
console.log('req.user in success login route', req.user);
return res.status(200).send({
msg: [`Your have successfully logged in;`, `Welcome to Hillfinders!`]
});
}
})(req, res, next);
});
It appears what fixed my problem was the way I was declaring my routes.
This works:
router.post('/login', passport.authenticate('local'), function(req, res) {
var user = req.user;
if (!user) {
return res.status(404).send({
msg: [
`We were unable to find this user.`,
`This email and/or password combo may be incorrect.
Please confirm with the "Forgot password" link above or the "Register" link below!`
]
});
}
if (user.isVerified === false) {
return res.status(401).send({
msg: [
'Your username has not been verified!',
'Check your email for a confirmation link.'
]
});
} else {
return res.status(200).send({
msg: [`Your have successfully logged in;`, `Welcome to Hillfinders!`]
});
}
});
I was declaring it like this:
router.route('/login').post((req, res, next) => {
passport.authenticate('local', (err, user) => {
console.log('user ', user);
// console.log('res.locals.user ', res.locals.user);
if (!user) {
res.status(404).send({
msg: [
`We were unable to find this user.`,
`This email and/or password combo may be incorrect.
Please confirm with the "Forgot password" link above or the "Register" link below!`
]
});
return;
}
if (user.isVerified === false) {
res.status(401).send({
msg: [
'Your username has not been verified!',
'Check your email for a confirmation link.'
]
});
return;
} else {
res.status(200).send({
msg: [`Your have successfully logged in;`, `Welcome to Hillfinder!`]
});
return;
}
})(req, res, next);
});
Think I saw this syntax in the Express docs and just thought it was cool because of the chaining:
router.route('/login').post((req, res, next)=>{})
There must be some reason to declare it like this instead of the normal way...
Anyway thats' what eventually got me the user from passport to be on the req object \o/, This might also help other libraries that add objects of value to the req object too...
I have an express API and a ReactJs front-end. I try to make a POST call from my front-end directly to the local API.
For this I'm using axios.
The request is working fine when I set the parameters directly inside the query string but is always getting on timeout if I try to add the parameters through the data attribute of the axios.post() method.
Working
axios.post(`http://localhost:5001/site/authenticate?username=demo&password=demo`)
Not working
const payload = {
"username":"mh",
"password":"mh"
}
axios.post(`http://localhost:5001/site/authenticate`, payload)
My express server:
const express = require('express');
const bodyParser = require('body-parser');
const morgan = require('morgan');
const jwt = require('jsonwebtoken'); // used to create, sign, and verify tokens
var cors = require('cors');
const app = express();
const port = process.env.API_PORT || 5001;
app.use(cors());
app.set('secret', process.env.API_SECRET);
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.use(morgan('dev'));
app.use((req, res, next) => {
let data = '';
req.setEncoding('utf8');
req.on('data', (chunk) => {
data += chunk;
});
req.on('end', () => {
req.rawBody = data;
next();
});
});
// Allow CORS
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});
// SITE ROUTES -------------------
const siteRoutes = express.Router();
siteRoutes.post('/authenticate', function(req, res) {
console.log('auth');
getDocument(usersBucket, req.query.username)
.then((doc) => {
console.log("Authentification... TODO");
// return the information including token as JSON
res.json({
success: true,
status: 200,
token: token
});
})
.catch(() => {
res.status(401).json({ success: false, message: 'Authentification failed. User not found.' });
});
});
// route middleware to verify a token
siteRoutes.use(function(req, res, next) {
const token = req.body.token || req.query.token || req.headers['x-access-token'];
if (token) {
// verifies secret and checks exp
jwt.verify(token, app.get('secret'), function(err, decoded) {
if (err) {
return res.json({ success: false, message: 'Failed to authenticate token.', status: 401 });
} else {
req.decoded = decoded;
next();
}
});
} else {
return res.status(403).send({
success: false,
message: 'No token provided.'
});
}
});
siteRoutes.get('/', function(req, res) {
res.json({ message: 'Welcome!' });
});
app.use('/site', siteRoutes);
app.listen(port, () => {
logger.log(`Express server listening on port ${port}`);
});
Any idea? Thanks.
Update
I replaced my route just to see if I got in or not (without worrying about parameters):
siteRoutes.post('/authenticate', function(req, res) {
console.log("go in");
res.json({
success: true,
status: 200,
});
});
But my console.log is not showing hen I use the payload (it is when I do not).
You should access the payload data via request.body, not the request.query:
// SITE ROUTES -------------------
const siteRoutes = express.Router();
siteRoutes.post('/authenticate', function(req, res) {
console.log('auth');
getDocument(usersBucket, req.body.username) // <------- HERE
.then((doc) => {
console.log("Authentification... TODO");
// return the information including token as JSON
res.json({
success: true,
status: 200,
token: token
});
})
.catch(() => {
res.status(401).json({ success: false, message: 'Authentification failed. User not found.' });
});
});
request.query are the parameters passed in the URL, like:
protocol://hostname:port/path/to.route?query_param_0=value_0&query_param_1=value_1
on your express endpoint request.query will be:
{
query_param_0: value_0,
query_param_1: value_1
}
while sending the payload, with the second argument in axios.post(url, payload):
axios.post('/user', {
firstName: 'Fred',
lastName: 'Flintstone'
})
on your express endpoint request.body will be:
{
firstName: 'Fred',
lastName: 'Flintstone'
}
when you use app.use(bodyParser.json()); (and you do).
You are using “getDocument(usersBucket, req.query.username)”
This means you express route is expecting username as a request param. That’s why it’s working when you use “?username=xx”
Instead try to get it from json body of request.
“req.body.username”
Also you should consider validating the request body or param as required.
I have this code on my client side:
sendMail(e) {
e.preventDefault();
var name = document.getElementById('name').value;
var contactReason = document.getElementById('contactReason').value;
var email = document.getElementById('email').value;
var additionalInfo = document.getElementById('additionalInfo').value;
var body = {
name: name,
contactReason: contactReason,
email: email,
additionalInfo: additionalInfo,
};
console.log(body);
fetch('http://localhost:4000/', {
method: 'POST',
body: body.toString(),
}).then(r => console.log(r)).catch(e => console.log(e));
}
And this kind of works. It logs the object to the console, and sends something to the back end.
Here's my Node call:
var express = require('express');
var router = express.Router();
var cors = require('cors');
var app = express();
var bodyParser = require('body-parser');
app.use(bodyParser.json()); // for parsing application/json
app.use(bodyParser.urlencoded({extended: true}));
app.use(cors());
app.options('*', cors());
var a = '=';
router.post('/', (req, res, next) => {
console.log('mailing');
console.log(a);
console.log(req.body);
a += '=';
var nodemailer = require('nodemailer');
var transporter = nodemailer.createTransport({
host: "smtp.gmail.com", // hostname
auth: {
user: '******',
pass: '******'
}
});
let mailOptions = {
from: `${req.body.name} ${req.body.email}`, // sender address
to: 'alexander.ironside#mygeorgian.ca', // list of receivers
subject: 'Email from UczSieApp contact form', // Subject line
text: 'Hello world ', // plaintext body
html: `
<h4>Imie: ${req.body.name}</h4>
<h4>Email: ${req.body.email}</h4>
<h4>Powod kontaktu: ${req.body.contactReason}</h4>
<p>Wiadomosc: ${req.body.additionalInfo}</p>
`
};
// send mail with defined transport object
transporter.sendMail(mailOptions, function (error, info) {
if (error) {
return console.log(error);
}
console.log('Message sent: ' + info.response);
});
}
);
module.exports = router;
So what the code does right now:
The object is being created, something (not sure what exactly) is being send to Node back-end, and an email is being sent. But req.body is logged as {}.
What I want to do:
Read the values sent to the back-end as body and send an email with this data.
What am I missing?
I used GET instead of POST and this solved my problems. It is kind of a cheat but it works.
should add to fetch
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify(body),
all correct code
frontend
sendMail(e) {
e.preventDefault();
var name = document.getElementById('name').value;
var contactReason = document.getElementById('contactReason').value;
var email = document.getElementById('email').value;
var additionalInfo = document.getElementById('additionalInfo').value;
var body = {
name: name,
contactReason: contactReason,
email: email,
additionalInfo: additionalInfo,
};
console.log(body);
fetch('http://localhost:4000/', {
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify(body),
method: 'POST',
}).then(r => console.log(r)).catch(e => console.log(e));
}
backend
var express = require('express');
var router = express.Router();
var cors = require('cors');
var app = express();
var bodyParser = require('body-parser');
app.use(bodyParser.json()); // for parsing application/json
app.use(bodyParser.urlencoded({extended: true}));
app.use(cors());
app.options('*', cors());
var a = '=';
router.post('/', (req, res, next) => {
console.log('mailing');
console.log(a);
console.log(req.body);
a += '=';
var nodemailer = require('nodemailer');
var transporter = nodemailer.createTransport({
host: "smtp.gmail.com", // hostname
auth: {
user: '******',
pass: '******'
}
});
let mailOptions = {
from: `${req.body.name} ${req.body.email}`, // sender address
to: 'alexander.ironside#mygeorgian.ca', // list of receivers
subject: 'Email from UczSieApp contact form', // Subject line
text: 'Hello world ', // plaintext body
html: `
<h4>Imie: ${req.body.name}</h4>
<h4>Email: ${req.body.email}</h4>
<h4>Powod kontaktu: ${req.body.contactReason}</h4>
<p>Wiadomosc: ${req.body.additionalInfo}</p>
`
};
// send mail with defined transport object
transporter.sendMail(mailOptions, function (error, info) {
if (error) {
return console.log(error);
}
console.log('Message sent: ' + info.response);
});
}
);
module.exports = router;