Basic setup

The process already performed in the previous filter.

There will be a difference in the "signature" of this exception filter. Instead of implementing the ExceptionFilter interface, it will extend the BaseExceptionFilter class. We do this because we'll handle only those cases already mentioned, and if another type of database error occurs, it will be thrown back to the BaseExceptionFilter, and we'll then get the default behavior again.

And, as the error to be catched is the QueryFailedError, this will be the filter's signature:

@Catch(QueryFailedError)
export class DatabaseExceptionFilter extends BaseExceptionFilter {
  catch(exception: QueryFailedError, host: ArgumentsHost) {}
}

However, before starting its development, we need to make another change in this signature. The QueryFailedError type is too generic and does not contain the fields to be extracted. We'll have to get three fields from the postgres error, they are:

  • code - The error code from Postgres

  • detail - Similar to an error message

  • table - The database table where the error occurred

So, to avoid using the type any, which obviously should be avoided whenever possible, let's create an interface to represent these fields. Do so in the file database -> interfaces -> database-error.interface.

export interface DatabaseError {
  readonly code: string;
  readonly detail: string;
  readonly table: string;
}

Now, we can state that the exception catched by this filter has the type of this interface.

exception: DatabaseError

The first step is identical to the previous filter, that is, to obtain a reference to the response.

const response = host.switchToHttp().getResponse<Response>();

After that, extract the fields from the exception.

const { code, detail, table } = exception;

The next situation to solve is similar to what we went through in the previous filter: extract the data from the message. We want the name and the value of the field that caused the error. They appear in the message in the following format: Key (name)=(value). We can then use these regexes:

private readonly FIELD_NAME_REGEX = /Key \((\w+)\)=/;
private readonly FIELD_VALUE_REGEX = /\)=\((.*?)\)/;

Then, the method to extract the data from the message.

private extractMessageData(message: string) {
  const fieldName = extractFromText(message, this.FIELD_NAME_REGEX);
  const fieldValue = extractFromText(message, this.FIELD_VALUE_REGEX);

  return { fieldName, fieldValue };
}

Now, we should use the code provided by Postgres to create appropriate error data.

Last updated