A consistent error format

API design: REST, HTTP, GraphQL and gRPC Junior Python 3.13+ PostgreSQL 17+ Reviewed By Best Latest Apps

Predict the output

What does the error body print?

Python 3.13
import json
from dataclasses import asdict, dataclass, field


@dataclass
class Problem:
    type: str
    title: str
    status: int
    errors: list[dict[str, str]] = field(default_factory=list)


p = Problem("/problems/validation", "Invalid order", 422)
p.errors.append({"field": "qty", "reason": "must be > 0"})
print(json.dumps(asdict(p))[:58])

Options
Hint 1 of 1

What does asdict return?

Choose an answer, then open Show answer below to check it.

Show answer

Answer: A {"type": "/problems/validation", "title": "Invalid order",

Correct. asdict keeps field order and json.dumps writes it; the print shows the first 58 characters.

A dataclass keeps fields in declaration order, asdict turns it into a plain dict, and json.dumps writes the keys in that order. The slice just cuts the JSON string after 58 characters.

Why not the others?
  • B {"status": 422, "type": "/problems/validation", "title": . Fields keep their declaration order.
  • C Problem(type='/problems/validation', title='Invalid order'. That's the repr, not JSON.
  • D A TypeError: dataclasses aren't JSON serializable. asdict converts it to a dict first.

30-second answer

Return the right status code plus a machine-readable body in one format across the whole API. RFC 9457 Problem Details (application/problem+json) is a good standard: type (a URI identifying the error kind), title, status, detail and instance, plus your own fields such as a list of invalid fields. Clients branch on type or a stable error code, never on the human-readable text, and the body never leaks stack traces or SQL.

Practise saying it · 30 s. No recording, just a timer

Design an error response.

Say your answer out loud, then check which of these points you covered:

  • Right status code
  • One format (Problem Details)
  • Stable type or code
  • Field-level errors
  • Trace id, no leaks

Deep dive

Include a request or trace id so support can find the logs.

For validation, list every invalid field with a reason, not just the first.

Keep detail safe to show; log the internal cause separately.

RFC 9457 replaced RFC 7807 in 2023 with the same core fields.

Common mistakes

  • Different error shapes per endpoint.
  • Stack traces in production responses.
  • Clients parsing English messages to decide what to do.

Senior take & follow-ups

Name Problem Details, the fields, a trace id, and what never to leak.

Follow-up questions

Think of your answer first, then open the hint.

  1. Why a type URI?

    Show hint

    A stable, documented identifier clients can switch on.

  2. What goes in logs but not the response?

    Show hint

    Exception details, SQL, internal hostnames.

Suggest a fix if something here is wrong or out of date.