I recently went about restructuring an application I am building to fit the service oriented architecture. I really liked the way a certain tutorial structured his code, so I was trying to replecate a similiar strucutre in my app.
I want to abstract all my middleware out of app.js in my root so that basically all my app.js folder does is configure my express app. I would like to abstract all my middleware out of app.js, and configure it in my index.js folder located in my server directory. You can check my github repo below.
Please check the example repo, I would like to set up my code like this but am having lots of difficulty. Every time I try and take the middleware out of app and run it by requiring into index my app breaks.
Github Repo
I am trying to structure my code like so.
Example Repo
App.js (located in root)
const express = require('express');
const app = require('./server/index');
const mongoose = require('mongoose');
const passport = require('passport');
const dotenv = require('dotenv');
dotenv.config();
const port = process.env.PORT || 3000;
require('./server/config/passport')(passport);
// DB Config
const db = process.env.MongoURI;
mongoose.connect(db, { useNewUrlParser: true, useUnifiedTopology: true })
.then(() => {console.log('MONGODB Connected')})
.catch(err => console.log(err))
app.listen(port, () => {
console.log(`Running on port ${port}`);
});
index.js (located in server directory)
const express = require('express');
const app = express();
const api = require('./api/api');
const indexRouter = require('./api/index/indexRouter');
const usersRouter = require('../server/api/user/userRoutes');
require('./middleware/appMiddleware')(app);
app.use('/', indexRouter);
app.use('/users', usersRouter);
module.exports = app;
appMiddleware.js (located in middleware directory which is inside server directory)
const createError = require('http-errors');
const express = require('express');
const expressLayouts = require('express-ejs-layouts');
const path = require('path');
const cookieParser = require('cookie-parser');
const logger = require('morgan');
const flash = require('connect-flash');
const session = require('express-session');
const passport = require('passport');
const dotenv = require('dotenv');
dotenv.config();
module.exports = function(app) {
app.use(expressLayouts);
app.set('views', path.join(__dirname, '../../views'));
app.set('view engine', 'ejs');
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(session({
secret: 'secret',
resave: true,
saveUninitialized: true
}));
app.use(passport.initialize());
app.use(passport.session());
app.use(flash());
app.use((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();
});
// catch 404 and forward to error handler
app.use(function(req, res, next) {
next(createError(404));
});
// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
})
};
Terminal Error
Error: Failed to lookup view "error" in views directory "/Users/jojovera/Documents/fantasyfootball/views"
at Function.render (/Users/jojovera/Documents/fantasyfootball/node_modules/express/lib/application.js:580:17)
at ServerResponse.render (/Users/jojovera/Documents/fantasyfootball/node_modules/express/lib/response.js:1008:7)
at ServerResponse.res.render (/Users/jojovera/Documents/fantasyfootball/node_modules/express-ejs-layouts/lib/express-layouts.js:77:18)
at /Users/jojovera/Documents/fantasyfootball/server/middleware/appMiddleware.js:55:7
at Layer.handle_error (/Users/jojovera/Documents/fantasyfootball/node_modules/express/lib/router/layer.js:71:5)
at trim_prefix (/Users/jojovera/Documents/fantasyfootball/node_modules/express/lib/router/index.js:315:13)
at /Users/jojovera/Documents/fantasyfootball/node_modules/express/lib/router/index.js:284:7
at Function.process_params (/Users/jojovera/Documents/fantasyfootball/node_modules/express/lib/router/index.js:335:12)
at next (/Users/jojovera/Documents/fantasyfootball/node_modules/express/lib/router/index.js:275:10)
at /Users/jojovera/Documents/fantasyfootball/server/middleware/appMiddleware.js:44:3
at Layer.handle [as handle_request] (/Users/jojovera/Documents/fantasyfootball/node_modules/express/lib/router/layer.js:95:5)
at trim_prefix (/Users/jojovera/Documents/fantasyfootball/node_modules/express/lib/router/index.js:317:13)
at /Users/jojovera/Documents/fantasyfootball/node_modules/express/lib/router/index.js:284:7
at Function.process_params (/Users/jojovera/Documents/fantasyfootball/node_modules/express/lib/router/index.js:335:12)
at next (/Users/jojovera/Documents/fantasyfootball/node_modules/express/lib/router/index.js:275:10)
at /Users/jojovera/Documents/fantasyfootball/server/middleware/appMiddleware.js:39:3
Related
I'm trying to access my routes /api and /api/superheroes, but i'm getting this error when I do that.
Not Found
404
NotFoundError: Not Found
at C:\Users\mikae\Desktop\Project\node-express-swig-mongo\app.js:27:8
at Layer.handle [as handle_request] (C:\Users\mikae\Desktop\Project\node-express-swig-mongo\node_modules\express\lib\router\layer.js:95:5)
at trim_prefix (C:\Users\mikae\Desktop\Project\node-express-swig-mongo\node_modules\express\lib\router\index.js:317:13)
at C:\Users\mikae\Desktop\Project\node-express-swig-mongo\node_modules\express\lib\router\index.js:284:7
at Function.process_params (C:\Users\mikae\Desktop\Project\node-express-swig-mongo\node_modules\express\lib\router\index.js:335:12)
at next (C:\Users\mikae\Desktop\Project\node-express-swig-mongo\node_modules\express\lib\router\index.js:275:10)
at C:\Users\mikae\Desktop\Project\node-express-swig-mongo\node_modules\express\lib\router\index.js:635:15
at next (C:\Users\mikae\Desktop\Project\node-express-swig-mongo\node_modules\express\lib\router\index.js:260:14)
at Function.handle (C:\Users\mikae\Desktop\Project\node-express-swig-mongo\node_modules\express\lib\router\index.js:174:3)
at router (C:\Users\mikae\Desktop\Project\node-express-swig-mongo\node_modules\express\lib\router\index.js:47:12)
app.js
var api = require('./routes/api.js');
var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');
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('/users', usersRouter);
app.use('/api', api);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
next(createError(404));
});
// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
module.exports = app;
api.js
var express = require('express');
var router = express.Router();
router.get('/superheros', function(req, res) {
res.send('Just a test');
});
module.exports = router;
I'm following a tutorial and I already saw from scratch again and I didn't found the solution. I just want to access the routes that I've created to continue the lesson. Someone can help me? What should I do?
You've got a typo: it says /superheros (heros, not heroes) in api.js. Also, under /api, you're mounting a Router instance that has exactly one route defined: /superheros. There's no / route in the Router that you pass to:
app.use('/api', api);
And so, there is no handler for /api + /.
I am trying to upload a single image using python code to a node js express server. The python code is:
import requests
url = 'http://localhost:9000/testAPI/uploadphoto'
files = {'file': ('photo', open('test.jpg', 'rb'))}
ret = requests.post(url, files=files)
print ret
For the app.js, it is mostly following the default template:
var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
var cors = require('cors');
var bodyParser= require('body-parser')
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
var testAPIRouter = require("./routes/testAPI");
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
app.use(cors());
app.use(logger('dev'));
app.use(express.json());
//app.use(express.urlencoded({ extended: false }));
app.use(bodyParser.urlencoded({extended: true}))
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', indexRouter);
app.use('/users', usersRouter);
app.use("/testAPI", testAPIRouter);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
next(createError(404));
});
// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
module.exports = app;
and I am using the router testAPI for handling the POST:
var express = require('express');
var multer = require('multer');
var router = express.Router();
// SET STORAGE
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, '/uploads')
},
filename: function (req, file, cb) {
var filename = file.originalname;
var fileExtension = filename.split(".")[1];
cb(null, Date.now() + "_" + filename);
}
});
var upload = multer({ storage: storage });
router.get('/', function(req, res, next) {
console.log("test");
res.send('API is working properly');
});
router.post('/uploadphoto', upload.single('photo', (req, res, next) => {
const file = req.file;
if (!file) {
const error = new Error('Please upload a file')
error.httpStatusCode = 400
return next(error)
}
res.send('Photo uploaded');
}));
module.exports = router;
When I run the python code, the server returns 500. In my node js directory, I have an uploads folder created.
At the first you should run your node server project in port 9000
Your npm start probably calls your bin/www file. Which contains the listen invocation to start your app.
Many people set up their app this way. eg. app.js to define and configure their app, and something like bin/www to actual get the server running. This way they can include the app.js into other parts, say tests, without actually starting the server when you require it.
Figured it out. Since my server is started in the bin/www file as opposed to the app.js file, from the terminal I went into my bin directory and then called
node wwww
or
nodemon www
or add this code to the app.js and then run it with node app.js to listen port 9000
const port = 9000;
app.listen(port, () => console.log(Example app listening on port ${port}!))
I'm using express.router and ejs template. I want the logic of one of my form with a POST method will be handled not in the app file (the main file of the application) but in some other file with the name 'user.js' using router.post. It returns 404 since it's trying to find the logic on the main file instead on the users.js file.
How can I route the post logic to be handled in the user.js file?
app.js file
const express = require('express');
var app = express();
var path = require('path');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var logger = require('morgan');
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
var router = express.Router();
var usersRouter = require('./routes/users');
app.use('/users', usersRouter);
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
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')));
// catch 404 and forward to error handler
app.use(function(req, res, next) {
next(createError(404));
});
// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
module.exports = app;
users file (routes/users.js)
var express = require('express');
var app = require('../app')
const axios = require('axios');
var bodyParser = require('body-parser');
const {User} = require('../models/userModel')
const mongoose = require('mongoose');
const mongodb = require('mongodb');
const router = express.Router();
router.get('/', function(req, res, next) {
res.render("user");
});
router.post('/userSearch', (req, res) => {
res.send(req.body.myUser);
})
module.exports = router;
user file (views/user.ejs)
<h1>Welcome to users page</h1>
<form action="/userSearch" method="POST">
Search user:<input type ="search" name="myUser"></br>
<input type = "submit">
</form>
There are few unnecessary declarations on your files but the main reason your are not reaching the router path is because you are POSTing to a NOT declared route:
<form action="/userSearch" method="POST">
should be:
<form action="/users/userSearch" method="POST">
EXTRA
Few fixes for your files:
app.js
var router = express.Router(); //not needed here
users file (routes/users.js)
var app = require('../app') //not needed here
My express application seems to return 404 NOT FOUND whenever im using a post request method in my routes file. GET-requests are working fine and i can only see "GET" requests in the console aswell, even if im using a post request.
Is there some missing link between app.js and routes/index.js that might be causing this?
// routes/index.js
router.post('/foo', function (req, res, next) {
res.setHeader('Content-Type', 'application/json');
res.send('You sent: sdadad to Express');
})
// App.js
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var index = require('./routes/index');
var app = express();
var cors = require('cors')
app.use(cors())
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', index);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
module.exports = app;
Result:
Not Found 404
Error: Not Found
at C:\Users\willow\Desktop\backend\app.js:29:13
at Layer.handle [as handle_request] (C:\Users\willow\Desktop\backend\node_modules\express\lib\router\layer.js:95:5)
at trim_prefix (C:\Users\willow\Desktop\backend\node_modules\express\lib\router\index.js:317:13)
at C:\Users\willow\Desktop\backend\node_modules\express\lib\router\index.js:284:7
at Function.process_params (C:\Users\willow\Desktop\backend\node_modules\express\lib\router\index.js:335:12)
at next (C:\Users\willow\Desktop\backend\node_modules\express\lib\router\index.js:275:10)
at C:\Users\willow\Desktop\backend\node_modules\express\lib\router\index.js:635:15
at next (C:\Users\willow\Desktop\backend\node_modules\express\lib\router\index.js:260:14)
at Function.handle (C:\Users\willow\Desktop\backend\node_modules\express\lib\router\index.js:174:3)
at router (C:\Users\willow\Desktop\backend\node_modules\express\lib\router\index.js:47:12)
at Layer.handle [as handle_request] (C:\Users\willow\Desktop\backend\node_modules\express\lib\router\layer.js:95:5)
at trim_prefix (C:\Users\willow\Desktop\backend\node_modules\express\lib\router\index.js:317:13)
at C:\Users\willow\Desktop\backend\node_modules\express\lib\router\index.js:284:7
at Function.process_params (C:\Users\willow\Desktop\backend\node_modules\express\lib\router\index.js:335:12)
at next (C:\Users\willow\Desktop\backend\node_modules\express\lib\router\index.js:275:10)
at SendStream.error (C:\Users\willow\Desktop\backend\node_modules\serve-static\index.js:121:7)
What you wanna do should look like this in practice:
// routes/index.js
module.exports = (express) => {
// Create express Router
var router = express.Router();
// add routes
router.route('/foo')
.post((req, res) => {
res.setHeader('Content-Type', 'application/json');
res.send('You sent: sdadad to Express');
});
return router;
}
// App.js
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var routes = require('./routes')(express); // require routes at routes/index.js
var app = express();
var cors = require('cors')
app.use(cors())
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', routes);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
module.exports = app;
What I usually do is create a function that expects express as param like this
(routes/index.js)
module.exports = (express) => {
// Create express Router
var api = express.Router();
// add routes
api.route('/some_endpoint')
.post((req, res) => {
res.json({ message : 'some message' })
});
return api;
}
then I just import this file to my app.js
like this
(app.js)
// set api as a middleware
const api = require('./routes')(express);
app.use('/api/v1', api);
that way I hook up my api and my server.
I'm trying to build a shopping cart using node.js, express.js and mongodb. I'm in the process of building the sign up functionality. My problem is when I try to access the localhost:3000/user/profile link I get this error message:
Failed to lookup view "/user/profile" in views directory
"/Users/vynguyen/shopping-cart/views
Error: Failed to lookup view "/user/profile" in views directory "/Users/vynguyen/shopping-cart/views"
at EventEmitter.render (/Users/vynguyen/shopping-cart/node_modules/express/lib/application.js:579:17)
at ServerResponse.render (/Users/vynguyen/shopping-cart/node_modules/express/lib/response.js:960:7)
at /Users/vynguyen/shopping-cart/routes/index.js:34:6
at Layer.handle [as handle_request] (/Users/vynguyen/shopping-cart/node_modules/express/lib/router/layer.js:95:5)
at next (/Users/vynguyen/shopping-cart/node_modules/express/lib/router/route.js:131:13)
at Route.dispatch (/Users/vynguyen/shopping-cart/node_modules/express/lib/router/route.js:112:3)
at Layer.handle [as handle_request] (/Users/vynguyen/shopping-cart/node_modules/express/lib/router/layer.js:95:5)
at /Users/vynguyen/shopping-cart/node_modules/express/lib/router/index.js:277:22
at Function.process_params (/Users/vynguyen/shopping-cart/node_modules/express/lib/router/index.js:330:12)
at next (/Users/vynguyen/shopping-cart/node_modules/express/lib/router/index.js:271:10)
at csrf (/Users/vynguyen/shopping-cart/node_modules/csurf/index.js:117:5)
at Layer.handle [as handle_request] (/Users/vynguyen/shopping-cart/node_modules/express/lib/router/layer.js:95:5)
at trim_prefix (/Users/vynguyen/shopping-cart/node_modules/express/lib/router/index.js:312:13)
at /Users/vynguyen/shopping-cart/node_modules/express/lib/router/index.js:280:7
at Function.process_params (/Users/vynguyen/shopping-cart/node_modules/express/lib/router/index.js:330:12)
at next (/Users/vynguyen/shopping-cart/node_modules/express/lib/router/index.js:271:10
)
The profile.hbs file is located in the right folder, but for some reason the server won't pull it up.
Here's the whole file structure:
enter image description here
Here's my index.js file:
var express = require('express');
var router = express.Router();
var csrf = require('csurf');
var passport = require('passport');
var Product = require('../models/product');
var csrfProtection = csrf();
router.use(csrfProtection);
/* GET home page. */
router.get('/', function(req, res, next) {
Product.find(function(err, docs) {
var productChunks = [];
var chunkSize = 3;
for (var i = 0; i < docs.length; i += chunkSize) {
productChunks.push(docs.slice(i, i + chunkSize));
}
res.render('shop/index', { title: 'Shopping Cart', products: productChunks });
});
});
router.get('/user/signup', function(req, res, next) {
res.render('user/signup', {csrfToken: req.csrfToken()});
});
router.post('/user/signup', passport.authenticate('local.signup', {
successRedirect: '/user/profile',
failureRedirect: '/user/signup',
failureFlash: true
}));
router.get('/user/profile', function(req, res, next){
res.render('/user/profile');
});
module.exports = router;
Here's my app.js:
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var expressHbs = require('express-handlebars');
var mongoose = require('mongoose');
var session = require('express-session');
var passport = require('passport');
var flash = require('connect-flash');
var routes = require('./routes/index');
var userRoutes = require('./routes/user');
var app = express();
mongoose.connect('localhost:27017/shopping');
require('./config/passport');
// view engine setup
app.set('views', __dirname+'/views');
app.engine('.hbs', expressHbs({defaultLayout: 'layout', extname: '.hbs'}));
app.set('view engine', '.hbs');
// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(session({secret: 'mysupersecret', resave: false, saveUninitialized: false}));
app.use(express.static(path.join(__dirname, 'public')));
app.use(flash());
app.use(passport.initialize());
app.use(passport.session());
app.use('/user', userRoutes);
app.use('/', routes);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
module.exports = app;
When the view file path is resolved, the view path with leading slash will resolve to root directory and so the error. You need to resolve the view file relative to your views directory. Using user/profile or ./user/profile in res.render method would resolve the view file correctly.
correct code:
res.render('user/profile') or res.render('./user/profile')