Add subrouter functionality
See original GitHub issueInitially I wanted to disallow this entirely (avoid Express nesting nightmare), and while I still mostly lean in that direction, there are valid use cases where the DX is better to have a “subrouter” than to split routing/behavior logic across two locations. (Thanks @evanderkoogh for raising this!)
Suppose you wanted to require Authentication
header validation for all /admin/*
routes:
Before
AKA current
// src/index.js
import * as CORS from 'worktop/cors';
import * as Cache from 'worktop/cache';
import { Router, compose } from 'worktop';
import * as Projects from './routes/projects';
import * as Auth from './utils/auth';
const API = new Router;
API.prepare = compose(
// Apply CORS globally
CORS.preflight,
// Validate Auth if "/admin/*" route
async (req, res) => {
if (req.pathname.startsWith('/admin/') {
// assume this is Promise<Response | void>
return Auth.validate(req, res);
}
}
);
// The actual administrative actions
// > Authentication & Authorization handled above
API.add('GET', '/admin/projects', Projects.list);
API.add('POST', '/admin/projects', Projects.create);
Cache.listen(API.run);
After
// src/routes/admin.js
import { Router } from 'worktop';
import * as Auth from '../utils/auth';
import * as Projects from './projects';
// NOTE: Exported!
export const Admin = new Router;
// All routes in this Router must
// have valid Authentication header
Admin.prepare = Auth.validate;
API.add('GET', '/projects', Projects.list);
API.add('POST', '/projects', Projects.create);
// src/index.js
import { Router } from 'worktop';
import * as CORS from 'worktop/cors';
import * as Cache from 'worktop/cache';
import { Admin } from './routes/admin';
const API = new Router;
// Apply CORS globally
API.prepare = CORS.preflight;
// NEW – direct all "/admin/*" routes to Admin router
API.attach('/admin', Admin);
Cache.listen(API.run);
The important thing to note here is that the API.attach
method (in the last snippet) is the new proposed method. I’m also considering “mount” as the method name… or “direct” lol. I’m purposefully avoiding .all()
and .use()
here, since they’re loaded terms – more on that below.
Relatedly, this means that all /admin/*
routes must be handled by the Admin
router. In other words, doing something like this will fail/never hit the foo
or the bar
handlers.
// I WILL NEVER RUN
API.add('GET', '/admin/foo', foo);
// attach subrouter
API.attach('/admin', Admin);
// NEITHER WILL I
API.add('GET', '/admin/bar', bar);
This may seem counterintuitive for Node.js users (especially Express users) since they may be used to the stacking-router model. In worktop, every route points to a single handler – handler/middleware functions can be compose
d into a final handler, but it’s still a single handler. This new method name needs to double-down on/imply this distinction. Calling this all()
or use()
would be cause confusion since, coming from Express land, those imply that you’re attaching items that expect to work alongside / in conjunction with other handlers. This isn’t the case here – it’s a complete detour.
Open to feedback & suggestions!
Issue Analytics
- State:
- Created 2 years ago
- Reactions:6
- Comments:6 (3 by maintainers)
Top GitHub Comments
Closed by #96 and now available in
worktop@next
. Will be included in the next0.8.0
stable release.It will be mount. And it’s coming in an upcoming
@next
release, which means it’ll be part of 0.8