Separating routes in Express - javascript

Edit #2
Got it, updated code
app.js
const express = require('express');
const bodyParser = require('body-parser');
const hbs = require('hbs');
const fs = require('fs');
var app = express();
// Server port
const port = process.env.PORT || 3000;
// Server starting message
app.listen(port, () => {
console.log(`Server is up on port ${port}`);
});
// Views directory established and handbars engine
hbs.registerPartials(__dirname + '/views/layouts')
app.set('view engine', 'hbs');
// static assets rendered
app.use(express.static(__dirname + '/public'));
// body-parser middleware
app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json())
// server.log setup middleware
app.use((req, res, next) => {
var now = new Date().toString();
var log = `${now}: ${req.method} ${req.url}`
console.log(log);
fs.appendFile('server.log', log + '\n', (err) => {
if (err) {
console.log('Unable to append to server.log');
}
});
next();
});
// Routes
const routes = require('./routes/routes');
app.use("/", routes);
// Get year for footer
hbs.registerHelper('getCurrentYear', () => {
return new Date().getFullYear()
});
Thank you everyone for your help!
Edit #1
I have added app.use("/", routes)" to my app.js but now when I test out my contact form and the mailer I get the following:
TypeError: Cannot read property 'name' of undefined
at router.post (/Users/benbagley/Code/poetry-out-loud/routes/routes.js:29:27)
at Layer.handle [as handle_request] (/Users/benbagley/Code/poetry-out-loud/node_modules/express/lib/router/layer.js:95:5)
at next (/Users/benbagley/Code/poetry-out-loud/node_modules/express/lib/router/route.js:137:13)
at Route.dispatch (/Users/benbagley/Code/poetry-out-loud/node_modules/express/lib/router/route.js:112:3)
at Layer.handle [as handle_request] (/Users/benbagley/Code/poetry-out-loud/node_modules/express/lib/router/layer.js:95:5)
at /Users/benbagley/Code/poetry-out-loud/node_modules/express/lib/router/index.js:281:22
at Function.process_params (/Users/benbagley/Code/poetry-out-loud/node_modules/express/lib/router/index.js:335:12)
at next (/Users/benbagley/Code/poetry-out-loud/node_modules/express/lib/router/index.js:275:10)
at Function.handle (/Users/benbagley/Code/poetry-out-loud/node_modules/express/lib/router/index.js:174:3)
at router (/Users/benbagley/Code/poetry-out-loud/node_modules/express/lib/router/index.js:47:12)
--
Original Question
I'm currently working on a node.js app and I'm trying to separate my app and routes into separate files.
Here is what I have so far
app.js
const express = require('express');
const bodyParser = require('body-parser');
const nodemailer = require('nodemailer');
const hbs = require('hbs');
const fs = require('fs');
const port = process.env.PORT || 3000;
var app = express();
hbs.registerPartials(__dirname + '/views/layouts')
app.set('view engine', 'hbs');
// body-parser middleware
app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json())
const routes = require('./routes/routes');
app.use((req, res, next) => {
var now = new Date().toString();
var log = `${now}: ${req.method} ${req.url}`
console.log(log);
fs.appendFile('server.log', log + '\n', (err) => {
if (err) {
console.log('Unable to append to server.log');
}
});
next();
});
app.use(express.static(__dirname + '/public'));
hbs.registerHelper('getCurrentYear', () => {
return new Date().getFullYear()
});
app.listen(port, () => {
console.log(`Server is up on port ${port}`);
});
routes.js
const express = require('express');
const router = express.Router();
// Routes
router.get('/', (req, res) => {
res.render('index.hbs', {
pageTitle: 'homepage'
});
});
router.get('/registration', (req, res) => {
res.render('registration.hbs', {
pageTitle: 'Registration'
});
});
router.get('/login', (req, res) => {
res.render('login.hbs', {
pageTitle: 'Login'
});
});
router.post('/send', (req, res) => {
const output = `
<p>You have a new contact request</p>
<h3>Contact Details</h3>
<br>
<ul>
<li>Name: ${ req.body.name }</li>
<li>Name: ${ req.body.email }</li>
</ul>
<h3>Message:</h3>
<p>${ req.body.message }</p>
`;
nodemailer.createTestAccount((err, account) => {
// create reusable transporter object using the default SMTP transport
let transporter = nodemailer.createTransport({
host: "smtp.mailtrap.io",
port: 2525,
auth: {
user: "xxxxxxx",
pass: "xxxxxxx"
}
});
// setup email data with unicode symbols
let mailOptions = {
from: `"${req.body.name}" <${req.body.email}>`, // sender address
to: 'xxxxxxxxx', // list of receivers
subject: 'New contact message', // Subject line
html: output // html body
};
// send mail with defined transport object
transporter.sendMail(mailOptions, (error, info) => {
if (error) {
return console.log(error);
}
console.log('Message sent: %s', info.messageId);
console.log('Preview URL: %s', nodemailer.getTestMessageUrl(info));
res.render('index', {
pageTitle: 'Thank you'
});
});
});
});
module.exports = router;
The current terminal output I'm receiving is
Server is up on port 3000
Tue Jan 09 2018 15:58:40 GMT+0000 (GMT): GET /
[nodemon] restarting due to changes...
[nodemon] starting `node app.js hbs, css`
Server is up on port 3000
and in the browser I'm getting
here is a screenshot of the file structure
Any help here would be appreciated.

