express-enrouten icon indicating copy to clipboard operation
express-enrouten copied to clipboard

Directory mode: process files with index.js before all others

Open sixlettervariables opened this issue 10 years ago • 19 comments

This PR changes the default behavior of express-enrouten to process files in directory mode alphabetically (explicitly) and to process index.js before all other files. This allows slightly more predictable route handling as structures get more complex. With this change, routes which must go earlier can be put into index.js for the given level.

Old behavior:

[development] Listening on http://localhost:8000
[router] GET      /about/                                  (./controllers/about.js)
[router] POST     /amz-ses/                                (./controllers/amz-ses.js)
[router] GET      /ecgs/:ecg                               (./controllers/ecgs/index.js)
[router] POST     /ecgs/:ecg                               (./controllers/ecgs/index.js)
[router] POST     /ecgs/:ecg/tags                          (./controllers/ecgs/index.js)
[router] POST     /ecgs/:ecg/signature                     (./controllers/ecgs/index.js)
[router] POST     /ecgs/:ecg/uploaded                      (./controllers/ecgs/index.js)
[router] GET      /                                        (./controllers/index.js)
[router] GET      /success                                 (./controllers/index.js)
[router] GET      /login/                                  (./controllers/login/index.js)
[router] POST     /login/                                  (./controllers/login/index.js)
[router] GET      /login/reset/                            (./controllers/login/reset.js)
[router] POST     /login/reset/                            (./controllers/login/reset.js)
[router] GET      /login/reset/sent                        (./controllers/login/reset.js)
...

New behavior:

[development] Listening on http://localhost:8000
[router] GET      /                                        (./controllers/index.js)
[router] GET      /success                                 (./controllers/index.js)
[router] GET      /about/                                  (./controllers/about.js)
[router] POST     /amz-ses/                                (./controllers/amz-ses.js)
[router] GET      /ecgs/:ecg                               (./controllers/ecgs/index.js)
[router] POST     /ecgs/:ecg                               (./controllers/ecgs/index.js)
[router] POST     /ecgs/:ecg/tags                          (./controllers/ecgs/index.js)
[router] POST     /ecgs/:ecg/signature                     (./controllers/ecgs/index.js)
[router] POST     /ecgs/:ecg/uploaded                      (./controllers/ecgs/index.js)
[router] GET      /login/                                  (./controllers/login/index.js)
[router] POST     /login/                                  (./controllers/login/index.js)
[router] GET      /login/reset/                            (./controllers/login/reset.js)
[router] POST     /login/reset/                            (./controllers/login/reset.js)
[router] GET      /login/reset/sent                        (./controllers/login/reset.js)
...

This may be a breaking change for some consumers if they rely on the current behavior for proper route selection (perhaps on case-insensitive file systems).

sixlettervariables avatar Aug 17 '14 22:08 sixlettervariables

Oh, this is interesting!

aredridel avatar Aug 17 '14 22:08 aredridel

This dovetails nicely into #35, specifically the discussion around swaggerize-express. I would like to see the two converge on solution since it will be a breaking change either way.

totherik avatar Aug 18 '14 16:08 totherik

I'll admit I'm relatively new to the node game, so some of the frameworks are foreign to me. If my understanding of swagger is correct, it basically is a configuration-convention to REST mapper. Is your idea of the perfect world in Kraken:

  1. express-enrouten handles directory routes like swaggerize-express, or...
  2. express-enrouten/swaggerize-express merge (you could swap out enrouten for swaggerize today via config.json updates I believe)

If you're looking for option 1, I can probably put that together tonight.

sixlettervariables avatar Aug 18 '14 17:08 sixlettervariables

I was more thinking that the traversal implementation be pulled into a separate module that can be reference by both enrouten and swagger. I think that module would then need to include the changes suggested here to introduce an ordering algorithm when file are scanned an loaded.

totherik avatar Aug 18 '14 17:08 totherik

So I've cobbled together what could be the base for this as a gist. It appears to match the behavior of a hybrid expresss-enrouten/swaggerize-express. It supports an options hash which can tell it to exclude dotfiles, and the user can provide a predicate to filter files.

Basically:

var routes = routeifyDirectory('./controllers');
Object.keys(routes).forEach(function (fn) {
  console.log('%s (%s)', lpad(routes[fn], 30), fn);
});

Looks like:

/                              (controllers\index.js)
/about                         (controllers\about.js)
/admin                         (controllers\admin.js)
/companies/:company            (controllers\companies\{company}.js)
/contact                       (controllers\contact.js)
/login                         (controllers\login\index.js)
/login/reset                   (controllers\login\reset.js)
/logout                        (controllers\logout.js)
/products/:product/update      (controllers\products\{product}\update.js)
/products/:product             (controllers\products\{product}.js)
/products                      (controllers\products.js)
/suppliers/:supplier           (controllers\suppliers\{supplier}\index.js)
/users                         (controllers\users\index.js)
/users/:user                   (controllers\users\{user}.js)

