Fullstack CourseLearn by building
Back to week 3

Topic

Error contracts / HTTP exceptions → stable JSON

Definition

An API error contract is a stable JSON response shape returned for every failed request, produced here by mapping thrown HTTP exceptions through a single global exception filter.

In simpler words

No matter what breaks, clients get the same kind of error object back — so the frontend can show a message without guessing the shape each time.

Ground in AllExceptionsFilter and ApiErrorBody from @repo/contracts.

After this you can

  • Read the shared ApiErrorBody shape
  • Explain how correlationId connects a client error to server logs
  • Choose the HTTP exception that matches a failure

One filter, one shape

Definition

AllExceptionsFilter is a global, catch-all Nest exception filter that inspects any thrown exception, derives a status, error label, message, and optional field-level details, and serializes an ApiErrorBody with a correlationId sourced from the request.

In simpler words

It does not decide business rules — it only standardizes how a thrown exception becomes a response body.

HttpException subclasses — NotFoundException, ForbiddenException, BadRequestException from ValidationPipe, and others — map their status and message straight into the shape.

An unexpected non-HTTP error becomes a generic 500 with a safe message; the real error is logged server-side, never sent to the client.

ApiErrorBody

{
  "statusCode": 400,
  "error": "Bad Request",
  "message": ["title must be longer than or equal to 1 characters"],
  "details": [{ "field": "request", "message": "..." }],
  "correlationId": "..."
}

message is always a string or string[]; the frontend never has to branch on a fifth shape.

Throw the exception that matches the failure

Definition

Choosing an HTTP exception class is choosing the contract a client will see, so a thrown exception should represent the actual failure — not-found, validation, authorization — rather than a generic error.

In simpler words

A missing ticket, an invalid role, and a bad body are different failures and should produce different statuses.

TicketsService.get and .remove throw NotFoundException when a row does not exist — the controller stays free of if-not-found branching.

Never catch and swallow an exception just to return 200 with an error flag in the body; that breaks the contract for every consumer.

Service throws, filter formats

async get(id: string) {
  const ticket = await this.ticketsRepo.findOne({ where: { id } });
  if (!ticket) throw new NotFoundException('Ticket not found');
  return this.toResponse(ticket);
}

The filter turns this into { statusCode: 404, error: "Not Found", message: "Ticket not found", correlationId }.

Keep in mind

  • Let the exception filter be the only place that builds an error response.
  • Pick 404/400/401/403 by what actually failed, not by convenience.
  • Never leak stack traces or raw driver errors to clients in production.

Test

Check your understanding

At least 10 questions — mix of concept, syntax, practical, and logic. Score ≥ 80% (enforced by the API) to save progress.

Checking your session…

10 questions · concept 3 · syntax 2 · practical 3 · logic 2

Concept1. Which statement best defines Error contracts / HTTP exceptions → stable JSON?
Syntax2. Which code-level choice matches Error contracts / HTTP exceptions → stable JSON?
Practical3. A reviewer spots a bug related to Error contracts / HTTP exceptions → stable JSON. What is the right fix?
Logic4. Which reasoning correctly explains Error contracts / HTTP exceptions → stable JSON?
Concept5. Which boundary does correct use of Error contracts / HTTP exceptions → stable JSON preserve?
Practical6. What is the safest next step when applying Error contracts / HTTP exceptions → stable JSON?
Syntax7. Which implementation direction matches the rule for Error contracts / HTTP exceptions → stable JSON?
Logic8. Which consequence follows from applying Error contracts / HTTP exceptions → stable JSON correctly?
Concept9. Which claim about Error contracts / HTTP exceptions → stable JSON is true in this Nest + Postgres monorepo?
Practical10. Which team practice best demonstrates Error contracts / HTTP exceptions → stable JSON?