REST APIs in Depth · Correctness: Errors, Validation, Concurrency and Caching
Error Responses with Problem Details (RFC 9457)
One machine-readable error format for every endpoint.
RFC 9457 defines application/problem+json with type (a URI identifying the problem kind), title, status, detail and instance, plus extension members. Use stable type URIs (documented pages), human-readable title/detail, and extensions like errors (field-level) and request_id. Never leak stack traces or SQL. Clients branch on status and type, never on message text.
def problem(status: int, type_: str, title: str, detail: str | None = None, **ext):
body = {"type": f"https://api.example.com/problems/{type_}", "title": title, "status": status, **ext}
if detail:
body["detail"] = detail
return JSONResponse(body, status_code=status, media_type="application/problem+json")
@app.exception_handler(OutOfStock)
async def out_of_stock(request: Request, exc: OutOfStock):
return problem(409, "out-of-stock", "Item out of stock", f"Only {exc.available} left", sku=exc.sku)
app.use((err: unknown, req: Request, res: Response, _next: NextFunction) => {
if (err instanceof OutOfStock) {
return res.status(409).type("application/problem+json").json({
type: "https://api.example.com/problems/out-of-stock",
title: "Item out of stock", status: 409,
detail: `Only ${err.available} left`, sku: err.sku, request_id: req.id,
});
}
res.status(500).type("application/problem+json").json({ title: "Internal Server Error", status: 500, request_id: req.id });
});
@ExceptionHandler(OutOfStockException.class)
ProblemDetail outOfStock(OutOfStockException ex) {
ProblemDetail pd = ProblemDetail.forStatusAndDetail(HttpStatus.CONFLICT, "Only " + ex.available() + " left");
pd.setType(URI.create("https://api.example.com/problems/out-of-stock"));
pd.setTitle("Item out of stock");
pd.setProperty("sku", ex.sku());
return pd;
}
Common pitfalls
- Different error shapes per endpoint or team.
- Clients parsing
detailtext to decide behavior. - Exposing internal exception messages.
Key points
- application/problem+json everywhere
- Stable type URIs; extensions for details
- request_id for support
Further reading: RFC 9457: Problem Details for HTTP APIs
Practice questions
Why should clients branch on type rather than title or detail?
Answer
Titles and details are human-readable and may change or be localized; the type URI is a stable identifier designed for programmatic handling.
What extension members are commonly added to problem details?
Answer
Field-level errors for validation, a request_id/trace id for support, and domain data like sku, available or retry_after.
Open in the app to mark lessons complete, take notes and track your progress.