I'm still new to this but I use the following on my base URL:
app.get('/', (req, res) => {
res.json('ready for your queries');
});
where
app = express() It's a simple code to let me know the server is running without doing anything with other services.

You should go for a tested solution. I like to use the express-generator. It creates a nice structure for you:
-bin
www
-config
-public
-javascripts
-stylesheets
-images
-routes
index.js
something.js
-views
index.ejs
something.ejs
app.js
bin/www holds your server-setting, app.js is where you load your config, your routes, your models if you are using a database. http://expressjs.com/en/starter/generator.html
You shouldn't have much trouble moving your code to this structure. Ask away if you have doubts.

Your code will be
app.js
const express = require('express');
const bodyParser = require('body-parser');
const nodemailer = require('nodemailer');
const hbs = require('hbs');
const fs = require('fs');
var app = express();
const port = process.env.PORT || 3000;
const routes = require('./routes/routes');
hbs.registerPartials(__dirname + '/views/layouts')
app.set('view engine', 'hbs');
// body-parser middleware
app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json())
router(app);
app.use((req, res, next) => {
var now = new Date().toString();
var log = `${now}: ${req.method} ${req.url}`
console.log(log);
fs.appendFile('server.log', log + '\n', (err) => {
if (err) {
console.log('Unable to append to server.log');
}
});
next();
});
app.use(express.static(__dirname + '/public'));
hbs.registerHelper('getCurrentYear', () => {
return new Date().getFullYear()
});
app.listen(port, () => {
console.log(`Server is up on port ${port}`);
});
routes.js
module.exports = function (app) {
app.get('/', (req, res) => { res.render('index.hbs', { pageTitle: 'homepage' }); });
router.get('/login', (req, res) => { res.render('login.hbs', { pageTitle: 'Login' }); });
..... Remaining function
}

Related

Cannot read fetch data on express server

