Question
I've got several nested routers, and would like to get access to the whole string that the request's path matched. It's a little hard to say with english, so take a look at this code:
const express = require('express')
const app = express()
const router1 = express.Router()
const router2 = express.Router()
// set up router 2 paths
router2.get('/path2/:param2', (req, res, next) => {
const someVar = req.something // the value I'll talk about in a second
return res.status(200).send({ someVar })
})
// set up router1 paths
router1.use('/path1/:param1', router2)
// connect the routers behind a base url
app.use('/api/v1', router1)
app.listen(3000, function () {
console.log('Example app listening on port 3000!')
})
If I were to make a GET request with:
curl -X GET http://localhost:3000/api/v1/path1/myparam1/path2/myparam2
I want that to return an object like this:
{
"someVar": "/api/v1/path1/:param1/path2/:param2"
}
Context
I have middleware in my app which logs the path to an elasticsearch cluster, and I'd like the cluster to group paths by the string they used to match the request, rather than the request itself. That way I can get a visual of which request endpoints are being hit the most.
// you need to set mergeParams: true on the router,
// if you want to access params from the parent router
var router1 = express.Router({mergeParams: true});
Related
I am trying to start my project via launching server.js but I am getting error:"cannot GET /"
even after I made an app.get() route in my server.js
I am using also "body-parser" as a middleware, and "cors"
server.js:
// Setup empty JS object to act as endpoint for all routes
const projectData = {};
// Require Express to run server and routes
const express = require('express');
// Start up an instance of app
const app = express();
/* Middleware*/
//Here we are configuring express to use body-parser as middle-ware.
const bodyParser = require('body-parser')
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
// Cors for cross origin allowance
const cors = require('cors');
app.use(cors());
// Initialize the main project folder
app.use(express.static('views'));
const port = 8080;
app.use(express.static('dist'));
// Setup Server
const server=app.listen(port, ()=>{console.log(`running on localhost: ${port}`)});
app.get('/all', sendData);
function sendData (request, response) {
response.send(projectData);
};
// TODO-ROUTES!
app.post('/add', Info);
function Info(req, res) {
projectData['date'] = req.body.date;
projectData['temp'] = req.body.temp;
projectData['content'] = req.body.content;
res.send(projectData);
}
module.exports = server;
I made a POST request to /add and it works. Then I call GET /all and also work. The error cannot GET / is because you are requesting an endpoint that not exists.
Just add a dummy data to your Fn() if you want to see some output on GET request wihtout making any post request
Here is my solution
app.get('/', (req, res) => {
res.redirect('/all');
})
we need this because you do not have any root URL set, so we set the root URL to redirect to /all
2nd step then we add a dummy data in the projectData
var projectData = {
date = new Date().getDate();,
temp = 10,
content="This is Test Content"
}
This way when you call 'http://localhost:8080/' you shall get redirected to http://localhost:8080/all and instead of empty {} you shall see the dummy data.
I have the following route in my express (version 4.17.1) API in a postTimecardCompany.js file:
const mongoose = require('mongoose');
const Timecard = require('./../models/timecard');
function postTimecardCompany(server) {
server.post('/api/v1/timecard/:userId', (req, res) => {
// Insert timecard data into the database
Timecard.create(data, (error, result) => {
// Check for errors
if (error) {
res.status(500).end();
return;
}
// Respond
res.status(200).send({timecardId: result._id});
});
});
}
module.exports = postTimecardCompany;
The route (among other routes) is loaded via the following mechanism by server.js file:
[
'postTimecardCompany',
'anotherRoute',
'someOtherRoute',
'andSoOn...'
].map((route) => {
require('./core/routes/' + route + '.js').call(null, server)
});
I have a middleware (in server.js file) where I check which route is being called.
server.use((req, res, next) => {
// If route is "/api/v1/timecard/:userId" do something
});
I have found various solutions which do nearly what I am looking for, but not exactly.
For example, if I post to the route with a data parameter userId value of "123f9b" then req.originalUrl gives an output of "/api/v1/timecard/123f9b."
What i'm looking to get is the original route path with the parameters in it so for a request of "/api/v1/timecard/123f9b" it would be: "/api/v1/timecard/:userId."
How do I get this functionality in express or extend express to get the original route path with parameters in the request object?
if you want to use from your approach, it's is impossible, after that your approach is not standard in express check the documentation, if you want get routes in a middleware you should try like this:
server.js
const express = require('express')
const server = express()
const postTimecardCompany = require('./routes/postTimecardCompany.js')// don't use map()
server.use("/",postTimecardCompany)//use the routes
server.listen(6565,()=>console.log(`Listening to PORT 6565`))
routes of postTimecardCompany.js
use Router of express and export router, and you can use middleware before each route you want, there are many ways to use middleware in routes, check the documentation
const express = require("express");
const router = express.Router();
const middleware = require('../middleware');//require middlewares
router.post("/api/v1/timecard/:userId", middleware,(req, res) => {
// Insert timecard data into the database
console.log(req.route.path);
});
module.exports = router;
middleware.js
module.exports = ((req, res, next) => {
console.log(req.route.path);
next()
});
Due to my shared-hosting situation, I was forced to have all incoming requests redirected to a non-80 port on localhost, which I did through htaccess. This mutates the HTTP host header to always say localhost, no matter what subdomain I try to request. Simple enough, I found a workaround to use x-forwarded-host instead, but this means that I'm not able to rely on any of the Express subdomain middleware packages currently available on NPM, as they all rely on that host header (as far as I'm aware).
So I managed to send requests to the router. But for some reason, any request handling I try to do with the router for the specific subdomain that I have activated, won't get picked up by the router, and passes straight on through to the 404 handler.
/index.js:
const path = require('path');
const fs = require('fs');
const express = require('express');
const app = express();
const PORT = 30001;
const subdomainHosts = [];
fs.readdirSync('./routes/subdomain').filter(file => file.endsWith('.js')).forEach(host => {
subdomainHosts.push(host.split('.js')[0]);
});
const forwardSubdomain = require('./middlewares/forwardSubdomain');
app.use(forwardSubdomain(subdomainHosts));
app.use(express.static(path.join(__dirname, 'public')));
app.use((req, res, next) => {
return res.status(404).sendFile(path.join(process.cwd(), 'public/404.html'));
});
/middlewares/forwardSubdomain.js:
module.exports = (subdomainHosts) => {
return (req, res, next) => {
let host = req.headers['x-forwarded-host'] ? req.headers['x-forwarded-host'] : '';
host = host.split(':')[0].split('.example.com')[0];
const isSubdomain = (host && subdomainHosts.includes(host));
if (isSubdomain) {
const subdomainRouter = require(`../routes/subdomain/${host}.js`);
return subdomainRouter(req, res, next);
}
next();
};
};
/routes/subdomain/test.js:
const path = require('path');
const express = require('express');
const router = express.Router();
router.use(express.static(path.join(process.cwd(), 'test')));
module.exports = router;
/test/ contains a simple hello world index.html. Yet, trying to access test.example.com gives me the 404.
I'm pretty certain that I'm missing something obvious, but I've been sitting on this for a bit too long, hence the cry for help.
With this very simple app:
const express = require('express');
const app = express();
const router = express.Router();
const port = 8080;
router.get('/test', (req, res) => {
res.send('Test was hit')
})
// binds router to express app
app.use('/root', router);
app.listen(port, () => logger.info(`Listening on port: ${port}`));
After running curl http://localhost:8080/root/test, unsurprisingly, the response is Test was hit
I am to make this much more generic and wish for the consumer to be able to hit curl http://localhost:8080/<whatever-the-consumer-specifies>/test and still hit the routers /test endpoint.
However, if I replace the binding to be as follows:
app.use('/*',router);
After a subsequent hit the response is Cannot GET /root/test
How can I instead achieve this?
* EDIT: *
Of course I could do:
router.get('*/test', (req, res) => {
res.send('Test was hit')
})
However - This is not the answer that I seek, I only want this configuration take place once in the project.
Express allows the use of regular expression in the router middleware as mentioned in the docs here.
app.use(/\/\w+/, router);
You could replace the string and place a regex in the first argument.
I am having difficulty making a route like this as I am new in express routing:
GET users's exercise log: GET
/api/exercise/log?{userId}[&from][&to][&limit]
{ } = required, [ ] = optional
from, to = dates (yyyy-mm-dd); limit = number
I don't understand what's that ? and & on the route for? what i see on youtube are routes like this:
app.route('/api/exercise/log/:userId').post(exercisehandler);
I want to make a route like this:
GET /api/exercise/log?userId=1234&from=2018-01-01&to=2018-07-23&limit=100
I am looking on the routing doc on express but I still want to get an idea here so i can get this done quicker. help?
You could do it this way:
const express = require("express")
const app = express()
const port = 3000
app.route("/api/exercise/log/:userId").get((req, res) => {
console.log(req.params)
console.log(req.query)
// ...
})
app.listen(port, () => console.log(`Listening on port ${port}!`))
and the GET request:
GET /api/exercise/log/1234?from=2018-01-01&to=2018-07-23&limit=100