Empty params object in express.js middleware - javascript

const app = express();
var router = require('express').Router({mergeParams: true});
const payloadMiddleware = (req, resp, next) => {
console.log('A:',req.params);
const {params, query} = req;
const payload = req.body;
req.my_params = { params, query, payload };
next();
};
router.use(payloadMiddleware);
router.get('/inventory/:itemID/price', async function GetPrice(req, res, next) {
console.log('B', req.my_params);
console.log('C', req.params);
}
app.use(bodyParser.urlencoded({extended: true}));
app.use(bodyParser.json());
app.use('/', router);
server = app.listen(port);
GET /inventory/abc/price?a=1&b=2 yields
A: {} # unclear why this is empty
B: { params: {},
query: { a: '1', b: '2' },
payload: {} }
C: {itemID: 'abc'}
So I'm confused: I expect my middleware to find params in req, construct the new object, and assign it to req as my_params, then pass that to the inventory handler. And this is partially happening, in that the querystring is being parsed and then assigned in my middleware. Why is req.params === {} in my middleware function, but req.params = {itemID: 'abc'}in the GET handler itself?
There are no other routes with the same pattern, no other middleware...
Also no change is observed when I remove the options object from the second line, i.e. var router = require('express').Router();

payloadMiddleware is a generic middleware that isn't declared for any specific URL pattern containing parameters (it matches any request).
Express also doesn't know that requests passed to the middleware will eventually end up in the handler for /inventory/:itemID/price.
If you want the middleware to receive the parameters, you have to specifically use it against routes that match a pattern:
app.use('/inventory/:itemID/price', payloadMiddleware);
Or as part of the route handler:
router.get('/inventory/:itemID/price', payloadMiddleware, async function ...);

Related

add json data to middleware request

I am new to express and node, I working on a task where I want to add some json data to middleware request, here is the approach I am following:
In my middleware I want to add some details to request like current date and time and then extract the URL path. Here is the code I came up with:
var express = require('express');
var app = express();
module.exports = app.use('/some-url', function(req, res, next) {
let logdetails = {
id: "some-id",
datetime: Date.now(),
path: '/path-in-url'
}
req.logdetails= logdetails;
next();
} );
I am using module.exports so it this function is exported. But it is giving errors. Also what is the correct way to access the URL path, for example if URL is /users/john then I want to extract /john and my middleware should be applied only when URL starts with /users.
Also what is the correct way to access the URL path, for example if
URL is /users/john then I want to extract /john
If your request url is /users/john then req.path will give you the path of the request url, i.e. /users/john. To extract john, you can use named route parameters and define your route as /users/:name. After using named route parameter in your route, if your request url is /users/john, req.params.name will give you the route parameter, i.e. john. For more details, take a look at req.params on express docs
and my middleware should be applied only when URL starts with /users
following middleware will only run when request path is /users
app.use('/users', (req, res, next) => {
...
}
If you want the middleware then just export the middleware function. Not the Whole app.use part. I think app.use returns an Express object. And :param in your url will make sure that you can access that parameter. You can check out more about path patterns here
middleware.js
module.exports = function(req, res, next) {
let logdetails = {
id: "some-id",
datetime: Date.now(),
path: '/path-in-url'
}
req.logdetails= logdetails;
next();
}
Your other main.js file:
const express = require('express');
const app = express();
const middleWare = require('./middleware')
app.use('/users/:name', middleWare, (req, res)=>{
//you can access logDetails
// and the name
const name = req.params.name;//This will be john for /users/john
const logDetails = req.logdetails;
})
req.originalUrl returns the url path like shown below
// GET /search?q=something
console.dir(req.originalUrl)
// => '/search?q=something'
source: https://expressjs.com/en/api.html
Similarly, get the URL path and split the string accordingly and apply the condition you need.
Here if your originalPath is /users/john then
const result = "/users/john".split("/")
would result in ["", "users", "john"]
Check if the result[1]==="users" and write your condition in the middleware.
You don't have to export the middle ware.
middleware.js
module.exports = {
handler: (req, res, next) => {
const userName = req.params.name;
// add payload to request
next();
}
}
app.js
middleware = require("middleware");
app.use('/users/:name', middleware.handler);
Concerning URL path access you could get access using request params, e.g
app.use('/users/:name', (req, res, next) => {
const userName = req.params.name;
// add payload to request
next();
});
1. Register your specific URL - `/users/:name`, where `:name` is dynamic params e.g *john*
2. Grab params in the callback

NodeJS req.body empty in funtion nodejs - Rest API whit ExpressJs and sequelize

I'm using ExpressJS and sequelize. I need invoke two functions ("accoun.js" and "people.js") into a main function (fullaccount.js) receving data in "fullaccount.js" for submit and process in the others functions, I received ready req.body in "fullaccount.js" but in "accoun.js" and "people.js" REQ.BODY IS EMPTY
app.js
const express = require('express');
const morgan = require('morgan');
var app= express();
app.set('port',process.env.PORT || 4094);
app.use(morgan('dev'));
app.use(express.urlencoded({extended:false}));
app.use(express.json());
app.use(require('./routes/back/account.route'));
app.use(require('./routes/back/people.route'));
app.listen(app.get('port'), function(){
console.log('Working in port: '+app.get('port'));
});
fullaccount.js
const account=require( './account.ctrl');
const people= require ('./people.ctrl');
import Sequelize from 'sequelize';
export function add(req, res) {
console.log(req.body); //-> it's ready. RETURNING JSON
const {nick,pass,email,firstNam,lastName,identCard,birthDate,genderId,countryId}=req.body;
account.add({nick,pass,email},res); //=>> invoke add method from account controller return undefined
people.add({firstName,lastName,identCard,birthDate,genderId,countryId},res); //=>> invoke add method from people controller return undefined
}
account.js
import Account from '../../db/models/account.mdl';
export function add(req, res) {
console.log(req.body); // it's return undefined
};
people.js
import People from '../../db/models/people.mdl';
export function add(req, res) {
console.log(req.body); // it's return undefined
};
I don't know what the error is, I need help
req.body is undefined because you are not passing the initial request to account.add or people.add
For example, for account, you are actually passing an object that contains nick, pass and email
account.add({nick, pass, email}, res); // req.nick, req.pass, req.email are available
To avoid confusion, you should rename the req parameter in account.add to data. Good names will save you a lot of headaches. :)

chain middleware functions in custom function

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.

Node/ Express Rest API keeps entering same controller function inspite of correct mapping

I am writing a node/express rest api.
Hitting,
http://localhost:5000/api/news
and
http://localhost:5000/api/news/?id=c5f69d56be40e3b56e55d80
both give me all the news objects because it enters the same .getNews function on for both the urls.
My controller:
const NewsController = {};
const News = require('../models/news.model');
// This implementation of getNews is using Promises
NewsController.getNews = function(req, res) {
console.log('Inside getNews');
sendResponse = function(arg) {
res.json(arg);
}
const allnews = News.find({}, function(err, ns) {
sendResponse(ns);
});
};
// ES6 style
NewsController.getSingleNews = async (req, res) => {
console.log("Inside getSingleNews");
const news = await News.findById(req.params.id);
res.json[news];
};
NewsController.createNews = async (req, res) => {
const news = new News(req.body);
await news.save();
res.json[{
'status': 'item saved successfully'
}];
};
NewsController.deleteNews = async (req, res) => {
await News.findByIdAndRemove(req.params.id);
res.json[{
'status': 'item deleted successfully'
}]
};
module.exports = NewsController;
My routes.js (I am using the router at /api. So app.js has // use Router
app.use('/api', newsRoutes);
)
const express = require('express');
const router = express.Router();
var newsController = require('../controllers/NewsController')
router.get('/news', newsController.getNews);
router.get('/news/:id', newsController.getSingleNews);
router.post('/news', newsController.createNews);
router.delete('news/:id', newsController.deleteNews);
module.exports = router;
My Model
const mongoose = require('mongoose');
const { Schema } = mongoose;
const newsSchema = new Schema({
title: { type: String, required: true },
content: { type: String, required: true },
author: { type: String },
image: { type: String },
source: { type: String }
});
module.exports = mongoose.model('news', newsSchema);
The issue with your code is the way you are trying to call your endpoint. Express routes don't match query string parameters.
Having said that, your call to the news endpoint that looks like this:
http://localhost:5000/api/news/?id=c5f69d56be40e3b56e55d80
Should look like this instead:
http://localhost:5000/api/news/c5f69d56be40e3b56e55d80
That way the id parameter will get mapped to the req.params.id property inside your getSingleNews controller.
Being that the expected behavior for the way you declared your route:
router.get('/news/:id', newsController.getSingleNews);
For more information on how express routes work, check the documentation here: https://expressjs.com/en/guide/routing.html
Use /news/:id first. Your request will be redirected to the first matched url following the declaration order.
So /api/news satisfies app.get(/news)? Yep, gets redirected to that controller.
/api/news/?id=c5f69d56be40e3b56e55d80 satisfies app.get(/news)? Yep, also gets redirected to /news controller.
By the way, as your getting the id from req.params you should use /news/c5f69d56be40e3b56e55d80. If you were to get it from req.query you wouldn't need another route. /news?id=c5f69d56be40e3b56e55d80 would be perfect, you'd just need to check the existence of req.query.

Calling Express Route internally from inside NodeJS

I have an ExpressJS routing for my API and I want to call it from within NodeJS
var api = require('./routes/api')
app.use('/api', api);
and inside my ./routes/api.js file
var express = require('express');
var router = express.Router();
router.use('/update', require('./update'));
module.exports = router;
so if I want to call /api/update/something/:withParam from my front end its all find, but I need to call this from within another aspect of my NodeJS script without having to redefine the whole function again in 2nd location
I have tried using the HTTP module from inside but I just get a "ECONNREFUSED" error
http.get('/api/update/something/:withParam', function(res) {
console.log("Got response: " + res.statusCode);
res.resume();
}).on('error', function(e) {
console.log("Got error: " + e.message);
});
I understand the idea behind Express is to create routes, but how do I internally call them
The 'usual' or 'correct' way to handle this would be to have the function you want to call broken out by itself, detached from any route definitions. Perhaps in its own module, but not necessarily. Then just call it wherever you need it. Like so:
function updateSomething(thing) {
return myDb.save(thing);
}
// elsewhere:
router.put('/api/update/something/:withParam', function(req, res) {
updateSomething(req.params.withParam)
.then(function() { res.send(200, 'ok'); });
});
// another place:
function someOtherFunction() {
// other code...
updateSomething(...);
// ..
}
This is an easy way to do an internal redirect in Express 4:
The function that magic can do is: app._router.handle()
Testing: We make a request to home "/" and redirect it to otherPath "/other/path"
var app = express()
function otherPath(req, res, next) {
return res.send('ok')
}
function home(req, res, next) {
req.url = '/other/path'
/* Uncomment the next line if you want to change the method */
// req.method = 'POST'
return app._router.handle(req, res, next)
}
app.get('/other/path', otherPath)
app.get('/', home)
I've made a dedicated middleware for this : uest.
Available within req it allows you to req.uest another route (from a given route).
It forwards original cookies to subsequent requests, and keeps req.session in sync across requests, for ex:
app.post('/login', async (req, res, next) => {
const {username, password} = req.body
const {body: session} = await req.uest({
method: 'POST',
url: '/api/sessions',
body: {username, password}
}).catch(next)
console.log(`Welcome back ${session.user.firstname}!`
res.redirect('/profile')
})
It supports Promise, await and error-first callback.
See the README for more details
Separate your app and server files with the app being imported into the server file.
In the place you want to call your app internally, you can import you app as well as 'request' from 'supertest'. Then you can write
request(app).post('/someroute').send({
id: 'ecf8d501-5abe-46a9-984e-e081ac925def',
etc....
});`
This is another way.
const app = require('express')()
const axios = require('axios')
const log = console.log
const PORT = 3000
const URL = 'http://localhost:' + PORT
const apiPath = (path) => URL + path
app.get('/a', (req, res) => {
res.json('yoy')
})
app.get('/b', async (req, res) => {
let a = await axios.get(apiPath('/a'))
res.json(a.data)
})
app.listen(PORT)

Categories