On the client side, I have an application based on threejs an d javascript. I want to send data to the server written in express using fetch. Unfortunately, the server does not receive the data and the browser also gives an error:
Uncaught (in promise) TypeError: NetworkError when attempting to fetch resource.
Application:
this.username = prompt("Username:");
const body = JSON.stringify({ username: this.username });
fetch("http://localhost:3000/addUser", { method: "POST", body })
.then((response) => response.json())
.then(
(data) => (
console.log(data), (this.aktualny_album_piosenki = data.files)
)
);
Server:
var express = require("express")
var app = express()
const PORT = 3000;
var path = require("path");
app.use(express.static('dist'));
var bodyParser = require("body-parser");
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
var cors = require('cors');
app.use(cors());
app.post("/addUser", function (req, res) {
console.log(req.body)
})
I might be wrong but maybe try... (very bottom of your main server file)
app.listen((PORT) => {
console.log(`app is listening on port ${PORT}`);
})
is required maybe? I have this chunk of code in every project of my own so maybe that could fix the server not recognizing the api request
express documentation on app listen
heres what I use typically... this is a boilerplate for every one of my projects
const express = require("express");
const app = express();
const connectDB = require("./config/db.js");
const router = express.Router();
const config = require("config");
// init middleware
const bodyParser = require('body-parser');
const cors = require("cors");
const mongoDB = require("./config/db.js");
const path = require("path");
const http = require("http");
const server = http.createServer(app);
const io = require('socket.io')(server, {
cors: {
origin: '*',
}
});
const xss = require('xss-clean');
const helmet = require("helmet");
const mongoSanitize = require('express-mongo-sanitize');
const rateLimit = require("express-rate-limit");
const PORT = process.env.PORT || 5000;
mongoDB();
app.options('*', cors());
app.use('*', cors());
app.use(cors());
const limitSize = (fn) => {
return (req, res, next) => {
if (req.path === '/upload/profile/pic/video') {
fn(req, res, next);
} else {
next();
}
}
}
const limiter = rateLimit({
max: 100,// max requests
windowMs: 60 * 60 * 1000 * 1000, // remove the last 1000 for production
message: 'Too many requests' // message to send
});
app.use(xss());
app.use(helmet());
app.use(mongoSanitize());
app.use(limiter);
// app.use routes go here... e.g. app.use("/login", require("./routes/file.js");
app.get('*', function(req, res) {
res.sendFile(__dirname, './client/public/index.html')
})
app.get('*', cors(), function(_, res) {
res.sendFile(__dirname, './client/build/index.html'), function(err) {
if (err) {
res.status(500).send(err)
};
};
});
app.get('/*', cors(), function(_, res) {
res.sendFile(__dirname, './client/build/index.html'), function(err) {
if (err) {
res.status(500).send(err)
};
};
});
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", '*');
res.header("Access-Control-Allow-Credentials", true);
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS');
res.header("Access-Control-Allow-Headers", 'Origin,X-Requested-With,Content-Type,Accept,content-type,application/json');
next();
});
if (process.env.NODE_ENV === "production") {
// Express will serve up production files
app.use(express.static("client/build"));
// serve up index.html file if it doenst recognize the route
app.get('*', cors(), function(_, res) {
res.sendFile(__dirname, './client/build/index.html'), function(err) {
if (err) {
res.status(500).send(err)
}
}
})
app.get('/*', cors(), function(_, res) {
res.sendFile(path.join(__dirname, './client/build/index.html'), function(err) {
if (err) {
res.status(500).send(err)
}
})
})
};
io.on("connection", socket => {
console.log("New client connected");
socket.on("disconnect", () => console.log("Client disconnected"));
});
server.listen(PORT, () => {
console.log(`Server listening on port ${PORT}!`);
});
client-side fetch request looks good to me its prob a server/express.JS thing but like i said i may be wrong but worth trying

Emitting socket.io events from express router and processing on server

I am trying to build a webchat app using node.js and express. I have a router file and a server file, together with some client files. I would like to emit a join event from the router and processing it on the server so the user can join the room. I did i like this
Server.js
const express = require('express');
const layout = require('express-layout');
const app = express();
var server = require('http').createServer(app);
var io=require('socket.io')(server);
const routes = require('./router')(io);
const bodyParser = require('body-parser');
var fs = require("fs");
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
const middleware = [
layout(),
express.static(path.join(__dirname, 'public')),
bodyParser.urlencoded(),
];
app.use(middleware);
app.use('/', routes);
app.use((req, res, next) => {
res.status(404).send("Sorry can't find that!");
});
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).send('Something broke!');
});
io.on('connect', onConnect);
function onConnect(socket) {
var contents = fs.readFileSync("./public/rooms.json");
let rooms = JSON.parse(contents);
socket.emit('parse',rooms);
socket.on('join',function (name, room) {
console.log(name+" "+ room);
socket.join(room);
socket.user=name;
socket.room=room;
})
}
Here I just initialize the io connection together with all the dependencies I use. I use const routes = require('./router')(io); to pass the io variable
router.js
const express = require('express');
const User= require("./public/classes/User");
const router = express.Router();
const {check, validationResult} = require('express-validator');
const {matchedData} = require('express-validator/filter');
var userlist=new Array();
router.get('/', (req, res) => {
res.render('index', {
data: {},
errors: {}
})
});
router.post('/enter', [
check('username')
.isLength({min: 1})
.withMessage('Username is required').trim() //implement personalized check
], (req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.render('index', {
data: req.body,
errors: errors.mapped()
})
}
const data = matchedData(req)
handleJoin(data);
});
return router;
//MOVE TO SUPPORT
function find(name) {
return 1;
}
function handleJoin (data){
if(find(data.username)){
const newUser= new User (data.username, data.room,"");
userlist.push(newUser);
io.emit('join',newUser.name,newUser.room);
}
};
};
The console should log the name and the choosen room but it doesn't. How do I process this?

