T
Typed Routes
Type-safe Express routes with properly typed request parameters, body, and response.
Code
typescript
1import express, {2 Request,3 Response,4 NextFunction,5 Router,6 RequestHandler,7} from "express";8 9// Type definitions10interface User {11 id: number;12 name: string;13 email: string;14 role: "admin" | "user";15 createdAt: Date;16}17 18// Typed request interfaces19interface TypedRequestBody<T> extends Request {20 body: T;21}22 23interface TypedRequestParams<T extends Record<string, string>> extends Request {24 params: T;25}26 27interface TypedRequestQuery<T> extends Request {28 query: T;29}30 31// Combined typed request32interface TypedRequest<33 TParams extends Record<string, string> = Record<string, string>,34 TBody = unknown,35 TQuery = unknown36> extends Request {37 params: TParams;38 body: TBody;39 query: TQuery;40}41 42// Response type helper43type TypedResponse<T> = Response<T>;44 45// DTO types46interface CreateUserDto {47 name: string;48 email: string;49 role?: "admin" | "user";50}51 52interface UpdateUserDto {53 name?: string;54 email?: string;55 role?: "admin" | "user";56}57 58interface UserParams {59 id: string;60}61 62interface UserQuery {63 page?: string;64 limit?: string;65 role?: "admin" | "user";66}67 68// In-memory database69const users: User[] = [];70let nextId = 1;71 72// Typed route handlers73const getUsers: RequestHandler<74 Record<string, string>,75 User[],76 unknown,77 UserQuery78> = (req, res) => {79 const { page = "1", limit = "10", role } = req.query;80 let result = users;81 82 if (role) {83 result = result.filter((u) => u.role === role);84 }85 86 const start = (parseInt(page) - 1) * parseInt(limit);87 const end = start + parseInt(limit);88 89 res.json(result.slice(start, end));90};91 92const getUserById: RequestHandler<UserParams, User | { error: string }> = (93 req,94 res95) => {96 const user = users.find((u) => u.id === parseInt(req.params.id));97 98 if (!user) {99 res.status(404).json({ error: "User not found" });100 return;101 }102 103 res.json(user);104};105 106const createUser: RequestHandler<107 Record<string, string>,108 User | { error: string },109 CreateUserDto110> = (req, res) => {111 const { name, email, role = "user" } = req.body;112 113 // Validation114 if (!name || !email) {115 res.status(400).json({ error: "Name and email are required" });116 return;117 }118 119 const newUser: User = {120 id: nextId++,121 name,122 email,123 role,124 createdAt: new Date(),125 };126 127 users.push(newUser);128 res.status(201).json(newUser);129};130 131const updateUser: RequestHandler<132 UserParams,133 User | { error: string },134 UpdateUserDto135> = (req, res) => {136 const id = parseInt(req.params.id);137 const userIndex = users.findIndex((u) => u.id === id);138 139 if (userIndex === -1) {140 res.status(404).json({ error: "User not found" });141 return;142 }143 144 users[userIndex] = { ...users[userIndex], ...req.body };145 res.json(users[userIndex]);146};147 148const deleteUser: RequestHandler<UserParams, void | { error: string }> = (149 req,150 res151) => {152 const id = parseInt(req.params.id);153 const userIndex = users.findIndex((u) => u.id === id);154 155 if (userIndex === -1) {156 res.status(404).json({ error: "User not found" });157 return;158 }159 160 users.splice(userIndex, 1);161 res.status(204).send();162};163 164// Router setup165const router = Router();166 167router.get("/", getUsers);168router.get("/:id", getUserById);169router.post("/", createUser);170router.patch("/:id", updateUser);171router.delete("/:id", deleteUser);172 173// App setup174const app = express();175app.use(express.json());176app.use("/api/users", router);177 178app.listen(3000, () => {179 console.log("Server running on http://localhost:3000");180});181 182export { app, router };Run this example locally
$ npm install express @types/express