I know I can do this in Express:
app.use('/:id', function (req, res){ // or app.get
console.log('Test param: ' + req.params.id); // "Test param: foo"
});
to get my url parameter.
When I try to use a router logic I did:
index.js
var sites = require('./routes/sites');
app.use('/:id', sites);
routes/sites.js
var express = require('express');
var router = express.Router();
router.get('/', function(req, res, next) {
console.log(req.params.id); // logs "undefined"
// etc ...
});
module.exports = router;
this logic does not work, I get {} in the shell command, undefined for req.params.id.
Any idea where my logic is wrong?
It doesn't work, because that's just not how express interacts with its Routers. The reason you're not seeing id inside your router, is because :id was not declared within its scope. You'd need to do something like
app.use('/', sites);
and in your router
var express = require('express');
var router = express.Router();
router.get('/:id', function(req, res, next) {
console.log(req.params.id);
// etc ...
});
module.exports = router;
Additionally you can try playing around with app.param() see docs for examples http://expressjs.com/api.html#app.param
When you are trying to do this in index.js and routes.js -
app.use('/:id', function (req, res){ // or app.get
console.log('Test param: ' + req.params.id); // "Test param: foo"
});
router.get('/', function(req, res, next) {
console.log(req.params.id); // logs "undefined"
// etc ...
});
"id" is not defined there because that's how express works with routers, it just matches the routes matching with the specified prefix in app.use() method. For that, you can try using -
const express = require('express');
const router = express.Router({mergeParams: true});
Now it will work perfectly.
It actually works now.
You can do something like
app.use('/:id/transactions', require('./routes/transactions'));
In the main file, and then add {mergeParams:true} to Router options in the controller file.
const router = require('express').Router({mergeParams:true});
So here you will be able to get the id that was set in base Route.
// localhost:5000/:id/transactions/
router.get('/',(req, res) => {
console.log(req.params.id);
}
Found here:
http://expressjs.com/api.html#app.param
In your file router/sites.js, add an option to express router:
const router = express.Router({mergeParams:true});
Now you have access to id in sites.js file.
Related
I have 2 router files. One is for view routing and other for api requests.
I am trying to set the routing using:
var routes = require('./routes/index'); //View Router
var api = require('./routes/api'); //API Router
app.use('/', routes);
app.use('/api', api);
This fails in case of /api requests. If I remove one of the routings, the other works.
I also tried,
routes(app);
api(app);
But this fails too. Any idea what might be the issue? Please let me know in case additional details are required.
routers/index.js
var express = require('express');
var router = express.Router();
var Promise = require('bluebird');
var nforce = require('nforce');
var org = require('../lib/connection');
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index', { title: 'App' });
});
router.get('/accounts', function(req, res, next){
console.log(org);
res.render('partials/' + name);
org.query({query: 'Select Id, Name, Type, Industry, Rating From Account Order By LastModifiedDate DESC'})
.then(function(results){
console.log(results);
res.render('accounts', {title: 'Accounts', records: results.records});
});
});
router.get('/partials/:name', function(req, res, next){
var name = req.params.name;
console.log(name);
res.render('partials/' + name);
});
router.get('/api/:name', function(req, res, next){
var name = req.params.name;
console.log(name);
res.render('api/' + name);
});
module.exports = router;
/routers/api.js
var express = require('express');
var router = express.Router();
var Promise = require('bluebird');
var nforce = require('nforce');
var org = require('../lib/connection');
/* GET home page. */
router.get('/getAccounts', function(req, res, next) {
console.log('in API router...');
org.query({query: 'Select Id, Name, Type, Industry, Rating From Account Order By LastModifiedDate DESC'})
.then(function(results){
console.log(results);
res.json({'accounts': results.records});
});
});
module.exports = router;
Maybe wrong but i see problem in this route.
router.get('/api/:name', function(req, res, next){})
It will match /api/cuteName and it also will match /api/getAccounts.
So you need to make routes more clear. I would suggest to change route inside index.js to be all something like /main/.
And all API routes move to api.js.
Hope this helps.
We can group our routes like this in Laravel:
Route::group("admin", ["middleware" => ["isAdmin"]], function () {
Route::get("/", "AdminController#index");
Route::post("/post", ["middleware" => "csrf", "uses" => "AdminController#index");
});
Basically, all the routes defined in admin group gets the isAdmin middleware and group name automatically. For example, post endpoint listens to admin/post not /post
Is there any way to do the same thing with Express? It would be awesome because my Laravel routes used to be so clean, whereas my Express routes are a bit messy/duplicated.
This is my routes.js on Express at the moment.
app.get("/admin", [passportConfig.isAuthenticated, passportConfig.isAdmin], AdminController.index);
app.post("/admin", [passportConfig.isAuthenticated, passportConfig.isAdmin], AdminController.postIndex);
Thank you.
Since express 4 you can define and compose routers
const app = require('express');
const adminRouter = app.Router();
adminRouter.use(isAdmin);
adminRouter.get('/', admin.index); /* will resolve to /admin */
adminRouter.post('/post', csrf, admin.index); /* will resolve to /admin/post */
app.use('/admin', adminRouter);
Hope that helps!
Just use before of every group you want to do:
app.use('/admin', AdminMiddleware);
app.get('/admin/route1', ...
app.get('/admin/route2', ...
app.use('/user', UserMiddleware);
app.get('/user/route1', ...
app.get('/user/route2', ...
require('express-group-routes');
var app = require('express');
app.group("/api/v1", (router) => {
router.get("/login", loginController.store); // /api/v1/login
});
In case you don't want to add a prefix but still need to group certain routes you can leave the first parameter and go straight for the function:
require('express-group-routes');
var app = require('express');
app.group((router) => {
router.use(middleware);
});
You can use app.use() - https://expressjs.com/en/guide/using-middleware.html#middleware.application
app.use("/admin",[passportConfig.isAuthenticated, passportConfig.isAdmin],AdminController)
// AdminController:
var express = require('express');
var router = express.Router();
router.get('/', AdminController.index);
// etc...
module.exports = router
https://expressjs.com/en/guide/routing.html#express-router
I found some better solution you can follow this method it's working good
Route file route/user.js
var express = require('express')
var router = express.Router()
const authMiddleware = require('../middleware/auth')
express.application.prefix = express.Router.prefix = function(path, middleware, configure) {
configure(router);
this.use(path, middleware, router);
return router;
}
router.prefix('/user', authMiddleware, async function (user) {
user.route('/details').get(function(req, res) {
res.status(201).send('Hello this is my personal details')
}); //also you can use controller method if you have any
});
module.exports = router //make sure you have to import/use this route in main/server js
You can use an npm module
Express group route
here is a code example from npm official module
var app = require('express');
require('express-group-routes');
app.group("/api/v1", (router) => {
router.get("/login", loginController.store); // /api/v1/login
});
Create the group method
export const group = ((callback: (router: Router) => void) => {
const router = express.Router();
callback(router);
return router;
});
Use the group method
import { group } from './relative/path/to/group/method'
const apiRouter = express.Router();
apiRouter.use('/foo', group((router) => {
router.get('/bar', (req, res) => {
res.send('Hello World');
});
}));
This will create a new GET route to "/foo/bar"
I just wrote this module to solve your problem: https://github.com/benjamin658/express-inject-middleware
You can group your middlewares as an array and pass it to the express-inject-middleware...
For example:
import express from 'express';
import { injectMiddleware } from 'express-inject-middleware';
const app = express();
const authMiddleware = (req, res, next) => {
// some auth logic...
};
const fooMiddleware = (req, res, next) => {
// some foo logic
}
const barMiddleware = (req, res, next) => {
// some bar logic
}
app.use(injectMiddleware(
[
authMiddleware,
fooMiddleware,
],
[
// Passing the app.[METHOD] as the parameter.
app.get('/secrets', (req, res, next) => res.send('secrets'));
// Mount barMiddleware itself
app.post('/secrets', barMiddleware, (req, res, next) => res.send('ok'));
],
));
and this is the result:
app.get('/secrets', authMiddleware, fooMiddleware, (req, res, next) => res.send('secrets'));
app.post('/secrets', authMiddleware, fooMiddleware, barMiddleware, (req, res, next) => res.send('ok'));
in express 4 to grouping your routes, you should create some changes :
seperate route files in multiple files like admin and front
pass the router to the divided route files in routes/index.js file
const express = require('express')
require('express-group-routes');
const router = express.Router()
require('./admin/web.router')(router)
require('./front/web.router')(router)
module.exports = router
in each files we can use groups, middlewares and prefixes, like below
const adminPrefix = 'admin'
module.exports = function (router) {
router.use(`\${adminPrefix}`, [ adminMiddleware ]);
router.group(`/${adminPrefix}`, (router) => {
router.get('/', home.index)
});
}
In my very simple app I have a users route which is hit when I browse to http://localhost/api/users
Is it possible for me to handle a post or get request to that url without appending anything extra to the route? Using the code below the route handler fires when I post to http://localhost/api/users/new but not to http://localhost/api/users and when I try get http://localhost/api/users/13 but not http://localhost/api/users
I know I could use router.post('/', function(req, res) {}); to post to http://localhost/api/users/ but that extra slash seems inelegant
app.js
var express = require('express');
var users = require('./routes/user');
var app = express();
app.use('/api/users', users);
module.exports = app;
routes\user.js
var express = require('express');
var User = require('../models/user');
var router = express.Router();
router.post(function(req, res) {
// post to root
});
router.post('/new', function(req, res) {
// post to /new
});
router.get(function (req, res, next) {
// get root
});
router.get('/:id', function (req, res, next) {
// get /id
});
module.exports = router;
in routes/user.js, you can simply write:
router.post('/', function (req, res, next) {
// post to /api/user or /api/user/
});
router.get('/', function (req, res, next) {
// get /api/user or /api/user/
});
This would work for both: http://localhost/api/users as well as http://localhost/api/users/
Also, there's nothing inelegant about having a / at the end of the url!
You can use an empty route like this :
router.get("", function (req, res, next) {
// get root
});
You will be able to access to /api/user as well as /api/user/
Also you can handle the route with the route method of router to simplify the code and make it more "elegant" :
router.route('/')
.get(function(req, res){}) // GET method of /api/users
.post(function(req, res){}) // POST method of /api/users
.put(function(req, res){}) // PUT method of /api/users
.delete(function(req, res){}) // DELETE method of /api/users
http://expressjs.com/es/api.html#router.route
I just started to learn node.js with express 4. I have read some books and tutorials, I also cloned some sample apps from git but I still have a very basic question, which practice should I follow to write the routing(or controller)?
Some people define all the routes in app.js, and export all the functions in the controller:
app.js
....
var homeController = require('./controllers/home');
var userController = require('./controllers/user');
....
app.get('/', homeController.index);
app.get('/login', userController.getLogin);
app.get('/logout', userController.logOUT);
app.get('/doStuff', userController.doStuff);
then in controllers/user.js
exports.getLogin = function(req, res) {
//logic...
});
exports.logout = function(req, res) {
//logic...
});
exports.doStuff = function(req, res) {
//logic...
});
Another way is like express-generator way:
app.js
...
app.use('/users', users);
...
controllers/users.js
....
router.get('/login', function(req, res, next) {
//logic...
});
router.get('/logout', function(req, res, next) {
//logic...
});
router.get('/doStuff', function(req, res, next) {
//logic...
});
module.exports = router;
And other are more dynamic like this proposal
is there any technical difference? Which pattern should I follow?
This is completely preferential. Any pattern that works is likely to be valid here. Express routers make things very nice and easy to setup. Personally I prefer to create a directory for every top level route, files for the second level, and exports for the third. Here's an example of how I lay things out for a set of API routes.
Directory:
routes/
index.js <- master route manifest
api/
index.js <- api routes manifest
books.js
authors.js
landing-pages/
index.js
awesome-deal.js
Route manifest:
// routes/index.js
var router = require('express').Router();
router.use('/api', require('./api'));
router.use('/landing', require('./landing-pages'));
module.exports = router;
API routes manifest:
// routes/api/index.js
var router = require('express').Router();
router.use('/books', require('./books.js'));
router.use('/authors', require('./authors.js'));
module.exports = router;
Entity endpoints:
// routes/api/books.js
var router = require('express').Router();
var db = require('mongoose-simpledb').db;
router.get('/get/:id', function (req, res) {
var id = req.param('id');
db.Book.findOneById(id, function (err, book) {
if (err) throw err;
res.json(book);
});
});
router.post('/new', /* etc... */);
return router;
Then in my app file I only setup the the top-level route:
// app.js
/* express setup.... */
app.use('/', require('./routes'));
Without resorting to regular expression is there anyway with expressjs to recursively call routing ie url examples:
/f:forum/s:section/t:thread/p:post
/f:forum/s:section/s:section/t:thread/p:post
/f:forum/s:section/s:section/s:section/t:thread/p:post
...
Therefore allowing technically an infinite amount of "sections/subsections" in the forum.
I attempted to do:
app.js:
var express = require('express');
app = express();
app.route('/').get(function(req, res, next){
return res.send('hello');
});
app.use('/f:forum', require('./section'));
server = app.listen(process.env.http || process.env.PORT);
module.exports = app;
section.js:
var router = require('express').Router();
router = router;
router.route('/s:section').get(function(req, res, next){
return res.send(req.params);
});
router.use('/s:section', require('./thread'));
module.exports = router;
thread.js:
var router = require('express').Router();
router.use('/s:section', require('./section'));
router.route('/t:thread/p-:post').get(function(req, res, next){
return res.send(req.params);
});
router.route('/t:thread').get(function(req, res, next){
return res.send(req.params);
});
module.exports = router;
but interestingly it tells me that in thread.js require('./section') = {}
yet in app.js it is correct... any suggestions?
You can do wildcard routing like router.route('/:path*') and then have the handler parse from that point down.
For example, something like:
router.route('/forum/:path*', function(req,res){
var requestPath = req.path; // will present the whole path to you for parsing
// do whatever db lookup logic you normally would do now that you have the pieces you wanted
res.render('forum', data);
};