Koa core does not include routing functionality, which needs to be implemented through middleware. The most commonly used routing middleware is @koa/router, providing powerful route definition and management capabilities.
Install routing middleware:
bashnpm install @koa/router
Basic routing usage:
javascriptconst Koa = require('koa'); const Router = require('@koa/router'); const app = new Koa(); const router = new Router(); // Define routes router.get('/', async (ctx) => { ctx.body = 'Hello Koa'; }); router.get('/users/:id', async (ctx) => { const id = ctx.params.id; ctx.body = `User ${id}`; }); router.post('/users', async (ctx) => { const user = ctx.request.body; ctx.body = { success: true, user }; }); // Register routing middleware app.use(router.routes()); app.use(router.allowedMethods()); app.listen(3000);
Route parameters:
- Path parameters:
javascriptrouter.get('/users/:id', async (ctx) => { const { id } = ctx.params; ctx.body = `User ID: ${id}`; }); // Multiple parameters router.get('/posts/:postId/comments/:commentId', async (ctx) => { const { postId, commentId } = ctx.params; ctx.body = `Post: ${postId}, Comment: ${commentId}`; });
- Query parameters:
javascriptrouter.get('/search', async (ctx) => { const { keyword, page, limit } = ctx.query; ctx.body = { keyword, page, limit }; });
- Regex routes:
javascriptrouter.get(/^\/users\/(\d+)$/, async (ctx) => { const id = ctx.params[0]; ctx.body = `User ID: ${id}`; });
Route methods:
javascriptrouter.get('/resource', handler); // GET router.post('/resource', handler); // POST router.put('/resource', handler); // PUT router.delete('/resource', handler); // DELETE router.patch('/resource', handler); // PATCH router.all('/resource', handler); // All methods
Route prefix:
javascriptconst apiRouter = new Router({ prefix: '/api/v1' }); apiRouter.get('/users', handler); // Actual path: /api/v1/users apiRouter.post('/login', handler); // Actual path: /api/v1/login app.use(apiRouter.routes());
Route nesting:
javascriptconst userRouter = new Router({ prefix: '/users' }); userRouter.get('/', async (ctx) => { ctx.body = 'User list'; }); userRouter.get('/:id', async (ctx) => { ctx.body = `User ${ctx.params.id}`; }); const commentRouter = new Router({ prefix: '/:userId/comments' }); commentRouter.get('/', async (ctx) => { ctx.body = `Comments for user ${ctx.params.userId}`; }); userRouter.use(commentRouter.routes()); app.use(userRouter.routes());
Route middleware:
javascript// Single route middleware router.get('/protected', authMiddleware, async (ctx) => { ctx.body = 'Protected content'; }); // Multiple route middleware router.post('/admin', authMiddleware, adminMiddleware, async (ctx) => { ctx.body = 'Admin content'; } ); // Route-level middleware router.use(async (ctx, next) => { console.log('Router middleware'); await next(); });
Route grouping and modularization:
javascript// routes/users.js const Router = require('@koa/router'); const router = new Router({ prefix: '/users' }); router.get('/', async (ctx) => { ctx.body = 'User list'; }); router.get('/:id', async (ctx) => { ctx.body = `User ${ctx.params.id}`; }); module.exports = router; // app.js const userRoutes = require('./routes/users'); app.use(userRoutes.routes()); app.use(userRoutes.allowedMethods());
Route naming and redirects:
javascriptrouter.get('user', '/users/:id', async (ctx) => { ctx.body = `User ${ctx.params.id}`; }); router.redirect('/old-path', '/new-path'); router.redirect('/old-path', 'user', { id: 123 });
Error handling:
javascriptrouter.get('/error', async (ctx) => { ctx.throw(404, 'User not found'); }); // Use allowedMethods to handle disallowed methods app.use(router.allowedMethods({ throw: true, notImplemented: () => new NotImplemented(), methodNotAllowed: () => new MethodNotAllowed() }));
Best practices:
- Organize route files by functional modules
- Use route prefixes to organize API versions
- Reasonably use route middleware for permission control
- Unified error handling and response format
- Add descriptive comments to routes
- Use TypeScript to enhance type safety