I'm new to Express and trying to use middleware to handle a POST request. If I expose the endpoint, and make a request to the API, everything works fine.
Working Correctly
api/index.js
app.post('/api/endpoint', (req, res, next) => {
next();
});
server.js
app.use(function() {
console.log('hello'); // => hello
});
But when I try to replace the middleware function with a module that exports a function, the function never gets invoked.
Not Working
api/index.js
app.post('/api/endpoint', (req, res, next) => {
next();
});
server.js
const makeExternalRequest = require('./server/makeExternalRequest');
...
console.log(makeExternalRequest, typeof makeExternalRequest);
// => [Function] 'function'
app.use(makeExternalRequest);
server/makeExternalRequest.js
module.exports = function(err, req, res, next) {
console.log('hello', err);
}
The function in server/makeExternalRequest.js is never invoked, and nothing logs... Am I using app.use(...) incorrectly?
Express middleware requires three arguments, the third of which is a function you call when you're done to move the request along to the next handler:
module.exports = function (req, res, next) {
console.log('hello');
next();
};
Without calling the third parameter, your request will just remain pending and a response will never be sent. Also, be sure you call app.use before any handler that would return the response. If the response is sent first, then your middleware will never be reached.
Related
I know that I can chain middleware functions after passing in the route like
const express = require('express');
const router = express.Router();
router.post('/', middlewareFunction1, middlewareFunction2, controllerFunction);
module.exports = router;
I would like to know if it's possible to call only one function (called gateway)
router.post('/', gatewayFunction1);
and this function is able to chain all those methods
const controller = require('../controllers/controller');
function gatewayFunction1(request, response, next) {
// validate route
// do other middleware stuff
// call controller.function1
}
module.exports = {
gatewayFunction1,
};
Why would I do that? I was thinking about separating the middleware logic from the routes. This gateway should just get executed after routing and before calling the router.
I tried to return an array of functions (example code)
function gatewayFunction1(request, response, next) {
return [(request, response, next) => {
console.log('called middleware 1');
next();
}, (request, response, next) => {
console.log('called middleware 2');
next();
}, (request, response, next) => {
response.status(200).json({
message: 'that worked',
});
}];
}
but when I call this api route I get no response
Could not get any response
so it keeps loading forever. Is there a way to chain these middleware functions within another function?
Your gatewayFunction1 does nothing except returns an array.
Just use router.
const express = require('express');
const gatewayFunction1 = express.Router();
gatewayFunction1.use(middlewareFunction1, middlewareFunction2, controllerFunction);
module.exports = gatewayFunction1;
Then
const gatewayFunction1 = require('...'); // where you define gatewayFunction1
router.post('/', gatewayFunction1);
Middleware should be a function and you are returning an array.If next function is not called it will get stuck. I don't like the whole idea combining them but I think the best way is to import all your middleware functions in one function and call them individually then use that function as your combined middleware.
I have the following router.use calls in one of my routers
router.use("/:collection/", (req) => {
return require(`./${req.params.collection}`);
});
and that calls in this example, example.js
example.js is as follows:
const header = require("../../header"); //gets our header that declares everything
const router = header.express.Router(); //makes our router for collections requests
console.log("123");
///The Following is when a name is requested
router.get("/test", (req, res, next) => {
console.log("test");
res.json({msg:"hi"});
next();
});
module.exports = router; //makes our router avialable
you'd expect when:
http://localhost:3000/api/example/test
is request that it would write in the console something to the effect of:
123
test
and I would get the response:
{msg:"hi"}
Instead the console gets just:
123
written and there is no response.
It seems the
router.get
in the example.js is never called, can someone tell me why?
I fixed it, instead of
router.use("/:collection/", (req) => {
return require(`./${req.params.collection}`);
});
I use
router.get("/:collection", (req, res) => {
//this is my other call that will do stuff in the parent file
//we don't call next because it is already matched, otherwise we call next
});
router.use("/:collection/", (req, res, next) =>{ //says if it gets here pass on the info
router.use("/:collection/", require(`./${req.params.collection}`)); //then route
next();
});
I am trying to set up a securitycheck middleware that will run on the routes i add it to.
Middleware
function SecurityCheckHelper(req, res, next){
apiKey = req.query.apiKey;
security.securityCheck(apiKey).then(function(result) {
res.locals.Security = result.securitycheck;
console.log(res.locals.Security);
});
return next(); // go to routes
};
Route
app.get('/settings', SecurityCheckHelper,function(req, res, next) {
console.log(res.locals);
});
Its relatively straight forward I'm trying to pass result.securitycheck (which return true/false) into the /settings route. However res.locals is returning an empty object
Your calling next before you have run your securityCheck.
IOW: the next middleware is getting processed before you securityCheck has finished processing. securityCheck is async,.
Placing your next inside your then, will wait until the securityCheck has finished.
eg.
function SecurityCheckHelper(req, res, next){
apiKey = req.query.apiKey;
security.securityCheck(apiKey).then(function(result) {
res.locals.Security = result.securitycheck;
console.log(res.locals.Security);
next();
});
};
You need to interface security check promise with the callback.
function SecurityCheckHelper(req, res, next){
apiKey = req.query.apiKey;
security.securityCheck(apiKey)
.then(function(result) {
res.locals.Security = result.securitycheck;
console.log(res.locals.Security);
return next();
})
.catch(err => next(err));
};
I'm developing a rest server on Node JS with Express.
I'm trying to wrap all my endpoints in try\catch block, so a central point of error will response back to the sender with details.
My problem that response (res instance) is alive for each of the endpoints methods, but I don't know how to make it global.
try {
app.get('/webhook', function (req, res) {
webhook.register(req, res);
});
app.get('/send', function (req, res) {
sendAutoMessage('1004426036330995');
});
app.post('/webhook/subscribe', function (req, res) {
webhook.subscribe("test");
});
app.post('/webhook/unsubscribe', function (req, res) {
webhook.unsubscribe("test");
});
} catch (error) {
//response to user with 403 error and details
}
There is a library (express-async-errors) which could suit your needs.
This enables you to write async route handlers without wrapping the statements in try/catch blocks and catch them with global error handler.
To make this work you must:
1. Install the express-async-errors package
2. Import package (before the routes)
3. Set up global express error handler
4. Write async route handlers (More info about this)
Example usage:
import express from 'express';
import 'express-async-errors';
const app = express();
// route handlers must be async
app.get('/webhook', async (req, res) => {
webhook.register(req, res);
});
app.get('/send', async (req, res) => {
sendAutoMessage('1004426036330995');
});
app.post('/webhook/subscribe', async (req, res) => {
webhook.subscribe("test");
});
app.post('/webhook/unsubscribe', async (req, res) => {
webhook.unsubscribe("test");
});
// Global error handler - route handlers/middlewares which throw end up here
app.use((err, req, res, next) => {
// response to user with 403 error and details
});
try catch can not catch error asynchronously.
This will work:
app.get('/webhook', function (req, res) {
try {
//enter code here
} catch (error) {
// something here
}
});
But it is local and not the best way.
Good way is make error-handling middleware function. It is global. You need to define it after all app.use() and routes calls.
app.use(function(err, req, res, next) {
// This is error handler
});
You can send the html page with details of error to client as usual.
Also, by default, Express have built-in error handler. The error will be written to the client with stack trace (It does not work in production mode).
this kind of try catch will not catch errors when some third function is called do the best solution will use global exception handler
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.end();
});
also you have to use promises in your end point handlers
that will catch errors in any scope
I'm working in a restful service using express.js and i want to enhance the req and res variables so for example you could write something like
app.use(function (req, res, next) {
res.Ok = function (data) {
res.status(200).send(data);
};
res.InternalError = function (err) {
res.status(500).send(err);
};
});
And later
router.get('/foo', function (req, res) {
res.Ok('foo');
})
This will send 'foo' in the body of the response and set the status code to 200 and is working perfectly.
My first question is if it is possible to add such functionality without a middleware function, lets say in a property or the prototype of the app variable?
The second question is if there are performance issues if you add many functionality with middleware functions at the app level. Are this functions attached to the request and response object per request or once on the application startup?
I know the Sails framework already do this but I'm wondering if they use middleware functions as well.
I keep digging and turns out that the request and response object are exposed in express using the __proto__ property.
var express = require('express'),
app = express();
app.response.__proto__.foo = function (data) {
this.status(200).send(data);
};
And later in the router
router.get('/foo', function (req, res, next) {
res.foo('test');
});
This will print test in your browser so it is possible to add functionality without using any middleware.
Note: I'm sure there are some drawbacks to this approach (overwriting express predefined properties, for example) but for testing purposes and adding very simple functionality I think is slightly better in terms of performance.
I'm not aware of any other way than using middleware. But in my opinion you could do the following to achieve nearly the same thing.
// Some Route
router.get('/foo', function(req, res, next) {
// ...
if(err) {
res.status(500);
return next(err);
}
return res.send('ok');
});
// Another route
router.get('/bar', function(req, res, next) {
// ...
if(badUserId) {
res.status(400);
return next('Invalid userId.');
}
req.result = 'hello';
return next();
});
router.use(function(req, res) {
// I prefer to send the result in the route but an
// approach like this could work
return res.send(req.result);
});
// Error Middleware
router.use(function(err, req, res, next) {
if(res.statusCode === 500) {
// Log the error here
return res.send('Internal server error');
} else {
return res.send(err);
}
});