I think a useful addition would be a params folder where we could specify req.param handlers, but that's a PR for another day.

sixlettervariables avatar Aug 19 '14 21:08 sixlettervariables

~~The downfall of this approach with enrouten, is express doesn't let you get the params from your parents in the stack. I had forgotten this until attempting to convert express-enrouten this AM. Swaggerize lives by this, but enrouten controllers expect more flexibility (e.g. taking a Router and not a Route).~~

I learn something new about express every day:

var router = express.Router({ mergeParams: true })

sixlettervariables avatar Aug 20 '14 16:08 sixlettervariables

I've completed my conversion to order routes with index.js first, use swaggerize-express style file naming, and be compatible with the old style structure (minus the order of resulting routes).

The functionality is broken out into a separate file ./lib/routeify.js, which I'm not certain deserves its own npm module. A tentative look at how swaggerize-express's readhandlers.js does its directory traversal suggests I could drop this into there as were.

This is obviously a big departure from current enrouten, and perhaps should be tagged vNext.

sixlettervariables avatar Aug 21 '14 16:08 sixlettervariables

I understand the use of index.js to map / but I wonder if there is also a case for:

/car/ford.js => '/car/ford'

Such that one could optionally use /name/index.js as well as simply /name.js to map /name.

I am thinking of adding index.js as an alternate to /name.js for convenience (even though that would block index from use as a path name) for familiarity's sake.

tlivings avatar Aug 21 '14 17:08 tlivings

This is currently in place (not only in enrouten, but preserved in my update).

On Thu, Aug 21, 2014 at 1:15 PM, Trevor [email protected] wrote:

I understand the use of index.js to map / but I wonder if there is also a case for:

/car/ford.js => '/car/ford'

Such that one could optionally use /name/index.js as well as simply /name.js to map /name.

I am thinking of adding index.js as an alternate to /name.js for convenience (even though that would block index from use as a path name) for familiarity's sake.

— Reply to this email directly or view it on GitHub https://github.com/krakenjs/express-enrouten/pull/47#issuecomment-52951907 .

Christopher A. Watford [email protected]

sixlettervariables avatar Aug 21 '14 17:08 sixlettervariables

/facepalm

Right. Missed that obvious bit.

tlivings avatar Aug 21 '14 17:08 tlivings

When you stare at directories of route handlers all day, it makes your eyes water ("there has got to be a better way!").

The one problem this brings with it is you find yourself nesting handlers deeply leading to ../../../../../ madness in require statements.

sixlettervariables avatar Aug 21 '14 17:08 sixlettervariables

A nasty side effect seems to be router.param() no longer appears to work as it only affects the paths at the current level.

sixlettervariables avatar Aug 22 '14 00:08 sixlettervariables

@sixlettervariables would you be able to rebase your changes?

gabrielcsapo avatar Jul 12 '17 22:07 gabrielcsapo

Yep!

On Jul 12, 2017 18:22, "Gabriel Csapo" [email protected] wrote:

@sixlettervariables https://github.com/sixlettervariables would you be able to rebase your changes?

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/krakenjs/express-enrouten/pull/47#issuecomment-314914620, or mute the thread https://github.com/notifications/unsubscribe-auth/AH22YnYYmEZ8V6G_r0fLBvUOE94tIohQks5sNUcUgaJpZM4CYKGb .

sixlettervariables avatar Jul 12 '17 22:07 sixlettervariables

Rebased.

sixlettervariables avatar Jul 14 '17 12:07 sixlettervariables

@sixlettervariables thank you for rebasing, looking for others to get a thumbs on this to get it merged in!

gabrielcsapo avatar Jul 14 '17 22:07 gabrielcsapo

@sixlettervariables how about handling for nested routes like this?

/users                         (controllers\users\index.js)
/users/:user                   (controllers\users\{user}\index.js)
/users/:user/orders            (controllers\users\{user}\orders\index.js)

blowsie avatar Oct 02 '19 16:10 blowsie

I was unable to get this code working, it just doesnt appear to be matching

yarn remove express-enrouten
yarn add sixlettervariables/express-enrouten#order-routes

Directory

/api/enitities/1000/alerts => api/entities/{id}/alerts.js

alerts.js does not run

blowsie avatar Oct 02 '19 16:10 blowsie

I do not actively maintain any nodejs projects anymore, and my free time is lacking. If someone would like to pick this up and fix/extend it that'd be great.

sixlettervariables avatar Oct 02 '19 19:10 sixlettervariables