使用自定义拦截器进行响应

发布于 2025-01-11 10:35:49 字数 2892 浏览 3 评论 0原文

我正在使用全局拦截器来获取如下响应:

{
  "data": "",
  "statusCode": int
  "message": "string"
}

所以我创建了拦截器文件

import { CallHandler, ExecutionContext, Injectable, NestInterceptor } from "@nestjs/common";
import { map, Observable } from "rxjs";

export interface Response<T> {
    data: T;
}

@Injectable()
export class TransformationInterceptor<T> implements NestInterceptor<T, Response<T>> {
    intercept(context: ExecutionContext, next: CallHandler): Observable<Response<T>> {
        return next.handle().pipe(map(data => ({ 
            data: data,
            statusCode: context.switchToHttp().getResponse().statusCode,
            message: data.message
        })));
    }
}

并将其放入我的 main.ts

在我的控制器中:

  @Patch('/:userId')
  @HttpCode(201)
  public async updateUser(    
    @Param('userId') userId: string,
    @Body() userUpdate: UpdateUserDto): Promise<any> {      
    return await this.usersService.update(userId, userUpdate);    
  }

结果是:

{
  "data": {
    "_id": "621d07d9ea0cdc600fae0f02",    
    "username": "foo",
    "name": "stringwwww",
    "__v": 0
  },
  "statusCode": 201
}

如果我想添加我的自定义消息,我需要返回一个对象,例如:

@Patch('/:userId')
  @HttpCode(201)
  public async updateUser(    
    @Param('userId') userId: string,
    @Body() userUpdate: UpdateUserDto): Promise<any> {      
    const result = await this.usersService.update(userId, userUpdate);    
    return { message: 'User updated', result };    
  }

但在这种情况下,我有两次消息并且结构不正确:

{
  "data": {
    "message": "User updated",
    "result": {
      "_id": "621d07d9ea0cdc600fae0f02",
      "username": "foo",
      "name": "stringwwww",
      "__v": 0
    }
  },
  "statusCode": 201,
  "message": "User updated"
}

如何设置自定义(可选)消息?

I can modify my interceptors like:
@Injectable()
export class TransformationInterceptor<T> implements NestInterceptor<T, Response<T>> {
    intercept(context: ExecutionContext, next: CallHandler): Observable<Response<T>> {
        return next.handle().pipe(map(data => ({ 
            data: data.res,
            statusCode: context.switchToHttp().getResponse().statusCode,
            message: data.message
        })));
    }
}

我的控制器就像:

@Patch('/:userId')
  @HttpCode(201)
  public async updateUser(    
    @Param('userId') userId: string,
    @Body() userUpdate: UpdateUserDto): Promise<any> {      
    const result = await this.usersService.update(userId, userUpdate);    
    return { message: 'User updated', res: result };    
  }

我会得到正确的形式,但我不想

return { message: 'User updated', res: result };    

为每个控制器添加

I'm using a global interceptor to get response like:

{
  "data": "",
  "statusCode": int
  "message": "string"
}

so I created the interceptor file

import { CallHandler, ExecutionContext, Injectable, NestInterceptor } from "@nestjs/common";
import { map, Observable } from "rxjs";

export interface Response<T> {
    data: T;
}

@Injectable()
export class TransformationInterceptor<T> implements NestInterceptor<T, Response<T>> {
    intercept(context: ExecutionContext, next: CallHandler): Observable<Response<T>> {
        return next.handle().pipe(map(data => ({ 
            data: data,
            statusCode: context.switchToHttp().getResponse().statusCode,
            message: data.message
        })));
    }
}

and put it into my main.ts

In my controller I have:

  @Patch('/:userId')
  @HttpCode(201)
  public async updateUser(    
    @Param('userId') userId: string,
    @Body() userUpdate: UpdateUserDto): Promise<any> {      
    return await this.usersService.update(userId, userUpdate);    
  }

and the result is:

{
  "data": {
    "_id": "621d07d9ea0cdc600fae0f02",    
    "username": "foo",
    "name": "stringwwww",
    "__v": 0
  },
  "statusCode": 201
}

If I want to add my custom message, I need to return an object like:

@Patch('/:userId')
  @HttpCode(201)
  public async updateUser(    
    @Param('userId') userId: string,
    @Body() userUpdate: UpdateUserDto): Promise<any> {      
    const result = await this.usersService.update(userId, userUpdate);    
    return { message: 'User updated', result };    
  }

but in that case I have twice message and the structure is not correct:

