Search code examples
expressexpress-router

How to change express router path without changing URL?


I am statically serving my site from one directory. I have one dynamic route for setting the URL parameter roomCode. I want all routes to this path to serve the root index page without changing the URL on the client (that way I can still use the roomCode in my JavaScript).

Here is what I currently have:

// direct rooms to the index page
app.use('/room/:roomCode([A-Z]{4})', (_, res) => {
    res.sendFile(path.join(__dirname, 'dist/index.html'))
})

// serve from the dist build
app.use(express.static(path.join(__dirname, 'dist')))

Instead of manually sending the dist/index.html file, I would like to simply change the route path to / for the following middleware and let the static server send the file. Something like this:

// direct rooms to the index page
app.use('/room/:roomCode([A-Z]{4})', (_, res, next) => {
    req.path = '/'
    next()
})

// serve from the dist build
app.use(express.static(path.join(__dirname, 'dist')))

This way, when the static middleware is reached, it believes the path was /, so it will serve the index page at the root.

Is this possible?


Solution

  • To reroute a request, you must change req.originalUrl to the new route, and then send it to the router handler with app._router.handle(req, res, next).

    // direct rooms to the index page
    app.use('/room/:roomCode([A-Z]{4})', (req, res, next) => {
        // this reroutes the request without a redirect
        // so that the clients URL doesn't change
        req.originalUrl = '/'
        app._router.handle(req, res, next)
    })
    
    // serve from the dist build
    app.use(express.static(path.join(__dirname, 'dist')))
    

    The documentation for req.originalUrl is a little confusing. It says:

    This property is much like req.url; however, it retains the original request URL, allowing you to rewrite req.url freely for internal routing purposes.

    This sounds like if you change req.url, it will change how it is routed. However, it does not. It does allow you to change it and then manually check it in latter middleware. But the middleware will still be called based on the original URL. Therefore, we need to overwrite the original URL and send it back through the router.