Problem with nodejs static route and files

In my project I have a report hat is reachable with index.html
But this is private and I want to protect / limit access with my node app. for this I use
app.use('/allure', express.static(path.join(__alluredir , 'allure-report/')));
Then I use for bugging purpose
app.all('/allure/*', function(req, res, next) {
console.log("catched allure query");
next(); // allow the next route to run
});
But the index.html is still reachable with localhost:8080/allure/index.hmtl and also just with localhost:8080/allure/ without an console output. This confuse a lot. Anybody has an idea how to hinder access the index.html without logged in? (Is use passport)
my whole app.js file is:
const express = require('express');
const app = express();
var http = require('http').Server(app);
var io = require('socket.io')(http);
const expressLayouts = require('express-ejs-layouts');
const mongoose = require('mongoose');
const passport = require('passport');
const flash = require('connect-flash');
const session = require('express-session');
var bodyParser = require('body-parser');
const fs = require('fs');
const path = require('path');
var favicon = require('serve-favicon')
const { allureGenerator } = require('./ops/copyalluredata');
app.set('socketio', io);
//app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json({ type: 'application/json' }));
app.use(bodyParser.urlencoded({
parameterLimit: 100000,
limit: '50mb',
extended: true
}));
var appDir = path.dirname(require.main.filename);
global.__basedir = appDir;
global.__alluredir = process.env.REPORT_DIR_ENV;
fs.readFile(path.join(appDir, '/config.xml'), (err, data) => {
if (err) throw err;
myConfigData = JSON.parse(data);
process.env.BROWSERSTACK_USERNAME = myConfigData.browserstackid;
process.env.BROWSERSTACK_ACCESS_KEY = myConfigData.browserstackkey;
process.env.BROWSERSTACK_DISPLAY_RESOLUTION="1600x1200";
console.log('config gelesen');
});
//Diese Funktion schreibt die benötigten Dateien in den allure Modul Ordner damit das Logo verwendet wird.
allureGenerator();
// Passport Config
require(path.join(appDir, '/config/passport'))(passport);
// DB Config
var db = '';
if (process.env.NODE_ENV == 'home') {
db = require(path.join(appDir, '/config/keys')).mongoURI;
console.log('keys');
}else{
db = require(path.join(appDir, '/config/keys_local')).mongoURI;
console.log('keys_local');
}
// Connect to MongoDB
mongoose
.connect(
db,
{ useNewUrlParser: true }
)
.then(() => console.log('MongoDB Connected'))
.catch(err => console.log(err));
app.use('/allure', express.static(path.join(__alluredir , 'allure-report/')));
app.use(express.static(appDir));
// EJS
app.use(expressLayouts);
app.set('view engine', 'ejs');
app.set('views', path.join(appDir, '/views'));
app.use(
session({
secret: 'secret',
resave: true,
saveUninitialized: true
})
);
app.use(favicon(path.join(__dirname, 'css', 'fvicon.ico')))
app.use(passport.initialize());
app.use(passport.session());
// Connect flash
app.use(flash());
// Global variables
app.use(function(req, res, next) {
res.locals.success_msg = req.flash('success_msg');
res.locals.error_msg = req.flash('error_msg');
res.locals.error = req.flash('error');
next();
});
// Routes
app.use('/', require('./routes/index.js'));
app.use('/users', require('./routes/users.js'));
app.use('/cases', require('./routes/cases.js'));
app.use('/tcafe', require('./routes/tcafe.js'));
app.use('/imgtest', require('./routes/imgtest.js'));
app.use('/rapitest', require('./routes/restapitest.js'));
io.on('connection', function(socket){
console.log('a user connected');
});
app.all('/allure/*', function(req, res, next) {
console.log("catched allure query");
next(); // allow the next route to run
});
app.use((req, res, next) => {
next({
status: 404,
message: 'Not Found',
});
});
app.use((err, req, res, next) => {
if (err.status === 404) {
return res.status(400).render('404',{ layout: 'system.ejs' });
}
if (err.status === 500) {
return res.status(500).render('500');
}
next();
});
const PORT = process.env.PORT || 8080;
http.listen(PORT, console.log(`Server started on port ${PORT}`));
You can use something like this Or just use somemiddleware-
app.use('/allure', function(req,res,next){
if(<authenticate check>){ // some kind of authenticate check
return express.static(path.join(__dirname, 'allure'));
} else {
<Any error you want to show>
}
});
OR
app.use('/allure',<Auth Middlewarae> , express.static(path.join(__dirname, 'allure')));

