typescript
45 lines · 6 steps
Catch-all routes and error shaping in NestJS
A wildcard controller turns unmatched routes into 404s, and an exception filter renders every HttpException as consistent JSON.
Explained by
highlit
1import {
2 Controller,
3 All,
4 Req,
5 NotFoundException,
6 HttpException,
7 ExceptionFilter,
8 Catch,
9 ArgumentsHost,
10 HttpStatus,
11} from '@nestjs/common';
12import { Request, Response } from 'express';
13
14@Controller('*')
15export class NotFoundController {
16 @All()
17 handleUnknownRoute(@Req() req: Request): never {
18 throw new NotFoundException(
19 `Cannot ${req.method} ${req.originalUrl}`,
20 );
21 }
22}
23
24@Catch(HttpException)
25export class HttpExceptionFilter implements ExceptionFilter {
26 catch(exception: HttpException, host: ArgumentsHost) {
27 const ctx = host.switchToHttp();
28 const res = ctx.getResponse<Response>();
29 const req = ctx.getRequest<Request>();
30 const status = exception.getStatus();
31 const payload = exception.getResponse();
32
33 res.status(status).json({
34 statusCode: status,
35 error: HttpStatus[status] ?? 'Error',
36 message:
37 typeof payload === 'string'
38 ? payload
39 : (payload as { message?: string | string[] }).message ??
40 exception.message,
41 path: req.originalUrl,
42 timestamp: new Date().toISOString(),
43 });
44 }
45}
01 / 01
STEP 01
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1A wildcard @Controller('*') gives you a single place to reject every route your app doesn't explicitly handle.
- 2An ExceptionFilter lets you intercept thrown exceptions and control the exact response body clients receive.
- 3Normalizing error payloads to a fixed shape makes APIs predictable for the clients that consume them.
Related explainers
typescript
import { registerLocaleData } from '@angular/common'; import localeFr from '@angular/common/locales/fr'; import localeFrExtra from '@angular/common/locales/extra/fr'; import localeDe from '@angular/common/locales/de';
Locale-aware bootstrapping in Angular
i18n
localization
dependency-injection
Intermediate
8 steps
typescript
import { Module } from '@nestjs/common'; import { ConfigModule } from '@nestjs/config'; import * as Joi from 'joi';
Validating env config at boot in NestJS
configuration
schema-validation
environment-variables
Intermediate
8 steps
python
import time import uuid from django.utils.deprecation import MiddlewareMixin
Attaching per-request context in Django
middleware
request lifecycle
multi-tenancy
Intermediate
7 steps
typescript
import { Inject, Injectable, Logger } from '@nestjs/common'; import { CACHE_MANAGER } from '@nestjs/cache-manager'; import { Cache } from 'cache-manager'; import { InjectRepository } from '@nestjs/typeorm';
A cache-aside country lookup in NestJS
cache-aside
dependency-injection
batch-lookup
Intermediate
8 steps
typescript
import { Injectable, effect, signal, computed } from '@angular/core'; interface Preferences { theme: 'light' | 'dark';
A signal-based preferences store in Angular
signals
state-management
persistence
Intermediate
7 steps
typescript
import { useEffect, useState } from "react"; interface Section { id: string;
Building a scroll-spy hook in React
custom-hooks
intersectionobserver
dom-observation
Intermediate
8 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/catch-all-routes-and-error-shaping-in-nestjs-explained-typescript-2359/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.