Bird
Raised Fist0
FastAPIframework~8 mins

Custom error response models in FastAPI - Performance & Optimization

Choose your learning style10 modes available

Start learning this pattern below

Jump into concepts and practice - no test required

or
Recommended
Test this pattern10 questions across easy, medium, and hard to know if this pattern is strong
Performance: Custom error response models
MEDIUM IMPACT
This affects the server response time and payload size, impacting how quickly error information is delivered and rendered in the client.
Returning error responses in an API
FastAPI
from fastapi import FastAPI
from fastapi.responses import JSONResponse
from pydantic import BaseModel

app = FastAPI()

class ErrorResponse(BaseModel):
    error_code: int
    message: str

@app.get("/items/{item_id}")
async def read_item(item_id: int):
    if item_id == 0:
        return JSONResponse(status_code=404, content=ErrorResponse(error_code=404, message="Item not found").dict())
    return {"item_id": item_id}
Defines a structured error model that serializes consistently, enabling clients to handle errors efficiently and predictably.
📈 Performance GainSaves client parsing time and improves UX; server serialization cost is slightly higher but negligible for typical use.
Returning error responses in an API
FastAPI
from fastapi import FastAPI, HTTPException

app = FastAPI()

@app.get("/items/{item_id}")
async def read_item(item_id: int):
    if item_id == 0:
        raise HTTPException(status_code=404, detail="Item not found")
    return {"item_id": item_id}
Using default HTTPException with plain detail string sends minimal error info but lacks structured data, causing clients to parse unstructured text and possibly trigger extra processing.
📉 Performance CostMinimal payload size but may cause extra client-side parsing; no significant server serialization cost.
Performance Comparison
PatternDOM OperationsReflowsPaint CostVerdict
Default HTTPException with string detailN/A (API response only)N/AMinimal paint cost on client[!] OK
Custom error response model with PydanticN/A (API response only)N/ASlightly higher paint cost due to larger payload[OK] Good
Rendering Pipeline
When a custom error response model is used, the server serializes the model to JSON, which adds CPU time before sending the response. The client then parses this structured JSON, which can be faster than parsing unstructured text. This affects the time until the error message is displayed (LCP).
Server Serialization
Network Transfer
Client Parsing
Render
⚠️ BottleneckServer Serialization and Network Transfer due to increased payload size
Core Web Vital Affected
LCP
This affects the server response time and payload size, impacting how quickly error information is delivered and rendered in the client.
Optimization Tips
1Keep custom error response models minimal to reduce serialization and payload size.
2Use structured error models to improve client parsing and user experience.
3Check network payload size and response time to monitor error response performance.
Performance Quiz - 3 Questions
Test your performance knowledge
How does using a custom error response model affect the Largest Contentful Paint (LCP)?
AIt can slightly increase LCP due to larger payload and serialization time.
BIt drastically reduces LCP by skipping serialization.
CIt has no effect on LCP because errors are not rendered.
DIt causes layout shifts affecting CLS, not LCP.
DevTools: Network
How to check: Open DevTools, go to Network tab, trigger the error response, and inspect the response payload size and timing.
What to look for: Look for response size and time to first byte; smaller payloads and faster responses improve LCP.

Practice

(1/5)
1. What is the main purpose of using custom error response models in FastAPI?
easy
A. To define a clear and consistent structure for error messages returned by the API
B. To speed up the API response time
C. To automatically fix errors in the API code
D. To hide all error messages from the client

Solution

  1. Step 1: Understand error response models

    Custom error response models define how error messages look, making them clear and consistent.
  2. Step 2: Identify the purpose in FastAPI

    FastAPI uses these models to send structured error info to clients, improving API usability.
  3. Final Answer:

    To define a clear and consistent structure for error messages returned by the API -> Option A
  4. Quick Check:

    Custom error models = clear error messages [OK]
Hint: Custom error models shape error messages clearly [OK]
Common Mistakes:
  • Thinking they speed up API responses
  • Believing they fix code errors automatically
  • Assuming they hide errors completely
2. Which of the following is the correct way to define a custom error response model using Pydantic in FastAPI?
easy
A. class ErrorResponse: message = str; code = int
B. class ErrorResponse(BaseModel): message: str; code: int
C. ErrorResponse = {'message': str, 'code': int}
D. def ErrorResponse(message: str, code: int): return {'message': message, 'code': code}

Solution

  1. Step 1: Recognize Pydantic model syntax

    Pydantic models are defined as classes inheriting from BaseModel with typed attributes.
  2. Step 2: Match correct syntax

    class ErrorResponse(BaseModel): message: str; code: int correctly defines a class with typed fields using BaseModel.
  3. Final Answer:

    class ErrorResponse(BaseModel): message: str; code: int -> Option B
  4. Quick Check:

    Pydantic model = class with BaseModel [OK]
Hint: Use class with BaseModel and typed fields [OK]
Common Mistakes:
  • Defining models as functions
  • Using plain dictionaries instead of classes
  • Missing BaseModel inheritance
3. Given this FastAPI code snippet, what will be the response when a ValueError is raised?
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
from pydantic import BaseModel

app = FastAPI()

class ErrorResponse(BaseModel):
    detail: str

@app.exception_handler(ValueError)
async def value_error_handler(request: Request, exc: ValueError):
    return JSONResponse(
        status_code=400,
        content=ErrorResponse(detail=str(exc)).dict()
    )