What is the problem with router division in express? (React)

[app.js]
onCreate = async (event) => {
event.preventDefault();
const clubData = new FormData(event.target)
console.log(clubData);
const post = await axios.post('/club', {
method: 'POST',
body: {
name : 'name',
intro : 'intro'
}
}).then(response => {console.log(post)})
}
This is when the router is not division.
[server.js]
const express = require('express');
const path = require('path');
const engines = require('consolidate');
const bodyParser = require('body-parser');
const app = express();
const PORT = process.env.PORT || 4000;
app.use(express.static(path.join(__dirname, '..', 'public/')));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended:true}));
app.post('/club', function(req, res, next) {
res.send({ test: 'test'});
})
app.set('views', __dirname + '/views');
app.engine('html', engines.mustache);
app.set('view engine', 'html');
app.listen(PORT, () => {
console.log(`Check out the app at http://localhost:${PORT}`);
});
At this point, we were able to see data coming over from the developer window at Chrome.
However, after splitting the router, an error occurs.
[server.js]
const express = require('express');
const path = require('path');
const engines = require('consolidate');
const bodyParser = require('body-parser');
const app = express();
const PORT = process.env.PORT || 4000;
var clubRouter = require('./router/clubRouter.js');
app.use(express.static(path.join(__dirname, '..', 'public/')));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended:true}));
app.use('/club', clubRouter);
app.set('views', __dirname + '/views');
app.engine('html', engines.mustache);
app.set('view engine', 'html');
app.listen(PORT, () => {
console.log(`Check out the app at http://localhost:${PORT}`);
});
[clubRouter.js]
const router = require('express').Router();
const controller = require('../controller/clubController');
router.post('/club', function(req, res, next) {
res.send({ test: 'test'});
})
module.exports = router;
An error occurs at this time.
(POST http://localhost:3000/club 404 (Not Found))
I've now created a project with a react-app-create and webpack.config.Added the code to dev.js file.
devServer: {
port: 4000,
open: true,
proxy: {
"/": "http://localhost"
}
},
The code was also added to the package.json file .
"proxy": "http://localhost:4000"
The clubRouter is mounted on path /club
That means any /club* requests will be handled over to clubRouter
The clubRouter further registers a controller on path /club that sends the response { test: 'test'}
So,
The complete path would now be => /club/club
In your React app, try this change and it would work:
const post = await axios.post('/club/club', { ... })
If you think the path is not how you want, you can register the controller in the clubRouter as follows:
router.post('/', function(req, res, next) {
res.send({ test: 'test'});
})
That way, you would be able to get hit it with the old path as:
const post = await axios.post('/club', { ... })

NodeJS :: TypeError: Cannot read property 'first_name' of undefined

I was learning the MEAN stack from a tutorial. When I tried on my localhost, I got an error.
TypeError: Cannot read property 'first_name' of undefined
at router.post (/var/www/html/mean/contactlist/routes/route.js:17:28)
I found some similar questions on the internet. But I didn't find the correct solution.
Here is my app.js file
//importing modules
var express = require('express');
var mongoose = require('mongoose');
var bodyparser = require('body-parser');
var cors = require('cors');
var path = require('path'); //core module
// calling express method
var app = express();
//connect to mongodb
mongoose.connect('mongodb://localhost/27017/contactlist');
//on connection
mongoose.connection.on('connected', () => {
console.log("connected to database database mongodb # 27017 ");
});
mongoose.connection.on('error', (err) => {
if(err){
console.log('Error in Database connection : ' + err);
}
});
//adding middleware cors
app.use(cors());
//adding body parser
app.use(bodyparser.json());
//adding static files
app.use(express.static(path.join(__dirname, 'public')));
//setting port no
const port = 3000;
//routing
var route = require('./routes/route');
//using the route
app.use('/api', route);
//testing server
app.get('/', (req, res)=>{
res.send('foobar');
});
//binding the server with port no (callback)
app.listen(port,() =>{
console.log('Server Started at Port : '+ port);
});
From a stackOverflow solution, I found,
I should use the following line before routing
app.use(bodyparser.json());
So I changed it.
And my ./routes/route.js
const express = require('express');
const router = express.Router();
const Contact = require('../models/contacts');
//Retrieving contacts
router.get('/contacts', (res, req, next) => {
contact.find(function(err,contacts){
res.json(contacts);
})
});
//Add contact
router.post('/contact', (res, req, next) => {
let newContact = new Contact({
first_name:req.body.first_name,
last_name:req.body.last_name,
phone:req.body.phone
});
newContact.save((err,contact) => {
if(err){
res.json({msg : 'Failed to add contact'});
}
else{
res.json({msg : 'Contact added successfully'});
}
});
});
//Deleting Contact
router.delete('/contact/:id', (res, req, next) => {
contact.remove({_id: req.params.id }, function(err, result){
if(err){
res.json(err);
}
else{
res.json(result);
}
});
});
module.exports = router;
Dependencies from package.json
"dependencies": {
"body-parser": "^1.17.1",
"cors": "^2.8.3",
"express": "^4.15.2",
"mongoose": "^4.9.8"
}
And the version of the nodejs is
v7.10.0
I used Postman to test the API
So I tested with POST method and following content-type option.
{"Content-Type":"application/x-www-form-urlencoded"}
This was my sample input
{
"first_name" : "RENJITH",
"last_name" : "VR",
"phone" : "1234567890"
}
Is it a version issue? Please suggest me the correct way of coding.
Your content type is {"Content-Type":"application/x-www-form-urlencoded"}
In order to support URL-encoded bodies of data you need to use this:
app.use(bodyparser.urlencoded({ // to support URL-encoded bodies
extended: true
}));
What you used is for JSON-encoded data, such as POST: {"name":"foo","color":"red"}
EDIT:
The order of your route parameters are wrong. It's not router.post('/contact', (res, req, next)
It's actually router.post('/contact', (req, res, next)
The first parameter is the request, the second is the response.
Just Move lines body-parse at the top before route (app.js)
app.use(bodyparser.json());
app.use('/api',route);
I was facing same issue but this is how it's been solved for me
At the top of the file before any routes and after require statements use
app.use(bodyParser.urlencoded({extended: true}))
app.use(bodyParser.json())
then in the post request route use res.json()
here is sample code:
var express = require('express');
var bodyParser = require('body-parser')
var app = express();
app.use(bodyParser.urlencoded({extended: false}))
app.use(bodyParser.json())
app.get('/', (req, res) => {
res.sendFile(__dirname + './index.html')
})
app.post("/name", (req, res) => {
let fullName = req.body.first + ' ' + req.body.last;
res.json({ name: fullName })
});

Categories

Resources