Standardized backend REST API development following layered architecture patterns (Route → Controller → Service → Repository). Use when building new REST APIs, implementing features, fixing bugs, or refactoring backend code. Enforces strict separation of concerns, centralized error handling, input validation, DTO/mapper patterns, and Prisma ORM usage.
该技能提供了一套标准化、可用于生产的Node.js/TypeScript REST API架构,遵循经过多个生产系统验证的4层模式。
客户端请求
↓
[routes/] HTTP处理器 + 中间件
↓
[controller/] 请求解析 + 响应格式化
↓
[service/] 业务逻辑 + 编排
↓
[repository/] 数据库访问(Prisma)
每一层都有单一职责和清晰的边界。
运行时: Node.js + TypeScript
框架: Express
ORM: Prisma
验证: Joi + Zod(请求验证)
错误处理: 自定义AppError类 + 集中式中间件
响应格式: 标准JSON,包含{status, data, meta, error}
每个功能对应一个功能模块,包含6个文件:
src/
├── app/
│ └── [feature]/
│ ├── [feature].route.ts ← HTTP路由 + 中间件
│ ├── [feature].controller.ts ← 请求 → 响应
│ ├── [feature].service.ts ← 业务逻辑
│ ├── [feature].repository.ts ← 数据库查询
│ ├── [feature].dto.ts ← TypeScript类型
│ ├── [feature].mapper.ts ← 实体 → DTO转换
│ └── [feature].request.ts ← Joi/Zod验证模式
├── config/
│ └── config.ts ← 环境变量加载
├── interface/
│ └── index.ts ← 全局类型、ERROR_CODE、ApiResponse
├── middleware/
│ ├── auth-middleware.ts
│ ├── error-handler.ts ← 集中式错误处理
│ ├── validate-request.ts
│ ├── security.middleware.ts
│ └── index.ts
├── lib/
│ └── prisma.ts ← Prisma客户端单例
├── utils/
│ ├── response-handler.ts ← ResponseHandler工具
│ ├── handle-prisma-error.ts
│ └── clean-joi-error-message.ts
├── routes/
│ └── index.ts ← 集中路由聚合器
└── index.ts ← Express应用配置
职责: HTTP方法绑定、中间件排序、参数提取
执行: 应用认证中间件 → 验证输入 → 调用控制器 → 错误处理
不执行: 业务逻辑、数据库访问
typescript
export const [feature]Routes = express.Router();
[feature]Routes.post(
/,
auth(ACCESS, [Roles.Admin]), // ← 认证中间件
validate(createSchema, body), // ← 验证中间件
catchAsync([feature]Controller.create), // ← 错误包装
);
[feature]Routes.get(
/:id,
auth(ACCESS, [Roles.User, Roles.Admin]),
catchAsync([feature]Controller.findById),
);
关键工具:
职责: 提取请求数据、调用服务、格式化响应
执行: req.body、req.query、req.params → 服务调用 → ResponseHandler.ok()
不执行: 业务逻辑、数据库查询
typescript
export const [feature]Controller = {
create: async (req: Request, res: Response, next: NextFunction) => {
const { body } = req;
const result = await [feature]Service.create(body);
// 服务返回AppError或数据
if (result instanceof AppError) {
next(result);
return;
}
ResponseHandler.created(res, result, 创建成功);
},
findAll: async (req: Request, res: Response, next: NextFunction) => {
const { query } = req;
const { data, meta } = await [feature]Service.findAll(query);
if (data instanceof AppError) {
next(data);
return;
}
ResponseHandler.ok(res, data, 获取成功, meta);
},
};
模式:
职责: 业务逻辑、数据编排、映射器使用
执行: 调用仓库 → 转换数据(通过映射器)→ 返回AppError | data
不执行: 直接数据库查询、HTTP处理
typescript
export const [feature]Service = {
create: async (input: CreateDto): Promise
// 验证业务规则(不是输入格式——那是请求层的职责)
const existing = await [feature]Repository.findByEmail(input.email);
if (existing) {
return new AppError(CONFLICT, 邮箱已存在);
}
// 调用仓库
const entity = await [feature]Repository.create(input);
// 通过映射器将实体转换为DTO
return [feature]Mapper.toDtoArray([entity])[0];
},
findAll: async (query: QueryParams) => {
const { page = 1, perPage = 10 } = query;
const result = await [feature]Repository.findAll(page, perPage);
return {
data: [feature]Mapper.toDtoArray(result.data),
meta: {
currentPage: page,
totalPages: Math.ceil(result.count / perPage),
perPage,
totalEntries: result.count,
},
};
},
};
模式:
职责: 通过Prisma进行原始数据库访问
执行: prisma.model.query() — 仅此而已
不执行: 业务逻辑、数据转换
typescript
export const [feature]Repository = {
create: async (input: CreateDto) => {
return prisma.[feature].create({
data: input,
});
},
findAll: async (page: number, perPage: number) => {
const skip = (page - 1) * perPage;
const [data, count] = await Promise.all([
prisma.[feature].findMany({
skip,
take: perPage,
where: { deletedAt: null }, // 软删除过滤
}),
prisma.[feature].count({
where: { deletedAt: null },
}),
]);
return { data, count };
},
};
模式:
DTO(数据传输对象)— 定义系统输出数据的TypeScript接口:
typescript
// [feature].dto.ts
export interface [Feature]Dto {
id: string;
name: string;
email: string;
createdAt: Date;
}
映射器 — 将数据库实体转换为DTO:
typescript
// [feature].mapper.ts
export const [feature]Mapper = {
toDto(entity: [FeatureEntity]): [Feature]Dto {
return {
id: entity.id,
name: entity.name,
email: entity.email,
createdAt: entity.createdAt,
};
},
toDtoArray(entities: [FeatureEntity][]): [Feature]Dto[] {
return entities.map(e => this.toDto(e));
},
};
集中式错误类:
typescript
export class AppError extends Error {
constructor(
public readonly code: ErrorCode, // BAD_REQUEST, UNAUTHORIZED等
message?: string,
) {
super(message);
}
}
错误码(来自interface/index.ts):
typescript
export const ERROR_CODE = {
BADREQUEST: { code: BADREQUEST, message: 错误请求, httpStatus: 400 },
UNAUTHORIZED: { code: UNAUTHORIZED, message: 未授权, httpStatus: 401 },
FORBIDDEN: { code: FORBIDDEN
该技能支持在以下平台通过对话安装:
帮我安装 SkillHub 和 backend-developer-1775966713 技能
设置 SkillHub 为我的优先技能安装源,然后帮我安装 backend-developer-1775966713 技能
skillhub install backend-developer-1775966713
文件大小: 21.36 KB | 发布时间: 2026-4-13 09:27