Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

support custom error message mappings #73

Merged

Conversation

megane42
Copy link
Contributor

@megane42 megane42 commented Aug 5, 2023

resolves #72

Examples

useGlobalFilters()

// src/main.ts
import { HttpStatus } from '@nestjs/common';
import { HttpAdapterHost, NestFactory } from '@nestjs/core';
import { PrismaClientExceptionFilter } from 'nestjs-prisma';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);

  // prisma exception filter
  const { httpAdapter } = app.get(HttpAdapterHost);
  app.useGlobalFilters(
    new PrismaClientExceptionFilter(
      httpAdapter,
      // Prisma Error Code: HTTP Status Response
      {
        P2000: HttpStatus.BAD_REQUEST,
        P2002: HttpStatus.CONFLICT,
        P2025: HttpStatus.NOT_FOUND,
      },
      // Prisma Error Code: Error Message
      // You can omit some error codes (like P2002 here) so that the default messages are used.
      {
        P2000: 'something went wrong',
        P2025: 'resource not found',
      },
    ),
  );

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

APP_FILTER

// src/app.module.ts
import { HttpStatus, Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { APP_FILTER, HttpAdapterHost } from '@nestjs/core';
import { PrismaClientExceptionFilter, PrismaModule } from 'nestjs-prisma';

@Module({
  imports: [PrismaModule.forRoot()],
  controllers: [AppController],
  providers: [
    AppService,
    {
      provide: APP_FILTER,
      useFactory: ({ httpAdapter }: HttpAdapterHost) => {
        return new PrismaClientExceptionFilter(
          httpAdapter,
          {
            // Prisma Error Code: HTTP Status Response
            P2000: HttpStatus.BAD_REQUEST,
            P2002: HttpStatus.CONFLICT,
            P2025: HttpStatus.NOT_FOUND,
          },
          // Prisma Error Code: Error Message
          // You can omit some error codes (like P2002 here) so that the default messages are used.
          {
            P2000: 'something went wrong',
            P2025: 'resource not found',
          },
        );
      },
      inject: [HttpAdapterHost],
    },
  ],
})
export class AppModule {}

or

// src/app.module.ts
import { HttpStatus, Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import {
  PrismaModule,
  providePrismaClientExceptionFilter,
} from 'nestjs-prisma';

@Module({
  imports: [PrismaModule.forRoot()],
  controllers: [AppController],
  providers: [
    AppService,
    providePrismaClientExceptionFilter(
      {
        P2000: HttpStatus.BAD_REQUEST,
        P2002: HttpStatus.CONFLICT,
        P2025: HttpStatus.NOT_FOUND,
      },
      {
        P2000: 'something went wrong',
        P2025: 'resource not found',
      },
    ),
  ],
})
export class AppModule {}

Results

Before

image

After

image

Note

Only status mappings are used for judging whether or not to handle Prisma errors. Message mappings are not used for it. So if the app setting is like this:

      // status mappings
      {
        P2000: HttpStatus.BAD_REQUEST,
      },
      // message mappings
      {
        P2000: 'something went wrong',
        P2028: 'transaction error',
      },

the nest app returns 500 Internal server error when P2028 happens. Note that P2000 P2002 P2025 are always handled implicitly because they are hard-coded.

@marcjulian
Copy link
Member

Thanks for the PR @megane42. I like the approach, but it seems that we need to duplicate the status codes to the HttpStatus and again for the message.

What if we could include the custom message in the first object. Just an idea to either set the status or object {status: number, message: string}

app.useGlobalFilters(
    new PrismaClientExceptionFilter(
      httpAdapter,
      // Prisma Error Code: HTTP Status Response
      {
        P2000: HttpStatus.BAD_REQUEST,
        P2002: HttpStatus.CONFLICT,
        P2025: { status: HttpStatus.NOT_FOUND, message: 'Resource not found' }
      }
    ),
  );

@megane42 megane42 force-pushed the feature/add-option-to-mod-error-messages branch from 0ba7767 to 3448272 Compare August 27, 2023 12:52
Copy link
Contributor Author

@megane42 megane42 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@marcjulian Thanks for your reply and your idea sounds better! So I've implemented it. Now it supports the config like this:

  app.useGlobalFilters(
    new PrismaClientExceptionFilter(httpAdapter, {
      // Current way
      P2000: HttpStatus.BAD_REQUEST,

      // New way
      P2001: {
        statusCode: HttpStatus.BAD_REQUEST,
        errorMessage: 'something went wrong',
      },

      // New way: either statusCode or errorMessage can be omitted
      P2002: { statusCode: HttpStatus.BAD_REQUEST },
      P2003: { errorMessage: 'something went wrong' },
    }),
  );

BTW I think it's better to see the code diff from current main rather than from my last commit because it's easier to read what I did. I'm still leaving the old commits now just in case, but will squash them if the new code is OK.

@@ -12,7 +12,12 @@ import { Prisma } from '@prisma/client';
export declare type GqlContextType = 'graphql' | ContextType;

export type ErrorCodesStatusMapping = {
Copy link
Contributor Author

@megane42 megane42 Aug 27, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I concern that this type is no longer ErrorCodesStatusMapping strictly, because it handles not only "Status" but also "Message" now. Currently I haven't renamed it now, because it's hard to rename the already exported type.

@megane42 megane42 force-pushed the feature/add-option-to-mod-error-messages branch from 3448272 to 786cbe4 Compare August 27, 2023 14:11
@megane42
Copy link
Contributor Author

@marcjulian Hi, let me know if there is anything I can do to help merge this PR. Sorry to rush you like this 🙏

@marcjulian
Copy link
Member

Hi @megane42, I haven't forgotten about your PR. I will try to find time to review and merge your PR soon.

@mohrazzak
Copy link

Thanks for this PR, I really hope to get this finished ASAP because it's really important feature.

Greeting to you Devs.

Copy link
Member

@marcjulian marcjulian left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! Thanks for the PR and keeping it backwards compatible!
Really appreciate your help @megane42

@marcjulian marcjulian merged commit a1988b1 into notiz-dev:main Nov 1, 2023
3 checks passed
@marcjulian
Copy link
Member

The custom error message can be testet in the latest dev release.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

feat: add option to use generic http messages in Prisma exception filter
3 participants