I am new to Node.js. After watching many explanatory videos and and reading the Node.js docs, I started developing the site while respecting an MVC structure. The node server seems to work but the display on the front shows Cannot GET /. Here is the Browser Screenshot and the MVC structure of the project
index.js code :
'use strict';
/* eslint-env node, es6 */
const express = require('express');
const app = express();
app.set('view engine', 'ejs');
const PORT = process.env.PORT || 4242;
app.use('/', require('./routes/home_route'));
app.listen(PORT, () => {
console.log(`serveur démaré: localhost:${PORT}`);
});
home_controller.js code :
'use strict';
const homeView = (req, res) => {
res.render("home_view", {
} );
}
module.exports = { homeView };
home_route.js code :
'use strict';
const express = require('express');
const { homeView } = require('../controllers/home_controller');
const router = express.Router();
router.get('/home', homeView);
module.exports = router;
And home_view.ejs is just html. I don't understand where my mistake is, the code seems correct to me. Thank you in advance for your answers.
The problem is that you don't have any route handler for /. You are only handling /home. What you are saying with this line app.use('/', require('./routes/home_route')); is that every time I receive a request on /, I passe it to that router inside home_route.js, which only handles /home.
One way to solve this is to redirect the request you get on / to /home which is already handled. For that change home_route.js to:
const express = require('express');
const { homeView } = require('../controllers/home_controller');
const router = express.Router();
router.get('/home', homeView);
router.get('/', (req, res)=> res.redirect('/home')); // line I added
module.exports = router;
Related
so I'm trying to make a simple "route system", that would handle requests and send them to a certain controller.
The problem is that I can't even handle any route, because I get
Cannot GET /
error in response.
app.js
const express = require('express')
const router = require('./routes/routes')
const app = express()
const port = 3000
app.engine('.html', require('ejs').__express)
app.set('view engine', 'html')
router.load()
app.listen(port, () => {
console.log(`Waiting on :${port}`)
})
routes.js
const express = require('express')
const app = express()
// Route config
const routes = {
['/']: {
controller: 'index',
method: 'get'
},
}
// Load routes
const load = () => {
for (const route in routes) {
app[routes[route].method](route, (req, res) => {
// Do something
})
}
}
exports.load = load
You don't use your router file in app.js, try that:
app.js
const express = require('express')
const router = require('./routes/routes')
const app = express()
const port = 3000
app.engine('.html', require('ejs').__express)
app.set('view engine', 'html')
app.use('/', router);
router.load()
app.listen(port, () => {
console.log(`Waiting on :${port}`)
})
routes.js
var express = require('express');
var router = express.Router();
router.get('/', function(req, res, next) { res.send({ success: true }); });
module.exports = router;
It's useless and unreadeable create an array whit your all your routes.
My suggestion is to try use command by terminal express my_app for generate the base structure and try to use it or at least read for see how it's work.
You seem to be lacking the context for how the routing system works within Express.
As a starting point, please create a project with the below structure, and try creating your own route to ensure you have a grasp on how to utilize them properly.
Create a new project folder
cd into the project folder from within your terminal
run npm init -y
Run npm i express dotenv
Create a file named app.js in the root of your project folder and place the below code inside of it:
require('dotenv').config();
const express = require('express');
const app = express();
app.use(express.json({limit: '30mb', extended: true}));
app.use(express.urlencoded({ extended: true }));
app.listen(process.env.PORT || 3000, () => {console.log('Server successfully started')});
app.get('/', (req, res) => {
return res.send('Hello, World!');
});
Create a new folder named routes
Create a new file named test.js and place it inside of the routes folder
Place the below code in the test.js file.
const router = require('express').Router();
router.get('/', (req, res) => {
return res.send('Hello from your custom route!');
});
module.exports = router;
Go back into your app.js file and add the below lines of code to the bottom of the file
const testRoute = require('./routes/test');
app.use('/test', testRoute);
In your terminal, run node app.js
Make a GET request to http://localhost:3000/test by navigating to it with your browser, or by using a REST client, such as Postman.
Once you have completed these steps, you should understand the basic concept of Express routing.
You can use the router combined with Express Middleware to re-route your user to the proper controller based on the endpoint they are trying to access / the data they are trying to send.
Please test with this code
const express = require('express')
const app = express();
app.get('/', (req, res) => {
res.json({"message": "Welcome! it's working"});
});
The complete code is here on Github
This question already has answers here:
How to separate routes on Node.js and Express 4?
(9 answers)
Closed 1 year ago.
In my NodeJS express application I have app.js that has a few common routes. Then in a wf.js file I would like to define a few more routes.
How can I get app.js to recognize other route handlers defined in wf.js file?
A simple require does not seem to work.
If you want to put the routes in a separate file, for example routes.js, you can create the routes.js file in this way:
module.exports = function(app){
app.get('/login', function(req, res){
res.render('login', {
title: 'Express Login'
});
});
//other routes..
}
And then you can require it from app.js passing the app object in this way:
require('./routes')(app);
Have a look at these examples: https://github.com/visionmedia/express/tree/master/examples/route-separation
In Express 4.x you can get an instance of the router object and import another file that contains more routes. You can even do this recursively so your routes import other routes allowing you to create easy-to-maintain URL paths.
For example, if I have a separate route file for my /tests endpoint already and want to add a new set of routes for /tests/automated I may want to break these /automated routes out into a another file to keep my /test file small and easy to manage. It also lets you logically group routes together by URL path which can be really convenient.
Contents of ./app.js:
var express = require('express'),
app = express();
var testRoutes = require('./routes/tests');
// Import my test routes into the path '/test'
app.use('/tests', testRoutes);
Contents of ./routes/tests.js:
var express = require('express'),
router = express.Router();
var automatedRoutes = require('./testRoutes/automated');
router
// Add a binding to handle '/tests'
.get('/', function(){
// render the /tests view
})
// Import my automated routes into the path '/tests/automated'
// This works because we're already within the '/tests' route
// so we're simply appending more routes to the '/tests' endpoint
.use('/automated', automatedRoutes);
module.exports = router;
Contents of ./routes/testRoutes/automated.js:
var express = require('express'),
router = express.Router();
router
// Add a binding for '/tests/automated/'
.get('/', function(){
// render the /tests/automated view
})
module.exports = router;
Building on #ShadowCloud 's example I was able to dynamically include all routes in a sub directory.
routes/index.js
var fs = require('fs');
module.exports = function(app){
fs.readdirSync(__dirname).forEach(function(file) {
if (file == "index.js") return;
var name = file.substr(0, file.indexOf('.'));
require('./' + name)(app);
});
}
Then placing route files in the routes directory like so:
routes/test1.js
module.exports = function(app){
app.get('/test1/', function(req, res){
//...
});
//other routes..
}
Repeating that for as many times as I needed and then finally in app.js placing
require('./routes')(app);
If you're using express-4.x with TypeScript and ES6, this would be the best template to use:
src/api/login.ts
import express, { Router, Request, Response } from "express";
const router: Router = express.Router();
// POST /user/signin
router.post('/signin', async (req: Request, res: Response) => {
try {
res.send('OK');
} catch (e) {
res.status(500).send(e.toString());
}
});
export default router;
src/app.ts
import express, { Request, Response } from "express";
import compression from "compression"; // compresses requests
import expressValidator from "express-validator";
import bodyParser from "body-parser";
import login from './api/login';
const app = express();
app.use(compression());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(expressValidator());
app.get('/public/hc', (req: Request, res: Response) => {
res.send('OK');
});
app.use('/user', login);
app.listen(8080, () => {
console.log("Press CTRL-C to stop\n");
});
Much cleaner than using var and module.exports.
Full recursive routing of all .js files inside /routes folder, put this in app.js.
// Initialize ALL routes including subfolders
var fs = require('fs');
var path = require('path');
function recursiveRoutes(folderName) {
fs.readdirSync(folderName).forEach(function(file) {
var fullName = path.join(folderName, file);
var stat = fs.lstatSync(fullName);
if (stat.isDirectory()) {
recursiveRoutes(fullName);
} else if (file.toLowerCase().indexOf('.js')) {
require('./' + fullName)(app);
console.log("require('" + fullName + "')");
}
});
}
recursiveRoutes('routes'); // Initialize it
in /routes you put whatevername.js and initialize your routes like this:
module.exports = function(app) {
app.get('/', function(req, res) {
res.render('index', { title: 'index' });
});
app.get('/contactus', function(req, res) {
res.render('contactus', { title: 'contactus' });
});
}
And build yet more on the previous answer, this version of routes/index.js will ignore any files not ending in .js (and itself)
var fs = require('fs');
module.exports = function(app) {
fs.readdirSync(__dirname).forEach(function(file) {
if (file === "index.js" || file.substr(file.lastIndexOf('.') + 1) !== 'js')
return;
var name = file.substr(0, file.indexOf('.'));
require('./' + name)(app);
});
}
I am trying to update this answer with "express": "^4.16.3". This answer is similar to the one from ShortRound1911.
server.js:
const express = require('express');
const mongoose = require('mongoose');
const bodyParser = require('body-parser');
const db = require('./src/config/db');
const routes = require('./src/routes');
const port = 3001;
const app = new express();
//...use body-parser
app.use(bodyParser.urlencoded({ extended: true }));
//...fire connection
mongoose.connect(db.url, (err, database) => {
if (err) return console.log(err);
//...fire the routes
app.use('/', routes);
app.listen(port, () => {
console.log('we are live on ' + port);
});
});
/src/routes/index.js:
const express = require('express');
const app = express();
const siswaRoute = require('./siswa_route');
app.get('/', (req, res) => {
res.json({item: 'Welcome ini separated page...'});
})
.use('/siswa', siswaRoute);
module.exports = app;
/src/routes/siswa_route.js:
const express = require('express');
const app = express();
app.get('/', (req, res) => {
res.json({item: 'Siswa page...'});
});
module.exports = app;
If you want a separate .js file to better organize your routes, just create a variable in the app.js file pointing to its location in the filesystem:
var wf = require(./routes/wf);
then,
app.get('/wf', wf.foo );
where .foo is some function declared in your wf.js file. e.g
// wf.js file
exports.foo = function(req,res){
console.log(` request object is ${req}, response object is ${res} `);
}
One tweak to all of these answers:
var routes = fs.readdirSync('routes')
.filter(function(v){
return (/.js$/).test(v);
});
Just use a regex to filter via testing each file in the array. It is not recursive, but it will filter out folders that don't end in .js
I know this is an old question, but I was trying to figure out something like for myself and this is the place I ended up on, so I wanted to put my solution to a similar problem in case someone else has the same issues I'm having. There's a nice node module out there called consign that does a lot of the file system stuff that is seen here for you (ie - no readdirSync stuff). For example:
I have a restful API application I'm trying to build and I want to put all of the requests that go to '/api/*' to be authenticated and I want to store all of my routes that go in api into their own directory (let's just call it 'api'). In the main part of the app:
app.use('/api', [authenticationMiddlewareFunction], require('./routes/api'));
Inside of the routes directory, I have a directory called "api" and a file called api.js. In api.js, I simply have:
var express = require('express');
var router = express.Router();
var consign = require('consign');
// get all routes inside the api directory and attach them to the api router
// all of these routes should be behind authorization
consign({cwd: 'routes'})
.include('api')
.into(router);
module.exports = router;
Everything worked as expected. Hope this helps someone.
index.js
const express = require("express");
const app = express();
const http = require('http');
const server = http.createServer(app).listen(3000);
const router = (global.router = (express.Router()));
app.use('/books', require('./routes/books'))
app.use('/users', require('./routes/users'))
app.use(router);
routes/users.js
const router = global.router
router.get('/', (req, res) => {
res.jsonp({name: 'John Smith'})
}
module.exports = router
routes/books.js
const router = global.router
router.get('/', (req, res) => {
res.jsonp({name: 'Dreams from My Father by Barack Obama'})
}
module.exports = router
if you have your server running local (http://localhost:3000) then
// Users
curl --request GET 'localhost:3000/users' => {name: 'John Smith'}
// Books
curl --request GET 'localhost:3000/books' => {name: 'Dreams from My Father by Barack Obama'}
I wrote a small plugin for doing this! got sick of writing the same code over and over.
https://www.npmjs.com/package/js-file-req
Hope it helps.
you can put all route functions in other files(modules) , and link it to the main server file.
in the main express file, add a function that will link the module to the server:
function link_routes(app, route_collection){
route_collection['get'].forEach(route => app.get(route.path, route.func));
route_collection['post'].forEach(route => app.post(route.path, route.func));
route_collection['delete'].forEach(route => app.delete(route.path, route.func));
route_collection['put'].forEach(route => app.put(route.path, route.func));
}
and call that function for each route model:
link_routes(app, require('./login.js'))
in the module files(for example - login.js file), define the functions as usual:
const login_screen = (req, res) => {
res.sendFile(`${__dirname}/pages/login.html`);
};
const forgot_password = (req, res) => {
console.log('we will reset the password here')
}
and export it with the request method as a key and the value is an array of objects, each with path and function keys.
module.exports = {
get: [{path:'/',func:login_screen}, {...} ],
post: [{path:'/login:forgotPassword', func:forgot_password}]
};
app.js
var express = require("express");
var app = express();
var path = require('path');
var db = require('./db');
var bodyParser = require('body-parser');
app.listen(80);
app.set('view engine', 'jade');
app.set('views', "./views");
// app.get('/', _GetMainPage);
// app.get('/sites', _GetSites);
app.use(express.static(path.join(__dirname, 'public')));
app.use(bodyParser.urlencoded({ extended: true })); // Support encoded bodies
app.use(bodyParser.json()); // Support json encoded bodies
app.use(require('./controllers'));
./controllers/index.js
var express = require('express');
var router = express.Router();
router.use('/', require('./sites'));
router.use('/site', require('./site'));
module.exports = router;
./controllers/sites.js
var express = require('express');
var router = express.Router();
var site = require('../models/site');
router.get('/', function(req, res) {
site.getAll(function(err, rows){
if(err) {
res.send(err);
return;
}
res.render('sites', { sites : rows });
});
});
./controllers/site.js
var express = require('express');
var router = express.Router();
var site = require('../models/site');
router.get('/site', function(req, res) {
// console.log("get /site received. req.body: " + req.body);
res.render('site', {
site: {
name : req.params.name
}
});
});
module.exports = router;
When I request localhost/site I get a response saying:
Cannot GET /site
localhost/ works perfectly
I have been looking at this for a while and can't find the problem yet. If there is anything I can add, let me know. Thanks.
Thank you to the person that commented with the answer:
What happens if you navigate to /site/site? Your site.js route is relative to the route you provided in use. So it should be router.get('/' ... not router.get('/site' ...
The ./controllers/site route is already being routed to /site. On top of this I was calling router.get('/site', ...). This means it was actually routing to /site/site.
The solution is to just use router.get('/', ...) in the site.js file instead.
This really helped me, thank you.
Basically, the root path in the sub-app is defined in your core app where you mount it via the app.use() method.
the best example I can find from app.mountpath docs is here:
https://expressjs.com/en/4x/api.html#express.router
The app.mountpath property contains one or more path patterns on which a sub-app was mounted.
var express = require('express');
var app = express(); // the main app
var admin = express(); // the sub app
admin.get('/', function (req, res) {
console.log(admin.mountpath); // /admin
res.send('Admin Homepage');
});
app.use('/admin', admin); // mount the sub app
It is similar to the baseUrl property of the req object, except
req.baseUrl returns the matched URL path, instead of the matched
patterns.
If a sub-app is mounted on multiple path patterns, app.mountpath
returns the list of patterns it is mounted on, as shown in the
following example.
var admin = express();
admin.get('/', function (req, res) {
console.log(admin.mountpath); // [ '/adm*n', '/manager' ]
res.send('Admin Homepage');
});
var secret = express();
secret.get('/', function (req, res) {
console.log(secret.mountpath); // /secr*t
res.send('Admin Secret');
});
admin.use('/secr*t', secret); // load the 'secret' router on '/secr*t', on the 'admin' sub app
app.use(['/adm*n', '/manager'], admin); // load the 'admin' router on '/adm*n' and '/manager', on the parent app
I've created a node application with express. I try to separate the following layers which will give me the ability to test the application with unit testing...
The problem is that I don't know how to call to the router.js file which will stops in the post/get/delete application.
The server.js file looks as follows
http = require('http'),
app = require('./app')(),
http.createServer(app).listen(app.get('port'), function (err) {
console.log('Express server listening on port ' + app.get('port'));
});
This is the app.js file
var express = require('express'),
logger = require('morgan'),
bodyParser = require('body-parser'),
routesApp = require('./ro/route');
module.exports = function () {
var app = express();
app.set('port', process.env.PORT || 3005);
app.use(logger('dev'));
app.use(function (req, res, next) {
res.set('APP', 'User app');
next();
});
app.use(bodyParser.json());
app.use(routesApp);
return app;
};
This is the router.js, which will route the call to other module according to the http type like post/delete/get etc...
var handleGet = require('../controller/handleGet');
var handlePost = require('../controller/handlePost');
var express = require('express');
module.exports = function (app) {
var appRoute = express.Router();
app.use(appRoute);
appRoute.route('*')
.post(function (req, res) {
handlePost(req, res);
})
.get(function (req, res) {
handleGet(req, res)
})
Currently I've two questions:
How to make it work since when in debug It dump in
app.use(appRoute); on the router.js file?
The error is TypeError: undefined is not a function
Is it good way to structure the node app like in my post? I want to seperate all this layers like SOC, I'm fairly new to node and express and I try to build it to be modular and testable...
How to make it work since when in debug It dump in app.use(appRoute); on the router.js file? The error is TypeError: undefined is not a function
This fails because you don't pass app into the module when you require it in app.js, you would need to do something like
app.use(routesApp(app)); // <- this hurts my eyes :(
Is it good way to structure the node app like in my post?I want to sperate all this leyrs like SOC,I fairly new to node and express and I try to build it to be modular and testable...
Your definitely on the right track, keeping things separated is generally always a good idea. Testing is definitely one of the big pluses but it also helps with other things like maintainability & debugging.
Personally, I would make use of the bin directory for any start up script configuration
bin/www
var app = require('./app');
app.set('port', process.env.PORT || 3005);
var server = app.listen(app.get('port'), function() {
console.log('Express server listening on port ' + app.get('port'));
});
This will help decouple your express app from all the environment setup. This should keep your app.js clean and only contain app-related config
app.js
var express = require('express')
, app = express()
, logger = require('morgan')
, bodyParser = require('body-parser')
, routes = require('./routes.js');
app.use(logger('dev'));
app.use(function (req, res, next) {
res.set('APP', 'User app');
next();
});
app.use(bodyParser.json());
app.use('/', routes);
...
module.exports = app;
Then finally, your routes.js should do nothing but handle your URLs
routes.js
var express = require('express')
, router = express.Router()
, handleGet = require('../controller/handleGet')
, handlePost = require('../controller/handlePost');
router.get('/', handleGet);
router.post('/', handlePost);
...
module.exports = router;
I have loads of router.get functions in my code which I think, could be reduced to a single switch-case function. Here is what I have tried:
function handlerA(req, res) {}
function handlerB(req, res) {}
var routes = {
'/url-one': handlerA,
'/url-two': handlerB
}
router.get('/*', function(req, res) {
var url = req.url;
if (routes[url]) {
routes[url](req, res);
}
});
This works but also, significantly slows my application. Is there any other solution which would not hit the performance of my app?
Thanks
Is there a reason you don't want to use router.get functions? I would guess express.js is internally performing the same logic that you are doing anyway. You are just replacing get functions with handlers.
If you are using similar logic between multiple routes, that may be worth abstracting.
I usually go with a setup like this:
app.js
routes.js
api/
user/
index.js
user.controller.js
user.model.js
image/
index.js
image.controller.js
image.model.js
/api/user/index.js:
var express = require('express');
var controller = require('./user.controller');
var router = express.Router();
router.get('/', controller.index);
router.post('/', controller.create);
module.exports = router;
/api/user/user.controller.js:
var User = require('./user.model');
exports.index = function(req, res) {
// Show list of users
};
exports.create = function (req, res, next) {
// Create user
};
/routes.js:
module.exports = function(app) {
// Insert routes below
app.use('/api/users', require('./api/user'));
app.use('/api/images', require('./api/image'));
// All undefined asset or api routes should return a 404
app.route('/:url(api|auth|components|app|bower_components|assets)/*')
.get(errors[404]);
// All other routes should redirect to the index.html
app.route('/*')
.get(function(req, res) {
res.sendfile(app.get('appPath') + '/index.html');
});
};
And lastly, the /app.js:
// Set default node environment to development
process.env.NODE_ENV = process.env.NODE_ENV || 'development';
var express = require('express');
var mongoose = require('mongoose');
var config = require('./config/environment');
// Connect to database
mongoose.connect(config.mongo.uri, config.mongo.options);
// Populate DB with sample data
if(config.seedDB) { require('./config/seed'); }
// Setup server
var app = express();
var server = require('http').createServer(app);
require('./config/express')(app);
require('./routes')(app);
// Start server
server.listen(config.port, config.ip, function () {
console.log('Express server listening on %d, in %s mode', config.port, app.get('env'));
});
// Expose app
exports = module.exports = app;
Most of this is directly from the Yeoman Generator Angular-Fullstack and it has a really nice setup!