Express - Custom middleware not firing as expected - javascript

So I have an express up like so:
// imports here
app.use(cors());
app.use(express.json());
app.use(express.urlencoded({extended: true}))
initRoutes(app);
app.use(responseMiddleware)
app.use("/", express.static("./client/build"));
const port = 3050;
app.listen(port, () => {})
Inside initRoutes it's the typical express routing:
const initRoutes = (app) => {
app.use("/api/users", userRoutes);
}
Inside userRoutes I have a router like so:
router.route('/')
.post(createUserValid,userService.createUser)
Both createUserValid and createUser are firing correctly. I'm expecting that after userService.createUser, responseMiddleware should be called.
What happens instead is that responseMiddleware doesn't fire. I check it using Postman and it says 'Cannot Post', but in my mock database the data gets written.
I've tried placing responseMiddleware directly after userRoutes:
router.route('/')
.post(createUserValid, userService.createUser, responseMiddleware)
I've alsto tried attaching responseMiddleware directoly to the route:
router.use(reponseMiddleware)
This is the code for userService.createUser:
createUser(req, res, next) {
userRepository.create(req.body)
req.data = userRepository.getOne(user => user.email === req.body.email);
console.log('Im here', req.data)
next();
}
I'm expecting next() to call responseMiddleware

Related

Exposing html file to express.static middleware on Replit

