8

Coming from Java world, where the Servlet-based application context path is set based on the WAR file name, I am trying to understand the best practices for defining context path in Node.js.

The Node application in question has no context path defined in the code. The Express code assumes that request to get a story, for example, has URL with path of /story/1. Thus, JavaScript UI code would makes a request to http://host:port/story/1. Likewise, for the user to connect to the main app page, they would go to http://host:port/.

I would like to change the URL the user sees to http://host:port/myapp. The question is how to consistently define "myapp" as the application context. The options I am considering:

  • Defining the context in Express.js code.
  • Defining the context in Nginx proxy server.

How do I make sure that the user always sees "myapp" in the URL? Do I also need to remap all the internal requests (the ones made by the UI code) to also have '/myapp' context?

Using Nginx seems cleaner since it does not require changing the code. But can this objective be achieved through Nginx configuration alone and if so, how?

Since this is a common problem, there must be a well-defined pattern for solving it.

Michael Smolyak
  • 593
  • 2
  • 6
  • 21
  • 1
    Mostly I use Router instances and export them in `*.router.js` files. then it is really easy to have something like `app.use('/myapp/', require(myapi.router)`. I'm not sure about best practices, that's why this isn't a post. Once we had a nginx, too. then we used that. – Patrick J. S. Oct 09 '15 at 22:54

3 Answers3

5

As you said it's better to do it in nginx config for the sake of context path independence from application code.

On the nginx side, you can set the context path with location directive and then you can remove the context path from path and send the request to the application. It can be done with a rewrite directive of nginx as follows:

    location /myapp/ {
        rewrite ^/myapp/(.*)$ /$1 break;
        ...
    }

Thus, in nodejs (express) side You should suppose that the application is running under the root path (/) as you said.

1

You can use express router for this.

const express = require('express');
const app = express();
const http = require('http');
const httpServer = http.createServer(app);
const router = express.Router();
const contextPath = '/api';

router.get('/', function(req, res) {
  res.send("you've reached the API endpoint");
});

app.use(contextPath, router);
httpsServer.listen(9000));

A get request to host:9000/api/ will now return "you've reached the API endpoint".

Raj Shah
  • 766
  • 7
  • 15
0

Actually there are many ways to add context path to an existing express app. One of these ways is to take advantage of http.createServer(). In the below code, I add 2 additional apps with context paths, and a fallback app.

const http = require('http');
const express = require('express');

const printReq = req => `contextPath: ${req.theContextPath},  url: ${req.url},  originalUrl ${req.theOriginalUrl}`;

//  Your original app
const app = express();
app.get('/hello', (req, res) => res.send(`Hello original, ${printReq(req)}`))
app.get('*', (req, res) => res.send(`Default original app routing , ${printReq(req)}`))

// second app with context /app1
const app1 = express();
const contextPath1 = '/app1'
app1.get('/hello', (req, res) => res.send(`Hello app1, ${printReq(req)}`))
app1.get('*', (req, res) => res.send(`Default app1 routing, ${printReq(req)}`))

// third app with context /app2
const app2 = express();
const contextPath2 = '/app2'
app2.get('/hello', (req, res) => res.send(`Hello app2, ${printReq(req)}`))
app2.get('*', (req, res) => res.send(`Default app2 routing, ${printReq(req)}`))

const stripContextPath = (req, contextPath) => {
  req.theOriginalUrl=req.url;
  req.theContextPath=contextPath;
  req.url = req.url.replace(new RegExp('^' + contextPath), '');
}
// -----------------------------------------------------------------------------------------------------------
// create raw server
const server = http.createServer((req, res) => {
  if(req.url.startsWith(contextPath1)){
    stripContextPath(req, contextPath1);
    app1(req, res);
  }else if(req.url.startsWith(contextPath2)){
    stripContextPath(req, contextPath2);
    app2(req, res);
  }else{
    // fallback
    app(req, res);
  }
});

server.listen(3000, '0.0.0.0', () => console.log('server listening at', server.address()));

You can do some test after saving it as server.js and installing express dependency.

BTW, if you want to do it with the proxy, in addition to nginx, you can also use the node http proxy to give context path to your existing apps.

Iceberg
  • 2,744
  • 19
  • 19