I'm using sequelizejs, nodejs in my application. I know this will check inbuild, but I want to check manually like in if() condition.
Below is some url path
/user
/user/11d9b6130159 => user/:id
/user/11d9bdfg0159/sample => user/:id/sample
what I want is, there is Middleware, have to check current url these in app route like
if(url.parse(req.url).path === "/user"){
//some action do
}
But I'm failing remaining urls. Please suggest the way to solve. Thanks
If you really want to do the URL parsing manually then the aproach could be like this:
EDIT: Based on your comment, I modified the sample code (more than 3 levels). You can easily extend it based on your needs.
const url = require('url');
const path = ctx.request.href;
const pathName = url.parse(path).pathname;
const pathNameParts = pathName.split('/'');
if (pathNameParts && pathNameParts[1] && pathNameParts[1] === 'user') {
if (pathNameParts[2]) {
const id = pathNameParts[2]; // :id is now defined
if (pathNameParts[3] && pathNameParts[3] === 'sample') {
if (pathNameParts[4]) {
const id2 = pathNameParts[4]; // :id2 is now defined
if (pathNameParts[5] && pathNameParts[5] === 'disable') {
// do some action for /user/:id/sample/:id2/disable
} else {
// do some action for /user/:id/sample/:id2
}
} else {
// do some action for /user/:id/sample
}
} else {
// do some action for /user/:id
}
} else {
// do some action for /user
}
}
So I would do this only, if you really want to do the parsing yourself. Otherwise use something like express router or koa router. Using express router it would be like:
app.use('/user/:id', function (req, res, next) {
console.log('ID:', req.params.id);
next();
});
Related
Am trying to split koa routes into separate files.
I'm having folder structure like this for routes.
routes/
__index.js
auth.js
user.js
So if trying with method one means it's working perfectly. But going with dynamic way that is method 2 means it's not working properly. All routes getting hitting, that's not the problem, but at the same time for auth route also it's going inside middleware.isAuthorized.
Method 1
const routesToEnable = {
authRoute: require('./auth'),
userRoute: require('./user')
};
for (const routerKey in routesToEnable) {
if (routesToEnable[routerKey]) {
const nestedRouter = routesToEnable[routerKey];
if (routerKey == 'authRoute') {
router.use(nestedRouter.routes(), nestedRouter.allowedMethods());
} else {
router.use(middleware.isAuthorized, nestedRouter.routes(), nestedRouter.allowedMethods());
}
}
}
module.exports = router;
Method 2
fs.readdirSync(__dirname)
.filter(file => (file.indexOf(".") !== 0 && file !== '__index.js' && file.slice(-3) === ".js"))
.forEach(file => {
// console.info(`Loading file ${file}`);
const routesFile = require(`${__dirname}/${file}`);
switch (file) {
case 'auth.js':
router.use(routesFile.routes(), routesFile.allowedMethods());
break;
default:
router.use(middleware.isAuthorized, routesFile.routes(), routesFile.allowedMethods());
break;
}
});
module.exports = router;
How can i use method two without middleware for auth route itself. Can anyone please suggest what I'm doing wrong here. Thanks in advance.
Issue solved as by own. Previously i used to combine routes with middleware also in the same line.
router.use(middleware.isAuthorized, routesFile.routes(), routesFile.allowedMethods());
But that's the wrong way I used to define route. router.use() uses the middleware to all the routes. So now i just splitted my routes into separate router use with individual path. Mentioned in the document Koa router
Solved answer
fs.readdirSync(__dirname)
.filter(file => (file.indexOf(".") !== 0 && file !== '__index.js' && file.slice(-3) === ".js"))
.forEach(file => {
const routesFile = require(`${__dirname}/${file}`);
if (file !== 'auth.js') {
routesFile.stack.forEach(elem => { router.use(elem.path, middleware.isAuthorized); });
}
router.use(routesFile.routes(), routesFile.allowedMethods());
});
For ExpressJs and NodeJs
Assume I have 3 types of users in my application.
Based on type of user(extracting from cookie), how to serve particular folder based on condition?
Say I have 3 folders x, y and z.
I have condition which says for user_type x -> serve folder x contents.
Same with y and z.
I tried following code but it didn't worked.
function checkCookieMiddleware(req, res, next) {
const req_cookies = cookie.parse(req.headers.cookie || '');
if(req_cookies.type){
if(req_cookies.type === "X"){
express.static(basePath + "/client/x");
}
else if(req_cookies.type === "Y"){
express.static(basePath + "/client/y");
}
else {
next();
}
}
else {
next();
}
}
app.use(checkCookieMiddleware, express.static(basePath + "/client/z"));
I found this NPM package - express-dynamic-static - that looks to do what you are looking for. If you don't want to pull in another dependency, the source code for it is fairly small, you could copy it as a custom middleware yourself.
If you were to use it, then I think you code might look something like this:
const express = require('express');
const dynamicStatic = require('express-dynamic-static')();
const app = express();
app.use(dynamicStatic);
function checkCookieMiddleware(req, res, next) {
const req_cookies = cookie.parse(req.headers.cookie || '');
if (req_cookies.type) {
if (req_cookies.type === 'X') {
dynamicStatic.setPath(basePath + '/client/x');
} else if (req_cookies.type === 'Y') {
dynamicStatic.setPath(basePath + '/client/y');
} else {
// Z
dynamicStatic.setPath(basePath + '/client/z');
}
}
next();
}
app.use(checkCookieMiddleware);
I have a middleware responsible for authorization: loopback-auth-jwt, and I want to apply it to most of the endpoints, but not to all of them. Some of the endpoints should be exposed, but if a request has the access token it should be used for authentication. So I wrote a middleware, that should check the token and if it's present authorize the user, otherwise it should do nothing, so user would be treated as anonymous. It works perfectly on the local environment, though it fails on the remote server. To be honest I don't even know how to debug that. Here is my middleware (it's not 1 to 1 code, but the general concept is here):
// Define routes that should be public and not protected by auth0 by default.
const EXCLUDED_ROUTES = [
'/api/projects/',
'/api/tasks/[a-z0-9]*',
'/api/projects/(task)/[a-z0-9]*'
];
module.exports = server => {
const auth0Jwt = require('loopback-auth0-jwt');
const jwtDecode = require('jwt-decode');
const authConfig = {
// ...
};
const auth = auth0Jwt(server, authConfig);
// Check if given URL should be considered as public or private route.
// This function is working as desired.
const isPublicRoute = url => {
let isPublic = false;
EXCLUDED_ROUTES.map(route => route.replace('/', '/')).forEach(pattern => {
const regex = new RegExp(pattern);
if (regex.test(url)) {
isPublic = true;
}
});
return isPublic;
};
// Middleware that depend on the result of isPublicRoute function applies auth0 middleware or not.
const authMiddleware = async (req, res, next) => {
const path = req._parsedUrl.pathname;
if (isPublicRoute(path)) {
// validate reuqest headers
if (!(req.headers && req.headers.authorization)) return next();
// ... some additional checks
const userWithToken = await server.models.User.findOne({where: { email: userEmail }, include: ['accessTokens']});
// no token was found, so we need to login user.
if (!userWithToken.accessToken) {
accessToken = await server.models.User.login({
// data
});
}
if (accessToken) {
req.accessToken = accessToken;
next();
} else {
next();
}
} else {
// route is not public - apply auth0 middelware.
server.use(path, auth.authenticated);
next();
}
};
// apply authMiddleware
server.use(authMiddleware);
server.enableAuth();
};
So we've identified the issue. According to the loopback docs, server.use(path, auth.authenticated) will add the middleware, but since it's an express middleware it has no control on the order of the middleware execution, that's why random results were returned.
So we've moved that to middleware.json and applied this middleware in the auth stage and it works like a charm.
I'm trying to consolidate a bunch of route usage throughout my Express API, and I'm hoping there's a way I can do something like this:
const app = express()
const get = {
fetchByHostname({
name
}) {
return `hey ${name}`
}
}
const map = {
'/public/hostname/:hostname': get.fetchByHostname
}
app.use((req, res, next) => {
const url = req.originalUrl
const args = { ...req.body, ...req.query }
const method = map[url] // this won't work
const result = method(args)
return res.json({
data: result
})
})
I'm trying to avoid passing round the req and res objects and just handle the response to the client in one place. Is there an Express/Node/.js module or way to match the URL, like my map object above?
I really don't understand what you are trying to achieve, but from what i can see, your fectchByHostname({name})should be fetchByHostname(name) and you might be able to return hey $name. You should be sure you are using ES6 because with you args. Else you have to define the as in es5 args = {body: req.body, query: req.query};. Hope it helps.
hello i have a question regarding the foodme express example over github:
code:
var express = require('express');
var fs = require('fs');
var open = require('open');
var RestaurantRecord = require('./model').Restaurant;
var MemoryStorage = require('./storage').Memory;
var API_URL = '/api/restaurant';
var API_URL_ID = API_URL + '/:id';
var API_URL_ORDER = '/api/order';
var removeMenuItems = function(restaurant) {
var clone = {};
Object.getOwnPropertyNames(restaurant).forEach(function(key) {
if (key !== 'menuItems') {
clone[key] = restaurant[key];
}
});
return clone;
};
exports.start = function(PORT, STATIC_DIR, DATA_FILE, TEST_DIR) {
var app = express();
var storage = new MemoryStorage();
// log requests
app.use(express.logger('dev'));
// serve static files for demo client
app.use(express.static(STATIC_DIR));
// parse body into req.body
app.use(express.bodyParser());
// API
app.get(API_URL, function(req, res, next) {
res.send(200, storage.getAll().map(removeMenuItems));
});
i don't understand where is the api folder. it doesn't exist and i don't understand how information is going in and out from there. i can't find it.
can someone please explain this to me?
another question:
there is a resource for the restaurant
foodMeApp.factory('Restaurant', function($resource) {
return $resource('/api/restaurant/:id', {id: '#id'});
});
and in the restaurant controller there is a query:
var allRestaurants = Restaurant.query(filterAndSortRestaurants);
and the following lines:
$scope.$watch('filter', filterAndSortRestaurants, true);
function filterAndSortRestaurants() {
$scope.restaurants = [];
// filter
angular.forEach(allRestaurants, function(item, key) {
if (filter.price && filter.price !== item.price) {
return;
}
if (filter.rating && filter.rating !== item.rating) {
return;
}
if (filter.cuisine.length && filter.cuisine.indexOf(item.cuisine) === -1) {
return;
}
$scope.restaurants.push(item);
});
// sort
$scope.restaurants.sort(function(a, b) {
if (a[filter.sortBy] > b[filter.sortBy]) {
return filter.sortAsc ? 1 : -1;
}
if (a[filter.sortBy] < b[filter.sortBy]) {
return filter.sortAsc ? -1 : 1;
}
return 0;
});
};
the things that isn't clear to me is:
how is that we are giving the query just a function without even activating it.
as i understand we should have passed the query somthing like:
{id: $routeParams.restaurantId}
but we only passed a reference to a function. that doesn't make any sense.
could someone elaborate on this?
thanks again.
var API_URL = '/api/restaurant';
var API_URL_ID = API_URL + '/:id';
var API_URL_ORDER = '/api/order';
These lines are just defining string constants that are plugged into Express further down. They're not a folder.
app.get(API_URL, function(req, res, next) {
res.send(200, storage.getAll().map(removeMenuItems));
});
So this function call to app.get(API_URL... is telling Express "Look out for GET requests that are pointed at the URL (your app's domain)/api/restaurant, and execute this function to handle such a request."
"api" is not a folder.
Every requests will pass through the app.get method.
This method will respond to the routes /api/restaurant as defined in the API_URL variable.