On Replit, rendering the html file using res.sendFile inside a app.get works perfectly fine, AND I am able to add logos, styles, and js logic file by passing in express.static middleware.
BUT when I try to also include the html as a static file passed to express.static middleware, the page does not render.
Here's the replit: https://replit.com/#yanichik/NodeJSandExpressFullCourseFCC#02-express-tutorial/app.js
Renders as expected when html passed in with res.sendFile:
const express = require('express'); const path = require('path');
const app = express();
// setup static & middleware // static -> file that server does NOT
have to change app.use(express.static(path.resolve(__dirname,
'./public')))
app.get('/', (req, res) => { res.sendFile(path.resolve(__dirname,
'./navbar-app/index.html')) })
app.all('*', (req, res) => { res.status(404).send('Resource not
found.') })
app.listen(5000, () => { console.log('Server listening on port
5000...') })
module.exports = app;
Now, DOES NOT render as expected when html passed in with express.static middleware:
const express = require('express'); const path = require('path');
const app = express();
// setup static & middleware // static -> file that server does NOT
have to change app.use(express.static(path.resolve(__dirname,
'./public')))
// app.get('/', (req, res) => { //
res.sendFile(path.resolve(__dirname, './navbar-app/index.html')) // })
app.all('*', (req, res) => { res.status(404).send('Resource not
found.') })
app.listen(5000, () => { console.log('Server listening on port
5000...') })
module.exports = app;
You have to specifically request for the statically exposed files like so:
https://baseURL.com/navbar-app/index.html
When you comment out get routes.
If you have your get route uncomented route then
https://baseurl.com
Will return the html file

Passport-Local and Express Router Issue with Imports

I have an Express.js app with a Passport-local Auth, I'm tying to implement express router to my app since it's getting really hard to debug
This is an example of my main file (app.js)
const express = require('express')
const app = express()
const passport = require('passport')
const testing = require('./routes/file')
app.use(passport.initialize())
app.use(passport.session())
app.use('/router', testing)
const initializePassport = require('./passport-config');
initializePassport.initialize(passport);
app.get('/', checkAuthenticated, (req, res) => {
let user = data.key
res.send(`Hi ${user}`)
})
app.post('/login', checkNotAuthenticated, passport.authenticate('local', {
successRedirect: '/',
failureRedirect: '/login',
failureFlash: true
}))
function checkAuthenticated(req, res, next) {
if (req.isAuthenticated()) {
return next()
}
res.redirect('/login')
}
function checkNotAuthenticated(req, res, next) {
if (req.isAuthenticated()) {
return res.redirect('/')
}
next()
}
app.listen(3000)
This is what my main file is like, this works perfectly fine
and just to make things clear, The function are to check if a user is authenticated or not, also my passport-config returns something called data.key which is basically the username of the user.
Now I've created a router here app.use('/router', testing) with the route as /router for testing purposes
Now this is my file.js that is being used by express
const express = require('express'), router = express.Router();
var bodyParser = require('body-parser');
// Handle POST requests
router.use(bodyParser.urlencoded({ extended: false }));
router.use(bodyParser.json());
router.get('/test', checkAuthenticated, (req, res) => {
let user = data.key;
res.send(`Hello ${user}, this is coming from the router`)
})
module.exports = router;
Now as expected when I open the site at localhost:3000/router/test it returns a undefined error for data.key since it's not imported and then when I comment that out the line causing the error then checkAuthenticated doesn't work, even when I'm not logged in I can get access to the page, now this is the problem, how do I fix it, I've gone through the entire express router docs I couldn't find luck there.
Thanks
Your function is not in the global scope you need to set it to global to be able to see it like:
GLOBAL.authFunction = function(){
}
Suggestion:
1- make a module for auth name it authModule.
2- import the module auth check middleware where ever you want.

Why after sending a response, node is still executing further middleware in Express?

so i have a very basic blog app made in express, and the thing is that when i respond to app.get('/') and render a home page view, the server is still responding to app.get('/:id') that is further in the code.
I didn't call next() in app.get('/'), and from what i know, when i render a view, then the rest of middleware after shouldn't get executed, so why is it executing app.get('/:id')?
const express = require('express');
const mongoose = require('mongoose');
const app = express();
// Setting up basic middleware
app.use(express.static('public'));
app.use(express.urlencoded({ extended: true }));
app.set('view engine', 'ejs');
app.set('views');
// Database things
// ...
// Home page
app.get('/', (req, res) => {
res.render('index')
})
// Get add new blog page
app.get('/add-new', (req, res) => {
res.render('addblog')
})
// Respond with single blog page
app.get('/:id', (req, res) => {
const id = req.params.id;
Blog.findById(id)
.then(data => res.render('blog', { data }))
})
// 404
app.use('/', (req, res) => {
res.render('404')
})
I did not understand properly what you meant to ask but from what I understood, I think you mean to ask that even if someone calls /123, (Here 123 is the id) the code to be executed should be
app.get('/', (req, res) => {
res.render('index')
})
If this is what you mean to ask, then that's not how it's done. Only www.yoursite.com/ request goes to app.get('/', (req, res) and any route having value after www.yoursite.com/ like www.yoursite.com/123 will go to the other route which renders single page. 1 more thing. As you have written that if you didn't call next, rest of the middleware shouldn't execute after render, that is not the case. The entire middleware has to execute unless there is an error or you call the return statement like return res.render or simply return.
your 404 Route should be :
app.get('*', function(req, res){
res.render('404');
});
every middelware you have to return something in you case:
return res.render('the-page')
without return it will not work

Express.js - Access target route details in Application-level Middleware

Background:
I have an express application with some simple routes and Router-level Middleware. I want to register an Application-Level Middleware.
The Problem
In Router-Level Middlewares. I can access req.route object. But I can not access the same object inside an Application-Level Middleware.
I can understand this, as inside Application-Level middlewares the program is not inside the route yet.
But is there any way to get req.route object or something equivalent to req.route.path inside global middlewares?
req.path or req.originalUrl contains the real url not the route path.
Example
const express = require('express');
const app = express();
const port = 3232;
app.use((req, res, next) => {
const route = req.route; // It is an application level middleware, route is null
return next();
});
app.get('/test/:someParams', (req, res) => {
const route = req.route; // can access req.route here because it is a Router-level middleware
console.log(route.path)
console.log(req.path)
return res.send('test')
});
app.listen(port, () => console.log(`Example app listening on port ${port}!`));
Output
Request: GET#localhost:3232/test/33333
/test/33333 // I don't need this.
/test/:someParams // This is what I want to get inside the Application-Level Middleware
Alternative Solution
An alternative solution to this problem can be as the following
const express = require('express');
const app = express();
const port = 3232;
function globalMiddleware(req, res, next) {
const route = req.route;
console.log(route) // can access it
return next();
}
app.use((req, res, next) => {
const route = req.route; // It is an application level middleware, route is null
return next();
});
app.get('/test/:someParams', globalMiddleware, (req, res) => {
const route = req.route; // can access req.route here because it is a Router-level middleware
});
app.listen(port, () => console.log(`Example app listening on port ${port}!`));
But injecting the same middleware to each and all of my routes does not sound like a smart solution. Specially on bigger applications.
A dump of router object
{
"path":"/test/:someParams",
"stack":[
{
"name":"globalMiddleware",
"keys":[
],
"regexp":{
"fast_star":false,
"fast_slash":false
},
"method":"get"
},
{
"name":"<anonymous>",
"keys":[
],
"regexp":{
"fast_star":false,
"fast_slash":false
},
"method":"get"
}
],
"methods":{
"get":true
}
}
the path key is the thing I want to get. Please note that req.route.path is not the same as req.path
I was having this difficulty too. I didn't find anything on the internet that would solve it so I tried to search the express code itself for what it did to find the route. Basically it is the same thing as the code below, it looks for which regexp is valid for that route. (Google Translate)
const url = req.originalUrl.split('?')[0] // Routes with query
const layer = req.app._router.stack.find(layer => {
return layer.regexp.exec(url) && layer.route
})
So you can access the original path:
console.log(layer.route.path)
What data do you expect in req.route?
you can use req.url, req.method, req.originalUrl, etc...
or in Application level middleware you can add new field to req object
req.customRoute = {yourField: "yourValue"}
and this field will available in route level middleware
You can use middleware as per request
const middleware = (req, res, next) => {
// Append what you want in req variable
req.route = "abc" // let abc
req.path = "path" // req.route.path
next();
}
You can get it here from middleware
app.get('/test/:someParams', middleware, (req, res) => {
console.log(req.params.someParams)
console.log(req.route) // "abc"
console.log(req.path) // "path"
});
For application level middleware
app.use((req, res, next) => {
req.route = "abc" // let abc
req.path = "path" // or req.route.path
next()
})

Node JS req.body undefined

I've looked through quite a bit of other posts and I'm very lost with this.
I can run a console.log(req) and get the following output
ServerResponse {
...
req:
IncomingMessage {
...
url: '/my-endpoint',
method: 'POST',
statusCode: null,
statusMessage: null,
...
body: { foo: 'bar' },
_body: true,
...
route: Route { path: '/my-endpoint', stack: [Object], methods: [Object] } },
...
Looks solid, so I would expect to do console.log(req.body) and get { foo: 'bar' } back in the console...but nope, getting undefined
After research, I found that it may be something with my app.js file and specifically with a body-parser, however, I have all of that already
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var http = require('http');
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
//Home Page Rendering
var index = require('./routes/index');
app.use('/', index);
// All other routes are kept in the `routes` module
require('./routes')(app);
module.exports = app;
routes.js
module.exports = function routing(app) {
var apiClient = require('./services/apiClient');
app.post('/get-device-info', function(err, req, res){
console.log("/get-device-info routes");
apiClient(req, res);
});
};
apiClient.js
module.exports = function callApi(req, res){
console.log(req);
console.log(req.body)
};
index.js
var express = require('express');
var router = express.Router();
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index', { title: 'Express' });
});
module.exports = router;
Here's what I've tried
app.use(express.bodyParser());
Ensuring that the incoming request is explicitly declaring application/json
Declaring body parser.json in other ways
Adding a config function
Your problem is that Express doesn't use error first callbacks for its route handlers. The below code won't work because the app.post handler doesn't have the signature (req, res) => {}. In the below code err is equal to req, req is equal to res, and res is equal to next.
// routes.js
module.exports = function routing(app) {
var apiClient = require('./services/apiClient');
app.post('/get-device-info', function(err, req, res){
console.log("/get-device-info routes");
// Assuming the request is correct
// the value of body will be the request body
console.log(res.body)
apiClient(req, res);
});
};`
There are 3 different route callback signatures you can use in Express
(req, res) => {} - This is the most basic and defines a route that just cares about the request and response
(req, res, next) => {} - This is middleware callback signature which looks like a basic route callback but, it also assigns the next object which tells Express to call the next matching route.
(err, req, res, next) => {} - This is the error handling route callback and you only need 1 per Express Router Middleware or Express App. It gets called if next(err) is called within a Route or Middleware. More specifically, if next() isn't called with a string or nothing it will skip all remaining Middleware and Routes and go straight to the error handler. You can read more about it in the Express Docs
You'll need to change the route definition to
app.post('/get-device-info', (req, res) => {
apiClient(req, res)
})
Or you could even do this
module.exports = app => {
let apiClient = require('./services/apiClient')
app.post('/get-device-info', apiClient)
}
Try this, since it worked for me.
First declare app and then the bodyParser, since bodyParser is used within app:
const app = express();
const bodyParser = require('body-parser');
Then have these lines below:
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({extended: true}))

Categories