I have only one MiddleWare with next called inside, and the request-response cycle is ended even though i did not use the res.send(), how is that?
app.use("/", function (req, res, next) {
console.log(`${req.method} ${req.path} - ${req.ip}`);
next();
});
Related
var cookieParser = require('cookie-parser')
var cookieValidator = require('./cookieValidator')
var app = express()
async function validateCookies (req, res, next) {
await cookieValidator(req.cookies)
next()
}
app.use(cookieParser())
app.use(validateCookies)
// error handler
app.use(function (err, req, res, next) {
res.status(400).send(err.message)
})
app.listen(3000)
In the above code both cookieParser() and validateCookies are middlewares but the way of executing them are different. There is a function like () with cookieParser but not with validateCookies. Can someone please explain why? Sorry If I am sounding foolish.
The app.use() function takes a single parameter, which is a function reference for a function that serves as a middleware for your router in Express.
You’ve correctly included the reference to your validateCookies function without parenthesis, as you just want Express to know which function you’d like it to use as middleware, and not to execute it at the time (Express will invoke the function for you when it’s time).
cookie-parser is a bit of an outlier (and I can see from where your confusion stems). The cookieParser() function actually returns a function reference upon successful execution. This design is likely because this particular module allows developers to pass in certain values to change the resulting function’s behavior as a middleware.
const express = require('express');
const app = express();
app.use('/', (req, res, next) => {
console.log('This always runs!');
next();
});
app.use('/add-product', (req, res, next) => {
console.log('In add product middleware!');
res.send('<h1>The "Add Product" Page</h1>');
});
app.use('/', (req, res, next) => {
console.log('In another middleware!');
res.send('<h1>Hello from Express!</h1>');
});
app.listen(3000);
NodeJS / Express: what is "app.use"?
I read from this post and still confused about how the flow-of-control goes in this program.How come if I visit "localhost:3000/add-product" the result logged is "This always runs!In add product middleware!This always runs!In another middleware!"(I omitted the changeline)
Does this mean after it goes into the second app.use,and as I've learnt,each app.use(middleware) is called every time a request is sent to the server.So this process restarts,but why this time next() would result in the third app.use being called?I thought next would go into the next matching path..
The order of route is important in express
Express match route based on first come first serve basis, just like a queue.
If a route matches, then whatever function you pass as callback will get called.
In your case:
Route 1: Match every route
Route 2: Match /add-product
Route 3: Match every route
So the order of checking would be 1 -> 2 -> 3
So if I make GET CALL TO /add-product
(1) and (2) will be called
and the following log
This always runs!
In add product middleware!
While call to / will
result in (1) and (3) being called.
This always runs!
In another middleware!
Next() is just passing the control to the next middleware
Routes.js
The below code worked.
var upload= multer({ storage: storage})
app.post('/upload', [ upload.any(), function(req, res) {
console.log(req.body) // form fields
console.log(req.files) // form files
res.status(204).end()
}]);
However, I wanted to call a controller method as well which is located in my file uploadController.js
So I did this, down below.
app.post('/upload', controllers.uploadFiles.upload, [ upload.any(), function(req, res) {
console.log(req.body) // form fields
console.log(req.files) // form files
res.status(204).end()
}]);
However, what happened was that my controller was called but then uploading part failed, i.e the below part wasn't called.
console.log(req.body) // form fields
console.log(req.files) // form files
res.status(204).end()
In conclusion, either one of them (multer or controller) work, both of them don't.
What could be wrong with this?
UPDATE
Tried the below. Only controller gets called. No file uploading done.
app.post('/upload', controllers.dataUpload.upload, [ upload.any(), function(req, res, next) {
console.log(req.body) // form fields
console.log(req.files) // form files
next()
}]);
You haven't called next from the first controller. The execution ends after you call res.end(). If you want the execution to continue to the next route match, you must call next() on the first middle-ware.
You can read more about routing and middlewares in the guide: https://expressjs.com/en/guide/routing.html
Here are some quotes that might be relevant:
You need to call the next function so that the next controller is called:
More than one callback function can handle a route (make sure you specify the next object).
When you call methods on the res object, the execution is terminated and the next controller is ignored:
The methods on the response object (res) in the following table can send a response to the client, and terminate the request-response cycle. If none of these methods are called from a route handler, the client request will be left hanging.
Credits to #squgeim for helping me out with the conceptual part. According to his guidance, I figured out the issue. Below is the working code.
Routes.js
var uploadStorage = multer({ storage: storage})
app.post('/upload', controllers.uploadController.uploadFile, [uploadStorage.any(), function(req, res, next) {
console.log(req.body) // form fields
console.log(req.files) // form files
res.status(204).end()
}]);
uploadController.js
module.exports = {
uploadFile: (req, res, next) => {
//Do whatever you want over here.
next()
},
}
So basically, inside app.post argument #2, I call the controller, do whatever I want and then call next() to proceed forward to app.post arguments #3 which is calling multer and uploading file.
code below, when I visit url like this http://localhost/. It can match the first one, but when I visit http://localhost/detail-999, It match the first one again. It can not match the second one.
I want that when I visit http://localhost or http://localhost/list-1-1 can match the first one and when visit http://localhost/detail-999 can match the second one correctly...
I have no idea to fix this problem...
router.get('/|/list-:type-:page', function (req, res) {});
router.get('/detail-:itemId', function (req, res) {});
All you need is to wrap it to brackets like this:
app.get('(/|/list-:type-:page)', function (req, res) {
});
Try this:
router.get('/list/:type/:page', function (req, res, next) {});
router.get('/detail/:itemId', function (req, res, next) {});
It can be problematic designing your routes as you did. If you have params that can not be changed then you should handle the dashes in the route's action method and just do a req.params.list_name.split('-')
I'm using a expressjs 4.x to build a simple api on top of mongodb.
The api needs to serve a few sets of data:
/api/v1/datatype1
/api/v1/datatype2
For each data type, I have CRUD operations (post, get, put, delete).
The api requests would look like this:
POST /api/v1/datatype1
GET /api/v1/datatype1:_id
PUT /api/v1/datatype1:_id
DELETE /api/v1/datatype1:_id
If I create a router params like this:
dataType1ApiRouter.param("entity_id", function (req, res, next, id) {
//async db fetch here by id, then call next with fetched data
//or error if faild request/not found entity.
//let's say req.dataEntity = dataEtity; next();
} );
If I create a route like this:
dataType1ApiRouter.route("/datatype1")
.get(":entity_id", function (req, res, next) {
//expcet req.dataEntity to be fetched by the param filter.
})
.post(function(req, res, next) {
//just create an new dataType1 entity.
});
I am getting a syntax error. The route .get and .post (and other methods like those) expect just one parameter, resulting in an error:
Route.get() requires callback functions but got a [object String]
Is there a way to actually group all the "/datatype1" requests under one url declaration instead of repeating the method("datatype1:entity_id") for each method that requires the ID expect for the post method?
There isn't a clean way to do this with Router.route(), but you might consider doing this with another Router instead of a Route there. Then, you could just mount that sub-router.
Basic example, modifying the code you provided:
var mainRouter = express.Router(),
subrouter = express.Router();
subrouter.param("entity_id", function (req, res, next, id) {
// param handler attached to subrouter
});
subrouter.post('/', function(req, res, next) {
// post handler attached to base mount-point
});
subrouter.get("/:entity_id", function (req, res, next) {
// get handler attached to base mount-point/<id>
});
// here we mount the sub-router at /datatype1 on the other router
mainRouter.use('/datatype1', subrouter);
Note that this requires adding a '/' to the URL, so instead of /api/v1/datatype1[someidhere] it would be /api/v1/datatype1/someidhere