@app.get("/test")
async def test():
    raise ValueError("Invalid input")
medium
A. Empty response with status 204
B. Plain text 'Invalid input' with status 500
C. {"detail": "Invalid input"} with status 400
D. JSON with key 'error' and message 'Invalid input' with status 400

Solution

  1. Step 1: Understand exception handler behavior

    The handler catches ValueError and returns JSONResponse with ErrorResponse model content and status 400.
  2. Step 2: Check response content and status

    The content is the dict form of ErrorResponse with detail set to the exception message, so JSON has key 'detail' with 'Invalid input'.
  3. Final Answer:

    {"detail": "Invalid input"} with status 400 -> Option C
  4. Quick Check:

    Exception handler returns JSON with detail key [OK]
Hint: Exception handler returns model dict as JSON with status [OK]
Common Mistakes:
  • Expecting plain text instead of JSON
  • Confusing status codes
  • Assuming different JSON key names
4. Identify the error in this FastAPI custom error handler code:
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
from pydantic import BaseModel

app = FastAPI()

class ErrorResponse(BaseModel):
    message: str

@app.exception_handler(KeyError)
async def key_error_handler(request: Request, exc: KeyError):
    return JSONResponse(
        status_code=404,
        content=ErrorResponse(message=exc).dict()
    )
medium
A. Missing BaseModel inheritance in ErrorResponse
B. Exception handler must be synchronous, not async
C. Using status code 404 instead of 400
D. Passing the exception object directly instead of converting to string

Solution

  1. Step 1: Check how exception is passed to model

    The code passes exc (KeyError object) directly to message field which expects a string.
  2. Step 2: Identify correct usage

    It should convert exc to string with str(exc) to avoid type errors.
  3. Final Answer:

    Passing the exception object directly instead of converting to string -> Option D
  4. Quick Check:

    Exception message must be string [OK]
Hint: Convert exception to string before passing to model [OK]
Common Mistakes:
  • Passing exception object without str()
  • Confusing async/sync handler rules
  • Incorrect status code choice
5. You want to create a FastAPI app that returns a custom error response with fields error_code (int) and error_msg (str) whenever a RuntimeError occurs. Which of the following code snippets correctly implements this behavior?
hard
A. class CustomError(BaseModel): error_code: int; error_msg: str @app.exception_handler(RuntimeError) async def runtime_error_handler(request: Request, exc: RuntimeError): return JSONResponse(status_code=500, content=CustomError(error_code=1001, error_msg=str(exc)).dict())
B. class CustomError(BaseModel): error_code: str; error_msg: int @app.exception_handler(RuntimeError) async def runtime_error_handler(request: Request, exc: RuntimeError): return JSONResponse(status_code=400, content=CustomError(error_code='1001', error_msg=exc).dict())
C. class CustomError: def __init__(self, error_code, error_msg): self.error_code = error_code self.error_msg = error_msg @app.exception_handler(RuntimeError) async def runtime_error_handler(request: Request, exc: RuntimeError): return JSONResponse(status_code=500, content=CustomError(1001, str(exc)))
D. @app.exception_handler(RuntimeError) async def runtime_error_handler(request: Request, exc: RuntimeError): return JSONResponse(status_code=500, content={'error_code': 1001, 'error_msg': str(exc)})

Solution

  1. Step 1: Define correct Pydantic model

    class CustomError(BaseModel): error_code: int; error_msg: str @app.exception_handler(RuntimeError) async def runtime_error_handler(request: Request, exc: RuntimeError): return JSONResponse(status_code=500, content=CustomError(error_code=1001, error_msg=str(exc)).dict()) defines CustomError inheriting from BaseModel with correct field types (int and str).
  2. Step 2: Implement exception handler properly

    class CustomError(BaseModel): error_code: int; error_msg: str @app.exception_handler(RuntimeError) async def runtime_error_handler(request: Request, exc: RuntimeError): return JSONResponse(status_code=500, content=CustomError(error_code=1001, error_msg=str(exc)).dict())'s handler returns JSONResponse with status 500 and content as dict from CustomError instance, converting exception to string.
  3. Step 3: Check other options for errors

    class CustomError(BaseModel): error_code: str; error_msg: int @app.exception_handler(RuntimeError) async def runtime_error_handler(request: Request, exc: RuntimeError): return JSONResponse(status_code=400, content=CustomError(error_code='1001', error_msg=exc).dict()) swaps types incorrectly and passes exc without str(); class CustomError: def __init__(self, error_code, error_msg): self.error_code = error_code self.error_msg = error_msg @app.exception_handler(RuntimeError) async def runtime_error_handler(request: Request, exc: RuntimeError): return JSONResponse(status_code=500, content=CustomError(1001, str(exc))) uses plain class not BaseModel and returns object not dict; @app.exception_handler(RuntimeError) async def runtime_error_handler(request: Request, exc: RuntimeError): return JSONResponse(status_code=500, content={'error_code': 1001, 'error_msg': str(exc)}) skips model usage.
  4. Final Answer:

    Option A correctly defines model and handler returning proper JSON response -> Option A
  5. Quick Check:

    Use BaseModel with typed fields and dict() in handler [OK]
Hint: Use BaseModel and dict() for error response content [OK]
Common Mistakes:
  • Swapping field types in model
  • Not converting exception to string
  • Returning model instance instead of dict
  • Skipping Pydantic model for error response