如何使用nestjs处理mongoose错误

时间:2018-06-14 18:45:42

标签: typescript nestjs

我按照https://docs.nestjs.com/techniques/mongodb

中的示例进行操作

问题是当出现mongoose验证错误时(例如,我有一个带有必填字段的架构但未提供):

来自games.service.ts:

  async create(createGameDto: CreateGameDto): Promise<IGame> {
    const createdGame = new this.gameModel(createGameDto);
    return await createdGame.save();
  }

save()函数返回一个Promise。

现在我在game.controller.ts

中有这个
  @Post()
  async create(@Body() createGameDto: CreateGameDto) {
    this.gamesService.create(createGameDto);
  }

处理错误然后返回具有不同http状态和json文本的响应的最佳方法是什么? 你通常会抛出HttpException但是从哪里来?如果我在promise中使用.catch()处理错误,我就不能这样做。

(刚开始使用nestjs框架)

8 个答案:

答案 0 :(得分:3)

您可以在猫鼬中使用 错误 并将其添加到 AllExceptionFilter

请参考Nest exception-filters的文档

import {
  ExceptionFilter,
  Catch,
  ArgumentsHost,
  HttpException,
  HttpStatus,
  InternalServerErrorException
} from "@nestjs/common";

@Catch()
export class AllExceptionsFilter implements ExceptionFilter {
  catch(exception: InternalServerErrorException, host: ArgumentsHost) {
    const ctx = host.switchToHttp();
    const response = ctx.getResponse();
    const request = ctx.getRequest();

    const status =
      exception instanceof HttpException
        ? exception.getStatus()
        : HttpStatus.INTERNAL_SERVER_ERROR;

    /**
     * @description Exception json response
     * @param message
     */
    const responseMessage = (type, message) => {
      response.status(status).json({
        statusCode: status,
        path: request.url,
        errorType: type,
        errorMessage: message
      });
    };

    // Throw an exceptions for either
    // MongoError, ValidationError, TypeError, CastError and Error
    if (exception.message.error) {
      responseMessage("Error", exception.message.error);
    } else {
      responseMessage(exception.name, exception.message);
    }
  }
}

您可以像这样在main.ts中添加它,但这实际上取决于您的用例。您可以在Nest.js documentation中进行检查。

async function bootstrap() {

  const app = await NestFactory.create(AppModule);

  app.useGlobalFilters(new AllExceptionsFilter());

  await app.listen(3000);
}
bootstrap();

希望有帮助。

答案 1 :(得分:2)

使用try / catch

async getUser(id: string, validateUser ?: boolean): Promise<Users> {
    try {
      const user = await this.userModel.findById(id).exec();
      if(!user && validateUser) {
        throw new UnauthorizedException();
      }else if(!user) {
        throw new HttpException(`Not found this id: ${id}`, HttpStatus.NOT_FOUND)
      }
      return user;
    } catch (err) {
      throw new HttpException(`Callback getUser ${err.message}`, HttpStatus.BAD_REQUEST);
    }

答案 2 :(得分:1)

首先,您忘记在控制器内的create方法中添加return。这是一个常见的非常令人误解的错误,我犯了上千遍,花了我几个小时来调试。

要捕获异常:

您可以尝试使用@Catch捕获MongoError。

对于我的项目,我正在执行以下操作:

import { ArgumentsHost, Catch, ConflictException, ExceptionFilter } from '@nestjs/common';
import { MongoError } from 'mongodb';

@Catch(MongoError)
export class MongoExceptionFilter implements ExceptionFilter {
  catch(exception: MongoError, host: ArgumentsHost) {
    switch (exception.code) {
      case 11000:
        // duplicate exception
        // do whatever you want here, for instance send error to client
    }
  }
}

然后您可以在控制器中像这样使用它(甚至将其用作全局/类范围的过滤器):

import { MongoExceptionFilter } from '<path>/mongo-exception.filter';

@Get()
@UseFilters(MongoExceptionFilter)
async findAll(): Promise<User[]> {
  return this.userService.findAll();
}

(在findAll()调用中,重复的异常在这里没有意义,但是您知道了)。

此外,我强烈建议您使用类验证器,如此处所述:https://docs.nestjs.com/pipes

答案 3 :(得分:1)

今天就钉

validation-error.filter.ts:

import { ArgumentsHost, Catch, RpcExceptionFilter } from '@nestjs/common';
import { Error } from 'mongoose';
import ValidationError = Error.ValidationError;

@Catch(ValidationError)
export class ValidationErrorFilter implements RpcExceptionFilter {

  catch(exception: ValidationError, host: ArgumentsHost): any {

    const ctx = host.switchToHttp(),
      response = ctx.getResponse();

    return response.status(400).json({
      statusCode: 400,
      createdBy: 'ValidationErrorFilter',
      errors: exception.errors,
    });
  }
}

main.ts:

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { ValidationErrorFilter } from './validation-error.filter';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.useGlobalFilters(new ValidationErrorFilter());
  await app.listen(process.env.PORT || 3000);
}
bootstrap();

结果:

