0

Another way of asking is: Can you use an instance of express.Router with a normal http server? For example:

const router = require('express').Router();
router.get("/", (req, res) => console.log("Routing..."));
require("http").createServer((req, res) => { /* how to use router here?*/ }).listen(3000);

Router doesn't seem to have an 'entry point' to connect it with a basic http server, nowhere in the Express.js documentation does it address using Router outside of an express app, and I interpret the comment to this SO question to mean Router actually can't be used without the express framework because of its lack of a .listen() method.

I ask because I am writing a node module which requires API routing, and I would like the freedom for it to be dropped into any type of server. Express is just one of the routing solutions I am looking at.

Community
  • 1
  • 1
  • 1
    The router expects to be called as Express middleware. That's how you hook a router into Express. It might be possible so simulate express middleware with a plain http server, but frankly, I don't really understand why you'd do that when Express has already written code for that. You may as well just instantiate an express handler for your existing web server and then hook the router into that. That could work in your situation too. – jfriend00 Sep 04 '16 at 03:07
  • @jfriend00 The module I'm writing is not meant exclusively for my web server. It is middleware, but I don't want it to be express-exclusive middleware because I don't want to make any assumptions about the sever setup of other implementers.I am asking specifically about express.Router because it is a very clean implementation of routing, and it is the one I'm most familiar with, but if it is not possible to use it outside of express, then it won't suit my needs. – TheKingOfTyrants Sep 04 '16 at 03:27
  • You need to do some experimentation. Create a handler for a plain http server that simulates the same calling convention as express middleware and see if you can call an express router using that. You may find some properties/methods on `req` or `res` that the express router relies on, but the only way to figure this out is to try it and see where the issues are. Or, you could study the code for the express router too, though that is usually much more complicated than just stepping through an actual middleware call. – jfriend00 Sep 04 '16 at 03:33

1 Answers1

2

You can hook an Express router into a plain node.js http server while still allowing other routing for routes that aren't handled by your router. You do, however, have to create an Express app and use that object, but that Express object doesn't have to take over the web server, it can just be used only for your route. Here's how it would work:

Code for a user of your API:

// generic node.js http server created by the user of your API
const http = require('http');
const server = http.createServer(function(request, response) {
    // the user of your API has to insert a handler here
    // that gives your API a first crack at handling the http request
    libRouter(request, response, function() {
        // if this callback is called, then your API did not handle the request
        // so the owner of the web server can handle it
    });
});
server.listen(80);

Your API code:

// you create your desired Express router
const express = require('express');
const router = express.Router();

// define the handlers for your router in the usual express router fashion
router.get("/test", function(req, res) {
    res.send("Custom API handled this request");
});

// your create an Express instance 
const app = express();
// hook your router into the Express instance in the normal way
app.use("/api", router);


// define a handler function that lets the express instance
// take a crack at handling an existing http request without taking over the server
function apiHandler(req, res, done) {
    // call app.handle() to let the Express instance see the request
    return app.handle(res, res, done);
}

In this manner, your use of Express and an express router is entirely internal to your code. All you need is for an existing node.js http server to call your function apiHandler(req, res, doneFn) with the right arguments. The done callback will be called only if your api did not handle the request in which case the user of your API should then handle the request.

This example defines a route for /api/test and you can define as many /api/xxx routes as you want. You can even use multiple routers on the app object each with different prefix paths and it will check all of them.


For the record, I tried using only a router without the Express app object. I sort of got it to work, but there were issues because the req and res objects being passed to the router are not the expected enhanced Express versions of req and res (with extra methods added by Express). This seemed likely to cause trouble. To get around that safely, you'd have to reverse engineer and then duplicate a bunch of Express app object code. Since I saw no reason to actually duplicate all that when you could just use the existing app object and let it do it's normal thing, I figured it's best to do so. And, the use of Express or the Express router is entirely internal to your own API module, invisible to the outside world so there's no harm in using the existing code that works.

jfriend00
  • 683,504
  • 96
  • 985
  • 979