python
34 lines · 7 steps
Custom exception handlers in FastAPI
Map a domain-specific exception to a structured HTTP error response so route handlers can fail by raising, not by formatting JSON.
Explained by
highlit
1from fastapi import FastAPI, Request, status
2from fastapi.responses import JSONResponse
3
4app = FastAPI()
5
6
7class InsufficientFundsError(Exception):
8 def __init__(self, account_id: str, balance: float, requested: float):
9 self.account_id = account_id
10 self.balance = balance
11 self.requested = requested
12
13
14@app.exception_handler(InsufficientFundsError)
15async def insufficient_funds_handler(request: Request, exc: InsufficientFundsError):
16 return JSONResponse(
17 status_code=status.HTTP_402_PAYMENT_REQUIRED,
18 content={
19 "error": "insufficient_funds",
20 "message": f"Account {exc.account_id} cannot withdraw {exc.requested:.2f}.",
21 "available_balance": exc.balance,
22 "shortfall": round(exc.requested - exc.balance, 2),
23 },
24 headers={"X-Error-Code": "INSUFFICIENT_FUNDS"},
25 )
26
27
28@app.post("/accounts/{account_id}/withdraw")
29async def withdraw(account_id: str, amount: float):
30 account = await accounts.get(account_id)
31 if amount > account.balance:
32 raise InsufficientFundsError(account_id, account.balance, amount)
33 await account.debit(amount)
34 return {"account_id": account_id, "balance": account.balance - amount}
01 / 01
STEP 01
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1Centralizing error formatting in a handler keeps route logic focused on the happy path.
- 2A custom exception can carry rich context that the handler turns into a meaningful response.
- 3Mapping domain failures to specific status codes makes an API's errors predictable for clients.
Related explainers
python
import argparse import sys from pathlib import Path
Building a subcommand CLI with argparse
cli
argparse
subcommands
Intermediate
6 steps
python
from collections.abc import Mapping from typing import Any, Iterator
Flattening nested config into dotted keys
recursion
generators
tree-traversal
Intermediate
7 steps
python
import csv import io from datetime import datetime
Streaming a CSV export in Flask
streaming
generators
csv
Intermediate
9 steps
python
import time from collections import defaultdict from threading import Lock
Sliding-window login rate limiting in Flask
rate-limiting
sliding-window
thread-safety
Intermediate
7 steps
python
from django.conf import settings from django.contrib.auth import get_user_model from django.core.mail import EmailMultiAlternatives from django.db.models.signals import post_save
Sending a welcome email with Django signals
signals
email
user-activation
Intermediate
8 steps
python
import csv import io from datetime import date
Streaming a CSV export in FastAPI
streaming
async-generators
csv
Advanced
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/custom-exception-handlers-in-fastapi-explained-python-3b95/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.