API Documentation
Complete API reference for clear-router
Table of Contents
Static Properties
routes
static routes: ArrayArray containing all registered routes with their configuration.
prefix
static prefix: stringCurrent route prefix used for grouping.
groupMiddlewares
static groupMiddlewares: Array<Function>Middleware functions currently applied at the group level.
globalMiddlewares
static globalMiddlewares: Array<Function>Middleware functions currently applied at the global level.
Static Methods
normalizePath(path)
Normalize a path by removing duplicate slashes and ensuring a leading slash.
Parameters:
path(string): Path to normalize
Returns: string - Normalized path
Example:
Router.normalizePath('/api//users/'); // Returns: '/api/users'add(methods, path, handler, middlewares)
Register a route with one or more HTTP methods.
Parameters:
methods(string | string[]): HTTP method(s) for the routepath(string): Route pathhandler(Function | Array): Route handler or [Controller, method]middlewares(Function[]): Optional middleware functions
Example:
Router.add('get', '/users', ({ res }) => res.send('Users'));
Router.add(['get', 'post'], '/data', handler);get(path, handler, middlewares)
Register a GET route.
Parameters:
path(string): Route pathhandler(Function | Array): Route handlermiddlewares(Function[]): Optional middleware functions
Example:
Router.get('/users', ({ res }) => res.json(users));
Router.get('/admin', [AdminController, 'index'], [authMiddleware]);post(path, handler, middlewares)
Register a POST route.
Parameters:
path(string): Route pathhandler(Function | Array): Route handlermiddlewares(Function[]): Optional middleware functions
Example:
Router.post('/users', ({ req, res }) => {
const user = createUser(req.body);
res.json(user);
});put(path, handler, middlewares)
Register a PUT route.
Parameters:
path(string): Route pathhandler(Function | Array): Route handlermiddlewares(Function[]): Optional middleware functions
Example:
Router.put('/users/:id', [UserController, 'update']);delete(path, handler, middlewares)
Register a DELETE route.
Parameters:
path(string): Route pathhandler(Function | Array): Route handlermiddlewares(Function[]): Optional middleware functions
Example:
Router.delete('/users/:id', ({ req, res }) => {
deleteUser(req.params.id);
res.sendStatus(204);
});patch(path, handler, middlewares)
Register a PATCH route.
Parameters:
path(string): Route pathhandler(Function | Array): Route handlermiddlewares(Function[]): Optional middleware functions
Example:
Router.patch('/users/:id', [UserController, 'patch']);options(path, handler, middlewares)
Register an OPTIONS route.
Parameters:
path(string): Route pathhandler(Function | Array): Route handlermiddlewares(Function[]): Optional middleware functions
Example:
Router.options('/api/*', ({ res }) => {
res.set('Allow', 'GET, POST, PUT, DELETE');
res.sendStatus(200);
});head(path, handler, middlewares)
Register a HEAD route.
Parameters:
path(string): Route pathhandler(Function | Array): Route handlermiddlewares(Function[]): Optional middleware functions
Example:
Router.head('/users/:id', [UserController, 'exists']);group(prefix, callback, middlewares)
Group routes under a common prefix with optional middlewares.
Parameters:
prefix(string): URL prefix for all routes in the groupcallback(Function): Sync or async function containing route definitionsmiddlewares(Function[]): Optional middleware functions
Returns: Promise<void>
Example:
Router.group(
'/api',
() => {
Router.get('/users', handler); // Becomes: /api/users
Router.get('/posts', handler); // Becomes: /api/posts
},
[apiMiddleware],
);
// Async group callback
await Router.group('/api', async () => {
await loadRoutes();
Router.get('/status', handler); // Becomes: /api/status
});
// Nested groups
Router.group('/api', () => {
Router.group('/v1', () => {
Router.get('/users', handler); // Becomes: /api/v1/users
});
});configure(options)
Configure HTTP method override behavior for POST requests.
Parameters:
options.methodOverride.enabled(boolean): Enable/disable method override supportoptions.methodOverride.bodyKeys(string | string[]): Body key(s) to inspect for method overrideoptions.methodOverride.headerKeys(string | string[]): Header key(s) to inspect for method override
When enabled, a POST request can target put, patch, delete, or post route handlers based on configured override keys.
Default keys:
- Body:
_method - Header:
x-http-method
Example:
Router.configure({
methodOverride: {
bodyKeys: ['_method', 'method'],
headerKeys: ['x-http-method', 'x-method-override'],
},
});
Router.put('/users/:id', handler);
// POST /users/12 with body { "method": "PUT" } routes to PUT handlerRouter.configure({ methodOverride: { enabled: false } });middleware(middlewares, callback)
Apply global middlewares to all routes defined within the callback.
Parameters:
middlewares(Function[]): Middleware functions to applycallback(Function): Function containing route definitions
Example:
Router.middleware([authMiddleware, logMiddleware], () => {
Router.get('/profile', handler);
Router.get('/settings', handler);
});allRoutes()
Get information about all registered routes.
Returns: Array<Route>
Route Object:
{
methods: string[], // HTTP methods
path: string, // Full route path
middlewareCount: number, // Number of middlewares
handlerType: string, // 'function' or 'controller'
handler: Handler // Original handler definition
middlewares: Middleware[] // Array of middleware functions
controllerName?: string // Controller class name (if applicable)
actionName?: string // Controller method name (if applicable)
}Example:
Router.get('/users', handler);
Router.post('/posts', [PostController, 'create'], [authMiddleware]);
const routes = Router.allRoutes();
console.log(routes);
// Output:
// [
// {
// methods: ['get'],
// path: '/users',
// middlewareCount: 0,
// handlerType: 'function'
// },
// {
// methods: ['post'],
// path: '/posts',
// middlewareCount: 1,
// handlerType: 'controller'
// }
// ]apply(router)
Apply all registered routes to an Express Router instance.
Parameters:
router(express.Router): Express Router instance
Returns: Promise<void>
Example:
const express = require('express');
const Routes = require('clear-router');
const app = express();
const router = express.Router();
// Define routes
Router.get('/hello', ({ res }) => res.send('Hello'));
// Apply to router
await Router.apply(router);
// Use in app
app.use(router);Types
HttpContext
Context object passed to route handlers.
interface HttpContext {
req: express.Request & { getBody: () => Record<string, any> };
res: express.Response;
next: express.NextFunction;
}Request body accessor behavior:
req.getBody()is always available in Express handlers.ctx.req.getBody()is always available in H3 handlers.- Returns parsed body when present, otherwise
{}.
Example:
Router.get('/users', ({ req, res, next }) => {
try {
const users = getUsers();
res.json(users);
} catch (error) {
next(error);
}
});
Router.post('/users', ({ req, res }) => {
const body = req.getBody();
res.json({ hasName: Boolean(body.name) });
});Handler Types
Function Handler
(ctx, clearRequest?) => any | Promise<any>ctx is always the first argument:
- Express:
{ req, res, next } - H3:
H3Event
clearRequest is passed as second argument and is guaranteed for controller handlers.
For callback route handlers, this is bound to the current route instance. During request execution, this instance is hydrated with:
this.ctxthis.bodythis.querythis.paramsthis.clearRequest
Controller Handler
[ControllerClass, 'methodName'];For controller instance handlers, the router hydrates request data on this before method execution:
this.bodythis.querythis.paramsthis.clearRequest
Custom Controller Pattern (Recommended)
You can extend the clear-router Controller to create an app-specific base controller and share behavior across feature controllers.
class AppController extends Controller<HttpContext> {
ok(data: any) {
this.ctx.res.json({ success: true, data });
}
get userId() {
return this.params?.id;
}
}
class UserController extends AppController {
show() {
this.ok({ id: this.userId, query: this.query });
}
}
Router.get('/users/:id', [UserController, 'show']);Benefits
- Shared helpers live in one place.
- Hydrated request state is consistently available on
this. - Feature controllers stay small and focused.
- Controller behavior is easier to test and enforce.
Static Method:
class UserController {
static index({ res }) {
res.send('Users');
}
}
Router.get('/users', [UserController, 'index']);Instance Method:
class UserController {
index({ res }) {
res.send('Users');
}
}
Router.get('/users', [UserController, 'index']);Middleware
Standard Express middleware function.
(req, res, next) => void | Promise<void>Example:
const authMiddleware = (req, res, next) => {
if (!req.headers.authorization) {
return res.status(401).json({ error: 'Unauthorized' });
}
next();
};Error Handling
All errors during route execution are automatically passed to Express error handling middleware.
Example:
// Route with potential error
Router.get('/users/:id', async ({ req, res }) => {
const user = await getUserById(req.params.id);
if (!user) {
throw new Error('User not found');
}
res.json(user);
});
// Express error handler
app.use((err, req, res, next) => {
console.error(err);
res.status(err.status || 500).json({
error: err.message,
});
});Middleware Execution Order
Middlewares are executed in the following order:
- Global middlewares (from
Router.middleware()) - Group middlewares (from
Router.group()) - Route-specific middlewares (passed to individual route methods)
Example:
const globalMw = (req, res, next) => {
console.log('Global');
next();
};
const groupMw = (req, res, next) => {
console.log('Group');
next();
};
const routeMw = (req, res, next) => {
console.log('Route');
next();
};
Router.middleware([globalMw], () => {
Router.group(
'/api',
() => {
Router.get('/users', handler, [routeMw]);
},
[groupMw],
);
});
// Execution: Global -> Group -> RouteBest Practices
1. Route Organization
// routes/users.js
export default (Routes) => {
Router.group('/users', () => {
Router.get('/', [UserController, 'index']);
Router.post('/', [UserController, 'create']);
Router.get('/:id', [UserController, 'show']);
Router.put('/:id', [UserController, 'update']);
Router.delete('/:id', [UserController, 'destroy']);
});
};
// main.js
require('./routes/users')(Routes);2. Middleware Composition
const authenticate = (req, res, next) => {
/* ... */ next();
};
const authorize = (role) => (req, res, next) => {
/* ... */ next();
};
const validate = (schema) => (req, res, next) => {
/* ... */ next();
};
Router.post(
'/admin/users',
[AdminController, 'create'],
[authenticate, authorize('admin'), validate(userSchema)],
);3. Error Handling
// Always use try-catch in async handlers
Router.get('/users/:id', async ({ req, res, next }) => {
try {
const user = await User.findById(req.params.id);
res.json(user);
} catch (error) {
next(error); // Pass to Express error handler
}
});4. Controller Organization
class UserController {
static async index({ res }) {
const users = await User.findAll();
res.json(users);
}
static async show({ req, res }) {
const user = await User.findById(req.params.id);
res.json(user);
}
static async create({ req, res }) {
const user = await User.create(req.body);
res.status(201).json(user);
}
static async update({ req, res }) {
const user = await User.update(req.params.id, req.body);
res.json(user);
}
static async destroy({ req, res }) {
await User.delete(req.params.id);
res.sendStatus(204);
}
}