COMMUNITY

How does one use Routes in Express?

I’m a bit stumped as to how I should define a Route in Haxe. All good in JavaScript, but the Haxe syntax for defining a route escapes me because I have no idea how to instantiate a route. I tried all sorts of weird syntax such as

var storyRouter: Router = Express.Router().get(x, (req, res, next) -> {});

I’ve seen an example on GitHub:

but it doesn’t work for the externs I’ve generated with dts2hx.

Trying to do

router = new Router();

Results in the mother of all verbose errors (it’s 6 KB in length :smiley: ).

Managed to get this to compile:

var storyRouter: express_serve_static_core.Router = Express.Router();

But have no idea how to use it. This, for example, fails with “no suitable overload”.

storyRouter.get("/story", (req, res, next) ->
        {
            res.end("Index");
        });

I’m obviously not very good at understanding how to call externs yet.

@Kyliathy please take a look at this externs https://github.com/abedev/hxexpress/blob/master/src/express/Router.hx. It worked fine when I tried it.

The Secret is in two things

  1. @:jsRequire("express", "Router") means we need to get “Router” property of require(“express”) object.
  2. @:selfCall function new(?options : RouterOptions) : Void; means calling constructor without new keyword.
    and after compilation we’ll get something like this:
    var router = require('express').Router();

Translating the example from https://expressjs.com/en/guide/routing.html

In js we have

var router = express.Router()

In haxe, because Router is a type, it can’t be called as a function like in js, so we use a specially generated call method. The static version of call here turns out to be call_() (because there’s already another non-static method with the same name). So this line becomes

var router = express.Router.call_();

The remaining lines are relatively straight forward, however haxe has stricter function unification so if the function type is : (A, B, C) -> D, you must pass it a function with 3 parameters that returns a value of type D. TypeScript will not complain if you miss parameters, so in TS (a, b) => { ... } will work. The get and use callbacks all have 3 parameters and return Dynamic. So we add the missing parameter (next) and add return null because in haxe, Void cannot unify with Dynamic so the callbacks are expecting something to be returned

var router = express.Router.call_();

// middleware that is specific to this router
router.use(function timeLog (req, res, next) {
	js.Browser.console.log('Time: ', Date.now());
	return null;
});

router.get('/', function (req, res, next) {
	return null;
});
// define the home page route
router.get('/', function (req, res, next) {
	res.send('Birds home page');
	return null;
});
// define the about route
router.get('/about', function (req, res, next) {
	res.send('About birds');
	return null;
});

I like the pattern in the handwritten externs of using new Router() rather than call() so I’ll look into making that the default in dts2hx

Edit: Investigated automatically replacing static call() with new, turns out it doesn’t work well in the general case as this pattern is often not synonymous with new (although in this specific case it is), so I’ll keep the generator as-is

1 Like