typescript
58 lines · 8 steps
A catch-all exception filter in NestJS
One filter turns any thrown error into a consistent, structured JSON response.
Explained by
highlit
1import {
2 ArgumentsHost,
3 Catch,
4 ExceptionFilter,
5 HttpException,
6 HttpStatus,
7 Logger,
8} from '@nestjs/common';
9import { HttpAdapterHost } from '@nestjs/core';
10import { Request } from 'express';
11
12interface ErrorResponse {
13 statusCode: number;
14 message: string | string[];
15 error: string;
16 path: string;
17 timestamp: string;
18}
19
20@Catch()
21export class AllExceptionsFilter implements ExceptionFilter {
22 private readonly logger = new Logger(AllExceptionsFilter.name);
23
24 constructor(private readonly httpAdapterHost: HttpAdapterHost) {}
25
26 catch(exception: unknown, host: ArgumentsHost): void {
27 const { httpAdapter } = this.httpAdapterHost;
28 const ctx = host.switchToHttp();
29 const request = ctx.getRequest<Request>();
30
31 const isHttp = exception instanceof HttpException;
32 const statusCode = isHttp
33 ? exception.getStatus()
34 : HttpStatus.INTERNAL_SERVER_ERROR;
35
36 const cause = isHttp ? exception.getResponse() : null;
37 const message =
38 typeof cause === 'object' && cause !== null && 'message' in cause
39 ? (cause as { message: string | string[] }).message
40 : isHttp
41 ? exception.message
42 : 'Internal server error';
43
44 const body: ErrorResponse = {
45 statusCode,
46 message,
47 error: HttpStatus[statusCode] ?? 'Error',
48 path: request.url,
49 timestamp: new Date().toISOString(),
50 };
51
52 if (statusCode >= HttpStatus.INTERNAL_SERVER_ERROR) {
53 this.logger.error(`${request.method} ${request.url}`, exception instanceof Error ? exception.stack : exception);
54 }
55
56 httpAdapter.reply(ctx.getResponse(), body, statusCode);
57 }
58}
01 / 01
STEP 01
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1A single @Catch() filter centralizes error formatting so every route returns the same shape.
- 2Using the HttpAdapterHost keeps the filter platform-agnostic instead of tied to Express directly.
- 3Distinguishing HttpException from unknown throws lets you preserve intended status codes while defaulting the rest to 500.
Related explainers
rust
use axum::{ extract::{Path, State}, http::StatusCode, response::{IntoResponse, Response},
Typed error handling in an Axum handler
error-handling
extractors
validation
Intermediate
9 steps
typescript
import { Module, Injectable } from '@nestjs/common'; import { ConfigModule, ConfigService } from '@nestjs/config'; import * as Joi from 'joi';
Validated, typed config in NestJS
configuration
validation
dependency-injection
Intermediate
6 steps
go
package middleware import ( "time"
Building a request logger middleware in Gin
middleware
structured-logging
closures
Intermediate
6 steps
typescript
type User = { id: number; email: string; roles: string[];
Validating API data with TypeScript type guards
type-guards
runtime-validation
type-narrowing
Intermediate
8 steps
php
<?php final class UserRepository {
A safe PDO user repository in PHP
prepared-statements
repository-pattern
sql-injection
Intermediate
7 steps
java
@RestController @RequestMapping("/api/users") public class UserController {
How a Spring REST controller maps users
rest-api
dependency-injection
dto-mapping
Intermediate
7 steps
Share this explainer
Here's the card — post it anywhere.
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code
Embed this explainer
Drop the interactive walkthrough into a blog or docs. Views never cost a credit.
<iframe src="https://highlit.co/explainers/a-catch-all-exception-filter-in-nestjs-explained-typescript-45d2/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.