{
  "statusCode": 400,
  "createdBy": "ValidationErrorFilter",
  "errors": {
    "dob": {
      "properties": {
        "message": "Path `dob` is required.",
        "type": "required",
        "path": "dob"
      },
      "kind": "required",
      "path": "dob"
    },
    "password": {
      "properties": {
        "message": "Path `password` is required.",
        "type": "required",
        "path": "password"
      },
      "kind": "required",
      "path": "password"
    }
  }
}

答案 4 :(得分:0)

我在申请时所做的是使用Exception Filtershttps://docs.nestjs.com/exception-filters)和try/catch

  async create(createGameDto: CreateGameDto): Promise<IGame> {
    try {
      const createdGame = new this.gameModel(createGameDto);
      return await createdGame.save();
    } catch (e) {
       // the e here would be MongoError
       throw new InternalServerException(e.message);
    }
  }

答案 5 :(得分:0)

我做了一些研究,发现这是可行的。如下创建一个Mongo异常过滤器

import { ExceptionFilter, Catch, ArgumentsHost, HttpStatus } from "@nestjs/common";
import { MongoError } from 'mongodb';
import { Response } from 'express';

@Catch(MongoError)
export class MongoExceptionFilter implements ExceptionFilter {

    catch(exception: MongoError, host: ArgumentsHost) {
        switch (exception.code) {
            case 11000:
                const ctx = host.switchToHttp();
                const response = ctx.getResponse<Response>();
                response.statusCode = HttpStatus.FORBIDDEN;
                response
                    .json({
                        statusCode: HttpStatus.FORBIDDEN,
                        timestamp: new Date().toISOString(),
                        message: 'You are already registered'
                    });
        }
    }
}

不要忘记按如下方式定义控制器方法:

@UseFilters(MongoExceptionFilter)
  @Post('signup')
  @HttpCode(HttpStatus.OK)
  async createUser(@Body() createUserDto: CreateUserDto) {
    await this.userService.create(createUserDto);
  }

希望这对某人有帮助。干杯!

答案 6 :(得分:0)

我在这里找到了解决方案,我正在使用的是两者的结合以捕获不同的错误

import { ArgumentsHost, Catch, ExceptionFilter, RpcExceptionFilter } from '@nestjs/common';
import { Error } from 'mongoose';
import { IDTOError } from '../errors/bad-request-exception.error';
import ValidationError = Error.ValidationError;
import { MongoError } from 'mongodb';


@Catch(MongoError)
export class MongoExceptionFilter implements ExceptionFilter {
  catch(exception: MongoError, host: ArgumentsHost) {
    // switch (exception.code) {
    //   case 11000:
    //   default: console.log(exception,'ALERT ERROR CATCHED');
    //     // duplicate exception
    //     // do whatever you want here, for instance send error to client


    //     /** MAIGOD */
    // }
    const ctx = host.switchToHttp(),
      response = ctx.getResponse();

    return response.status(400).json(<IDTOError>{
      statusCode: 400,
      createdBy: 'ValidationErrorFilter, Schema or Model definition',
      errors: exception,
    });

  }
}

@Catch(ValidationError)
export class ValidationErrorFilter implements RpcExceptionFilter {

  catch(exception: ValidationError, host: ArgumentsHost): any {

    const ctx = host.switchToHttp(),
      response = ctx.getResponse();

    return response.status(400).json(<IDTOError>{
      statusCode: 400,
      createdBy: 'ValidationErrorFilter, Schema or Model definition',
      errors: exception.errors,
    });
  }
}

答案 7 :(得分:0)

我使用的是Moongose,这里的解决方案或其他任何问题都不适合我;我按照文档示例进行了此操作,对我来说确实有用。

src \ filters \ mongo-exception.filter.ts

import { ArgumentsHost, Catch, ExceptionFilter, HttpStatus } from '@nestjs/common';

import * as MongooseError from 'mongoose/lib/error'; // I couldn't see the error class is being exported from Mongoose

@Catch(MongooseError)
export class MongoExceptionFilter implements ExceptionFilter {
  catch(exception: MongooseError, host: ArgumentsHost) {
    const ctx = host.switchToHttp();
    const response = ctx.getResponse();
    // const request = ctx.getRequest();

    let error;

    switch (exception.name) {
      case 'DocumentNotFoundError': {
        error = {
          statusCode: HttpStatus.NOT_FOUND,
          message: "Not Found"
        }
        break;
      }
      // case 'MongooseError': { break; } // general Mongoose error
      // case 'CastError': { break; }
      // case 'DisconnectedError': { break; }
      // case 'DivergentArrayError': { break; }
      // case 'MissingSchemaError': { break; }
      // case 'ValidatorError': { break; }
      // case 'ValidationError': { break; }
      // case 'ObjectExpectedError': { break; }
      // case 'ObjectParameterError': { break; }
      // case 'OverwriteModelError': { break; }
      // case 'ParallelSaveError': { break; }
      // case 'StrictModeError': { break; }
      // case 'VersionError': { break; }
      default: {
        error = {
          statusCode: HttpStatus.INTERNAL_SERVER_ERROR,
          message: "Internal Error"
        }
        break;
      }
    }

    response.status(error.statusCode).json(error);
  }
}

src \ main.ts

import { MongoExceptionFilter } from './filters/mongo-exception.filter';

async function bootstrap() {
  // .......

  app.useGlobalFilters(new MongoExceptionFilter); // Use Mongo exception filter

  await app.listen(3000);
}
bootstrap();