Node.js+Express+TypeScript路由选型及相关技术问题咨询
Hey there! Great question—both routing patterns you mentioned are totally valid, but they’re designed for different scenarios and come with distinct tradeoffs. Let’s unpack this clearly:
1. 两种写法的正确性
First off, neither is "wrong"—they’re just different approaches tailored to different ecosystems:
- The first one (
router.get('/packages/:name', (req, res) => { ... })) is Express.js’s native imperative routing syntax. It’s the standard way to define routes directly in Express, tying the route path, HTTP method, and request handler together in one place. - The second one (
export const Routes = [{ method: "post", route: "/user", controller: CustomerController, action: "createUser" }]) is a declarative routing pattern, commonly used in MVC (Model-View-Controller) architectures (like the one set up bytypeorm init). It separates route definitions from the actual business logic (which lives in controllers).
2. 哪种写法更优?分场景看
The "better" choice depends on your project’s size, complexity, and architecture goals:
👉 优先选Express原生写法的场景
- Small projects/prototypes: It’s fast to set up, requires no extra layers (like controllers), and keeps all route-related code in one spot. You can iterate quickly without over-engineering.
- Simple APIs with minimal routes: If your API only has a handful of endpoints, this syntax is straightforward and avoids unnecessary abstraction.
👉 优先选TypeORM声明式写法的场景
- Medium-to-large projects: This pattern enforces separation of concerns—route definitions are centralized, and business logic lives in dedicated controller classes. This makes code easier to maintain, test, and scale, especially for teams.
- TypeScript-first projects: The declarative approach plays nicely with TypeScript’s type system. You get type safety for controllers and their methods, reducing runtime errors.
- MVC-focused architectures: If you’re building an app that follows MVC principles, this routing style aligns perfectly with separating presentation (routes), business logic (controllers), and data access (models).
3. 如何给TypeORM式路由添加自定义中间件
Adding middleware to this declarative pattern is straightforward—you just extend the route objects with a middleware array, then handle it when registering routes with Express. Here’s how:
Step 1: Update your route configuration
// routes.ts import { CustomerController } from './controllers/CustomerController'; import authMiddleware from './middleware/auth'; import validationMiddleware from './middleware/validation'; export const Routes = [ { method: "post", route: "/user", controller: CustomerController, action: "createUser", middleware: [authMiddleware, validationMiddleware] // Add your custom middleware here }, // Other routes... ];
Step 2: Register routes with middleware support
When setting up your Express app, iterate over the routes array and apply middleware before the controller action:
// app.ts import express from 'express'; import { Routes } from './routes'; const app = express(); // Register all routes Routes.forEach(route => { // Destructure route properties const { method, route: path, controller, action, middleware = [] } = route; // Apply middleware, then the controller action app[method]( path, ...middleware, // Execute middleware in order (req, res) => { const controllerInstance = new controller(); controllerInstance[action](req, res); } ); }); app.listen(3000, () => console.log('Server running on port 3000'));
This way, your middleware runs before the controller’s createUser method handles the request.
4. 两种写法的核心区别
Let’s summarize the key differences between the two patterns:
| Aspect | Express Native Routing | TypeORM Declarative Routing |
|---|---|---|
| Pattern Type | Imperative (direct commands) | Declarative (define "what" instead of "how") |
| Code Organization | Routes + handlers in one place | Routes, controllers, and middleware are separated |
| Separation of Concerns | Low (handlers mix routing and business logic) | High (routing is a mapping layer; logic lives in controllers) |
| Type Safety (TS) | Manual type annotations needed | Built-in type safety for controllers/actions |
| Scalability | Less ideal for large apps (harder to manage many routes) | Better for scaling (centralized route config, modular controllers) |
| Setup Overhead | Minimal (no extra layers) | Moderate (requires controller classes, route registration logic) |
内容的提问来源于stack exchange,提问作者PawelC




