I am writing a middleware to check for authentication of a user, and want to shorten the amount of repetetive code by writing one function for the entire Router class.
Here's how I do it:
const express = require('express')
express.Router.checkAuthorization = (address) => {
return function(req, res, next) {
if(req.session.user)
next()
else
Router.redirect(res, address, 401)
}
}
What's more interesting, is that I route Router.redirect using the same principle, and it works just fine:
express.Router.redirect = (res, path, status) => {
res.status(status || 308)
res.redirect(path)
}
Albeit, when using it in an instance of a router, it says that checkAuthorization is not a function, even though when I console.log it, it says that it is an anonymous function.
Here's how I do it:
const { Router } = require('express')
router.get('/profile', Router.checkAuthorization('/authorize'),
controller.displayUserProfile)
Why doesn't it recognize it as a function?
Related
I have a "/" route on my "events" router and the controller for that route just sends all event documents. I tried implementing another route so I can send only future events. The route is very similar to the base "/" but every time I try to call it I get a 403. I would even change it so that it's literally the same functionality as the "/" route or very similar and I would still get 403. I don't understand why the base route works but not this one. I tested it with a post instead of get it worked that time, but I don't understand why, because of how similar the controllers are.
export const getEvents = async (req, res, next) => {
try {
const events = await Event.find();
res.status(200).json(events);
} catch (err) {
next(err);
}
};
export const getFuture = async (req, res, next) => {
try {
let now = moment().toISOString();
const events = await Event.find({date: { $gte: now}});
res.status(200).json(events);
} catch (err) {
next(err);
}
};
And here are the routes
router.get("/", getEvents);
router.get("/future", getFuture);
controllers are properly imported
I have the following case:
There is a list of routes in the form
var lst = ["route1/:foo", "route2/:bar", "route3/:bar/route4/:baz", ..] // this list has like 200 entries
I have the following code
app.use(lst, function (req, res) {
// here I want to know which route the middleware was invoked on
// req.route.path doesn't work unless I use app.METHOD()
// req.originalUrl would give me route1/200, instead of route1/:foo
})
What I tried so far:
Using the router stack as in app._router.stack, my routes aren't even registered there - I don't see route1/:foo, route2/:bar and route3/:bar/route4/:baz
Hook into the express router:
var Route = express.Route;
let defaultImplementation = Route.prototype.dispatch;
function foo(req, res) {
console.log('Called route ', req.route.path); // still doesn't trigger on the routes in lst, only parent routes
}
Route.prototype.dispatch = function handle(req, res, next) {
foo(req, res); // req.route is available here
defaultImplementation.call(this, req, res, next);
};
By the way, I'm passing those routes and using them along with http-proxy-middleware https://github.com/chimurai/http-proxy-middleware, so if you have any clues on how do achieve that with that library as well, I'd be very grateful as I couldn't find out.
I am trying to replicate a middleware you might have in express on an azure function.
For example:
router.get('/protectedEndpoint', secured(), function (req, res) {
where the secured() function is a middleware that will send next() if valid.
the problem with azure is it is done in the style
module.exports = function (context) {
and i am unsure of how to run a middleware with next() in this
here is a dumb example of what that function may look like:
module.exports = function () {
return function secured (req, res, next) {
if (req.user) { return next(); }
req.session.returnTo = req.originalUrl;
res.redirect('/login');
};
};
With azure function you can use azure-middleware engine to add middleware just like you do with Express. By this method you can do the same thing as you were doing with Express.
The link for this Engine is as follow azure-middlware
var MiddlewareHandler = require('azure-middleware')
module.exports = new MiddlewareHandler()
.use((ctx) => {
secured();//Your middleware function
ctx.next();
})
.use(async (ctx) => {
//Your controller or your main function script
ctx.log.info('Im called third');
ctx.done(null, { status: 200 });
})
.catch((error, ctx, msg) => {
ctx.log.info(error); // ERROR!
ctx.next();
})
.listen();
Yes well that example on the page is cryptic at best, and as it turns out, the package does not have full Typescript support yet either.
If anyone reading this is looking for a Typescript solution, you will have to embrace nested try catch statements to first verify the token (if the use case is Authentication), then proceed with the service to call any protected resources.
I have a general question on how you handle services and routes in node.js. Would you handle the response directly in the service or would you leave that to the route? Here's what i mean in code
Like this
Route
router.get('/', (req, res, next) ==> {
someService.someMethod(req, res);
});
Service
const someMethod = (req, res) => {
try {
var something = await someOtherMethod(req.body.someParameter);
return res.status(200).send(something.data);
} catch (err) {
return res.status(500).send({msg: err.message});
}
}
Or this
Router
router.get('/', (req, res, next) ==> {
try {
var something = await someService.someMethod(req.body.someParameter);
res.status(200).send(something.data);
} catch (err) {
res.status(500).send({msg: err.message})
}
});
Service
const SomeMethod = (Input) => {
return someOtherMethod(Input);
}
The first way would make the routers much simpler and cleaner especially if the use the service in multiple routes, but on the downside I always need to supply the res and req and I will run into problems if I want to use the service internally. I'm tending to the second method.
How do you design your services?
I would go for router.get('/', RootController)
const RootController = (req, res) => {
// extract what you need from the request
const param = req.body.param;
// calculate what you need in a pure function `businessLogic`
const result = businessLogic(param);
// send the response
return res.send(result);
}
This way you get a separation of concerns - your root controller is responsible only for handling / requests - getting a response for a request. All "business logic" is done in a pure function (you can easily test it without any HTTP request contexts/mocks, it can be reused somewhere else, for example in different controller).
I use the following architecture:
1. Route
2. Controller
3. Services
Your route is the one validating the input, your controller is the one handling all the logics and calling the services and returning the final result to your route.
In the express, we can just use following codes to deal with the request. The server side will send index.html when the request that isn't handled by router.
app.get('*', function (request, response){
response.sendFile(path.resolve(__dirname, '../public', 'index.html'))
})
But in koa, the following code don't work. When the request isn't handled by koa-router, it will return 404 instead of index.html.
var send = require('koa-send')
var serve = require('koa-static')
var router = require('koa-router')
var koa = require('koa')
var app = koa();
app.use(serve(__dirname+'/../public'));
app.use(function *(){
yield send(this, path.join(__dirname, '/../public/','index.html' )); })
app.use(router.routes())
following code also don't work
router
.get('*', function* () {
yield send(this, __dirname +'/../public/index.html')
})
router.get('*', async function(ctx, next) {
var html = fs.readFileSync(path.resolve('./build/index.html'));
ctx.type = 'html';
ctx.body = html;
})
this works for me
Essentially what you're trying to achieve is server-rendering.
You need to write route configuration with match & RouterContext. react-router has detailed documentation for this.
Server Rendering in react-router
In case of koa, it can roughly be done in this way.
import router from 'koa-router'
import { match, RouterContext } from 'react-router'
const koaRouter = router()
const otherRouter = () => {
return new Promise((resolve, reject) => {
match({ routes, location }, (error, redirectLocation, renderProps) => {
...
..
.
}
}
koaRouter
.use(otherRouter)
I found couple of repos online which seem pretty decent. I haven't verified them though.
breko-hub
koa-react-isomoprhic