is there a better way of prefixing all routes with /something than this?
app.use('/api/users', require('./routes/users'));
app.use('/api/books', require('./routes/books'));
app.use('/api/authors', require('./routes/authors'));
That would also work when using the routes in my server.js with the app.get()/post()/...
If all your routes are prefixed by /api, I suppose you could use function.
function api(route) {
return `/api/${route}`;
}
app.use(api('users'), require('./routes/users'));
app.use(api('books'), require('./routes/books'));
app.use(api('authors'), require('./routes/authors'));
That being said, the /api prefix may be unnecessary. You could just omit it:
app.use('/users', require('./routes/users'));
app.use('/books', require('./routes/books'));
app.use('/authors', require('./routes/authors'));
You need to add { mergeParams: true } into the child router.
// app.js
import routes from './routes'
const API_PREFIX = '/api'
app.use(API_PREFIX, routes)
// routes.js
import { Router } from 'express'
import users from './users'
import books from './books'
import authors from './authors'
const router = Router({ mergeParams: true })
router.use(users)
router.use(books)
router.use(authors)
export default router
Related
I was working on a personal express project. I've created two files one server file and other restaurants.route.js to sepearate routes and server code. But I'm not able trigger the home route from local host. Moreover no console error is showing only the 404 page error.
server.js code:
import express from "express";
import cors from "cors";
import restaurants from "./api/restaurants.route.js";
// initialising express app
const app = express();
// applying middlewears
app.use(cors());
app.use(express.json());
app.use("api/v1/restaurants", restaurants);
app.use("*", (req, res) => res.status(404).json({error: "not found"}));
export default app;
restaurants.route.js:
import express from "express";
// express router
const router = express.Router();
router.route("/")
.get((req, res) => {
res.send("Hello World");
});`enter code here`
export default router;
It looks like you might be missing the leading forward slash (/) in the path you're using to mount the restaurants router in your server.js file. When you use the app.use() method to mount a router, the path you specify should start with a forward slash.
So instead of this:
app.use("api/v1/restaurants", restaurants);
Try this:
app.use("/api/v1/restaurants", restaurants);
I implemented protected API routes in Express using the Auth0 quick start. Protected routes are handled with a middleware function called checkJwt, provided by Auth0. It runs whenever one of the GET methods is called. This process works well if I manage all my routes in server.js.
How can I separate out the route handling and still preserve the protected API routes?
server.js working code with protected routes.
import colors from 'colors'
import cors from 'cors'
import express from 'express'
import morgan from 'morgan'
import dotenv from 'dotenv'
import connectDB from './db.js'
import checkJwt from './middleware/auth.middleware.js'
import { getStudents, getStudent } from './controllers/students.controller.js'
dotenv.config()
connectDB()
export const app = express()
app.use(cors())
app.use(express.json({ limit: '50mb' }))
if (process.env.NODE_ENV === 'development') {
app.use(morgan('dev'))
}
//handle routing internally
app.get('/api/students/:id', checkJwt, getStudent)
app.get('/api/students', checkJwt, getStudents)
const PORT = process.env.PORT || 6000
app.listen(PORT, () =>
console.log(
`Server running in ${process.env.NODE_ENV} mode on port ${PORT}`.yellow.bold
)
)
I want to divorce out the route handling as my code grows. I can't figure out where to put checkJwt once I separate out the routing.
server.js desired code structure is:
import colors from 'colors'
import cors from 'cors'
import express from 'express'
import morgan from 'morgan'
import dotenv from 'dotenv'
import connectDB from './db.js'
import studentsRouter from './routes/students.routes.js'
dotenv.config()
connectDB()
const app = express()
app.use(cors())
app.use(express.json({ limit: '50mb' }))
if (process.env.NODE_ENV === 'development') {
app.use(morgan('dev'))
}
// handle routing externally
const apiRouter = express.Router()
app.use('/api', apiRouter)
apiRouter.use('/students', studentsRouter)
const PORT = process.env.PORT || 6000
app.listen(PORT, () =>
console.log(
`Server running in ${process.env.NODE_ENV} mode on port ${PORT}`.yellow.bold
)
)
Routes are implemented in the students.routes.js Route handler.
import express from 'express'
import { getStudent, getStudents } from '../controllers/students.controller.js'
const router = express.Router()
// where can I implement checkJwt?
router.route('/').get(getStudents)
router.route('/:id').get(getStudent)
export default router
Is it possible to simplify the code by moving the routing, and still protect my routes?
you can use any middleware like this in your router:
const router = express.Router();
router.route('/').get([checkJwt, secondMiddleware, ...] , getStudents);
based on documentation:
express-routing
You can provide multiple callback functions that behave like middleware to handle a request. The only exception is that these callbacks might invoke next('route') to bypass the remaining route callbacks. You can use this mechanism to impose pre-conditions on a route, then pass control to subsequent routes if there’s no reason to proceed with the current route.
After receveing help about using Express, I continued to follow tutorials about Node.js. I'm at a point where i'm building my own routes in controllers to create a REST API. I have two files, app.js and /controllers/account-api.js.
Here's my app.js shortened (i deleted the parts that were not used my my test), and the line that is returning me some issues.
import express from 'express';
import exphbs from 'express-handlebars';
import * as accountApiRoutes from './controllers/account-controller.js';
import * as bodyParser from 'body-parser';
var app = express();
app.engine('handlebars', exphbs());
app.set('view engine', 'handlebars');
app.use(bodyParser.urlencoded({extended:true}));
app.use(accountApiRoutes); // ISSUE HERE, i tried ('/account-api', accountApiRoutes) too
app.get('/', function(req, res)
{
res.redirect('/server-home');
});
app.get('/server-home', function(req, res)
{
res.render('server-home');
});
app.listen(1337, '127.0.0.1');
console.log('Express Server running at http://127.0.0.1:1337/');
And here's my ./controllers/account-api.js shortened again to give the main elements that causes the issue :
import express from 'express';
const apiRouter = express.Router(); //ISSUE HERE
var accounts = [];
accounts.push( { code: 1, name: 'Pierrette', adress: 'Sur la Lune'} );
// =========== API ROUTES =========== //
// GET
apiRouter.route('/produit-api/produit/:code')
.get( function(req, res, next) {
var codeSended = req.params.code;
var account = findAccountInArrayByCode(codeSended);
res.send(account);
});
// =========== METHODS AND FUNCTIONS =========== //
// GET
function findAllAccounts() {
return accounts;
}
function findAccountInArrayByCode(codeSended) {
var accountFound = null;
for(i in accounts)
{
if(accounts[i].code === codeSended)
{
accountFound = accounts[i];
break;
}
}
return accountFound;
}
module.exports = { //ISSUE HERE
getApiRouter: function() {
const apiRouteur = express.Router();
return apiRouter;
}
}
The problem is.. This code returns me "module" is not defined.
I use Node.JS with Express and Handlebars.
For what I saw online, when using "app.use", it requires a function. And module.exports too. I tried various solutions, like this one :
account-api.js
const apiRouter = function() { return express.Router() }
...
module.exports = apiRouteur;
The problem is that it changes the type of apiRouteur, when calling apiRouteur.get from IRouter to () => Router, and the routes break.
I don't know how to arrange the code to make the module.exports returning a function that works, or if the problem is not even about the type of value returned, but if I'm missing dependancies, etc...
Thanks for your help.
EDIT : With the explanations I got, I replaced all my ES6 calls to commonjs imports. But it doesn't solve the problem. Now it's "require" that's not define.
I was stuck firstly by "require is not defined", and the solution I was given by reading old SO threads about it, the answer was regularly to use ES6 imports...
ack to the begining I guess ! Maybe I miss something in my project?
Your problem is this line app.use(accountApiRoutes); and you are using a mix of ES6 and commonjs modules.
To fix the module imports (as you are using .js files not .mjs) change all your ES6 imports i.e import * as xyz imports to commonjs imports const x = require('...');
The accountApiRoutes is an object but not a Router object.
To fix you just need to pass the router object to the app.use function.
So you will need to make a couple of changes based on what you have supplied above.
// ./controllers/account-api.js
const express = require('express');
...
module.exports = { //ISSUE HERE
getApiRouter: function() {
return apiRouter; // you have already defined the router you don't need to recreate it
}
}
Properly pass the Router object to the express app.
const express = require('express');
const exphbs = require('express-handlebars');
const bodyParser = require('body-parser');
const accountApiRoutes = require('./controllers/account-controller.js');
...
app.use(accountApiRoutes.getApiRouter());
You could also just set module.exports to your configured router in your account-api.js and then you could pass it directly to app.use as you have already done in your server above. Either way should work. To can do that as follows:
// ./controllers/account-api.js
const express = require('express');
...
module.exports = apiRouter;
And in your server.js
const accountRouter = require('./controllers/account-controller.js');
app.use(accountRouter);
Folder structure
index.js
modules/users/users.server.routes.js
modules/users/users.server.routes.js
export default (app) => {
app.route('/api', (req, res) => {
res.send('User routes working');
});
};
index.js
import express from 'express';
import mongoose from 'mongoose';
/*
* For iterating through files using a regex
* */
import glob from 'glob';
let files = glob.sync('app/**/*.routes.js');
files = files.map((file) => {
import(file);
});
const app = express();
const config = {
app_port: 8080
};
/*
* Test route
* */
app.get('/', (req, res) => {
res.send('Voila!!');
});
Above code is giving an error!
'import' and 'export' may only appear at the top level
What I want to achieve is, once the server gets started, all the routes should be imported. (Live require(--route file--))
I don't want to declare all the routes in a single routes file like this.
// mount user routes at /users
router.use('/users', userRoutes);
// mount auth routes at /auth
router.use('/auth', authRoutes);
I want each route to be defined from the root of the API.
How to achieve this in ES6 way?
Thank you all!
I have a route /users as a parent suffix in my router, all subsequent routes will append the the parent eg. /users/details
In my app.js
app.use('/api/v1/users', userRoutes);
In my userRoutes
import express from 'express';
import users from '../controllers/user_controller';
import { authenticateRoute, authenticateSignedRoute, aclAuthenticator } from './../middlewares/AuthenticationMiddleware';
const router = express.Router();
//user routes
router.get('/details', authenticateRoute, aclAuthenticator, users.getDetails);
router.get('/posts', authenticateRoute, aclAuthenticator, users.getPosts);
module.exports = router;
WHAT I WOULD LIKE TO DO
Is there a way for me to add the authenticateRoute and the aclAuthenticator middleware to the parent prefixed route, and then for one particular route have an exception where only a third middleware is applied and not the first two.
For eg
app.use('/api/v1/users', authenticateRoute, aclAuthenticator, userRoutes);
My new router file
router.get('/details', applyOnlyThisMiddleWare, users.getDetails);
router.get('/posts', No MiddleWareAtAll, users.getPosts);
I'm basically trying to overide the initial middleware, is this possible?
This is how i explicitly disable middleware for specific routes
'use strict';
const ExpressMiddleware = ( req, res, next ) => {
// dont run the middleware if the url is present in this array
const ignored_routes = [
'/posts',
'/random-url',
];
// here i am checking for request method as well, you can choose to remove this
// if( ! ignored_routes.includes(req.path) ) {
if( req.method === 'GET' && ! ignored_routes.includes(req.path) ) {
// do what you gotta do.
// next();
}
else {
next();
}
}
export default ExpressMiddleware;
And in your server/routes file
app.use( ExpressMiddleware );
Ofcourse you might have to change the code, if you're using dynamic routes.. but that shouldn't be difficult.
The only way I know of to do that is to apply the first two middlewares directly to your router with no path prefix:
router.use(middleware1, middleware2);
Then, in each of those middlewares, check the path of the URL and if it is the special path that you want to skip those middlewares for, then just call next().
if (req.path.indexOf("/somepath") === 0) { return next() };
Then, you can register your third middleware only for the path you are interested in:
router.use("/somepath", middleware3);
The first two middewares will skip the ones you want them to skip and the third one will only get called for your specific route.