如何在NestJS中将Prisma结果转为自定义模型返回?支持全局配置吗?
在NestJS中全局统一响应格式(适配Prisma查询结果)
针对你需要将Prisma查询结果统一包装成指定响应结构的需求,NestJS提供了全局拦截器的方案,能一次性解决所有接口的响应格式统一问题,无需在每个接口中手动处理。
一、创建全局响应拦截器
拦截器是NestJS处理请求/响应生命周期的核心组件,正好用来统一包装返回结果。
- 新建拦截器文件
src/common/interceptors/transform.interceptor.ts:
import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common'; import { Observable } from 'rxjs'; import { map } from 'rxjs/operators'; import { Reflector } from '@nestjs/core'; // 自定义装饰器:用于设置接口的响应消息 export const ResponseMessage = (message: string) => Reflector.createDecorator<string>({ key: 'responseMessage', }); @Injectable() export class TransformInterceptor implements NestInterceptor { constructor(private reflector: Reflector) {} intercept(context: ExecutionContext, next: CallHandler): Observable<any> { // 默认响应消息 const defaultMsg = '操作成功'; // 从控制器方法上获取自定义消息 const message = this.reflector.get<string>('responseMessage', context.getHandler()) || defaultMsg; // 获取当前响应状态码 const statusCode = context.switchToHttp().getResponse().statusCode; return next.handle().pipe( map(data => { // 统一包装成目标响应结构 return { status: statusCode, message, data: { // 根据返回数据类型自动适配字段:单条数据用user,列表用list,可按需调整 [typeof data === 'object' && !Array.isArray(data) ? 'user' : 'list']: data } }; }), ); } }
二、全局注册拦截器
有两种方式将拦截器全局生效:
方式1:在AppModule中注册
修改 src/app.module.ts,添加全局拦截器提供者:
import { Module } from '@nestjs/common'; import { APP_INTERCEPTOR } from '@nestjs/core'; import { TransformInterceptor } from './common/interceptors/transform.interceptor'; // 导入你的其他模块(比如PrismaModule) @Module({ imports: [/* 你的业务模块、Prisma模块 */], controllers: [/* 你的控制器 */], providers: [ { provide: APP_INTERCEPTOR, useClass: TransformInterceptor, }, ], }) export class AppModule {}
方式2:在main.ts中注册
修改 src/main.ts:
import { NestFactory } from '@nestjs/core'; import { AppModule } from './app.module'; import { TransformInterceptor } from './common/interceptors/transform.interceptor'; import { Reflector } from '@nestjs/core'; async function bootstrap() { const app = await NestFactory.create(AppModule); // 注册全局拦截器 app.useGlobalInterceptors(new TransformInterceptor(app.get(Reflector))); await app.listen(3000); } bootstrap();
三、在控制器中使用
现在控制器方法可以直接返回Prisma查询结果,拦截器会自动包装成目标结构。如果需要自定义响应消息,使用@ResponseMessage装饰器即可:
import { Controller, Get, Param } from '@nestjs/common'; import { PrismaService } from './prisma.service'; import { ResponseMessage } from './common/interceptors/transform.interceptor'; @Controller('users') export class UsersController { constructor(private readonly prisma: PrismaService) {} @Get(':id') @ResponseMessage('User data retrieved') async getUser(@Param('id') id: string) { // 直接返回Prisma查询结果,无需手动包装 return this.prisma.user.findUnique({ where: { id: Number(id) }, }); } }
四、扩展优化建议
- 自定义data字段:如果不同接口需要不同的data子字段(比如
post、product),可以再创建一个@ResponseDataKey('post')装饰器,在拦截器中获取该值替换默认字段名。 - 错误响应统一:如果需要统一错误格式,可以创建全局异常过滤器,将错误信息也包装成类似结构。
- 空数据处理:在拦截器中添加逻辑,当查询结果为
null时,返回data: { user: null }这类更友好的格式。
内容的提问来源于stack exchange,提问作者Ajitesh Sivakumar
相关产品推荐
相关产品推荐