{
  "data": {
    "message": "User updated",
    "result": {
      "_id": "621d07d9ea0cdc600fae0f02",
      "username": "foo",
      "name": "stringwwww",
      "__v": 0
    }
  },
  "statusCode": 201,
  "message": "User updated"
}

How can I set a custom (optional) message?

I can modify my interceptors like:
@Injectable()
export class TransformationInterceptor<T> implements NestInterceptor<T, Response<T>> {
    intercept(context: ExecutionContext, next: CallHandler): Observable<Response<T>> {
        return next.handle().pipe(map(data => ({ 
            data: data.res,
            statusCode: context.switchToHttp().getResponse().statusCode,
            message: data.message
        })));
    }
}

and my controller like:

@Patch('/:userId')
  @HttpCode(201)
  public async updateUser(    
    @Param('userId') userId: string,
    @Body() userUpdate: UpdateUserDto): Promise<any> {      
    const result = await this.usersService.update(userId, userUpdate);    
    return { message: 'User updated', res: result };    
  }

and I will get the correct form, but I don't want to add

return { message: 'User updated', res: result };    

for each controller

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

遇见了你 2025-01-18 10:35:49

实现此目的的一种方法如下,但每个控制器都将绑定到固定消息

创建响应装饰器 (response.decorator.ts)

    import { SetMetadata } from '@nestjs/common'
    
    export const ResponseMessageKey = 'ResponseMessageKey'
    export const ResponseMessage = (message: string) => SetMetadata(ResponseMessageKey, message)

为响应创建常量文件 (response.constants.ts)

    export const USER_INSERTED = 'User Inserted'
    export const USER_UPDATED = 'User Updated'
    export const USER_DELETED = 'User Deleted'

将装饰器添加到您的响应中控制器设置响应消息元数据

    @Patch('/:userId')
    @HttpCode(201)
    @ResponseMessage(USER_UPDATED)
    public async updateUser(    
      @Param('userId') userId: string,
      @Body() userUpdate: UpdateUserDto
    ): Promise<any> {      
      const result = await this.usersService.update(userId, userUpdate);    
      return result;    
    }

更新您的拦截器以从控制器上设置的元数据读取响应消息并将其添加到响应中

    import { Reflector } from '@nestjs/core'

    @Injectable()
    export class TransformationInterceptor<T>
      implements NestInterceptor<T, Response<T>>
    {
      constructor(private reflector: Reflector) {}

      intercept(
        context: ExecutionContext,
        next: CallHandler
      ): Observable<Response<T>> {
        const responseMessage = this.reflector.get<string>(
          ResponseMessageKey,
          context.getHandler()
        ) ?? ''

        return next.handle().pipe(
          map((data) => ({
            data,
            statusCode: context.switchToHttp().getResponse().statusCode,
            message: responseMessage
          }))
        )
      }
    }

您可以扩展此方法以将字符串/对象列表设置为可能的响应(元数据),并基于拦截器中的响应代码,发送特定消息作为 response.message

One way to achieve this is as below, but you will be bound to a fixed message per controller

Create a response decorator (response.decorator.ts)

    import { SetMetadata } from '@nestjs/common'
    
    export const ResponseMessageKey = 'ResponseMessageKey'
    export const ResponseMessage = (message: string) => SetMetadata(ResponseMessageKey, message)

Create a constants file for your responses (response.constants.ts)

    export const USER_INSERTED = 'User Inserted'
    export const USER_UPDATED = 'User Updated'
    export const USER_DELETED = 'User Deleted'

Add the decorator to your controller to set response message metadata

    @Patch('/:userId')
    @HttpCode(201)
    @ResponseMessage(USER_UPDATED)
    public async updateUser(    
      @Param('userId') userId: string,
      @Body() userUpdate: UpdateUserDto
    ): Promise<any> {      
      const result = await this.usersService.update(userId, userUpdate);    
      return result;    
    }

Update your interceptor to read the response message from the metadata set on the controller and add it in the response

    import { Reflector } from '@nestjs/core'

    @Injectable()
    export class TransformationInterceptor<T>
      implements NestInterceptor<T, Response<T>>
    {
      constructor(private reflector: Reflector) {}

      intercept(
        context: ExecutionContext,
        next: CallHandler
      ): Observable<Response<T>> {
        const responseMessage = this.reflector.get<string>(
          ResponseMessageKey,
          context.getHandler()
        ) ?? ''

        return next.handle().pipe(
          map((data) => ({
            data,
            statusCode: context.switchToHttp().getResponse().statusCode,
            message: responseMessage
          }))
        )
      }
    }

You could extend this approach to set a list of strings/objects as possible responses (metadata), and based on response code in interceptor, send a particular message as response.message

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文