[{"data":1,"prerenderedAt":2609},["ShallowReactive",2],{"nav":3,"page-\u002Fcore-architecture-routing-patterns\u002Frequest-response-lifecycle\u002Fresponse-model-and-serialization-order\u002F":580,"surround-\u002Fcore-architecture-routing-patterns\u002Frequest-response-lifecycle\u002Fresponse-model-and-serialization-order\u002F":2608},[4,186,386],{"title":5,"path":6,"stem":7,"children":8},"Advanced Pydantic Validation Serialization","\u002Fadvanced-pydantic-validation-serialization","advanced-pydantic-validation-serialization",[9,12,42,66,90,114,150,174],{"title":10,"path":6,"stem":11},"Advanced Pydantic Validation and Serialization","advanced-pydantic-validation-serialization\u002Findex",{"title":13,"path":14,"stem":15,"children":16},"Custom Validators and Field Constraints in Pydantic","\u002Fadvanced-pydantic-validation-serialization\u002Fcustom-validators-field-constraints","advanced-pydantic-validation-serialization\u002Fcustom-validators-field-constraints\u002Findex",[17,18,24,30,36],{"title":13,"path":14,"stem":15},{"title":19,"path":20,"stem":21,"children":22},"Before, After and Wrap Validators in Pydantic v2","\u002Fadvanced-pydantic-validation-serialization\u002Fcustom-validators-field-constraints\u002Fbefore-after-and-wrap-validators","advanced-pydantic-validation-serialization\u002Fcustom-validators-field-constraints\u002Fbefore-after-and-wrap-validators\u002Findex",[23],{"title":19,"path":20,"stem":21},{"title":25,"path":26,"stem":27,"children":28},"Creating Reusable Custom Validators in Pydantic","\u002Fadvanced-pydantic-validation-serialization\u002Fcustom-validators-field-constraints\u002Fcreating-reusable-custom-validators-in-pydantic","advanced-pydantic-validation-serialization\u002Fcustom-validators-field-constraints\u002Fcreating-reusable-custom-validators-in-pydantic\u002Findex",[29],{"title":25,"path":26,"stem":27},{"title":31,"path":32,"stem":33,"children":34},"Cross-Field Validation Patterns in Pydantic v2","\u002Fadvanced-pydantic-validation-serialization\u002Fcustom-validators-field-constraints\u002Fcross-field-validation-patterns","advanced-pydantic-validation-serialization\u002Fcustom-validators-field-constraints\u002Fcross-field-validation-patterns\u002Findex",[35],{"title":31,"path":32,"stem":33},{"title":37,"path":38,"stem":39,"children":40},"Pydantic v2 Async Custom Validator: What to Do Instead","\u002Fadvanced-pydantic-validation-serialization\u002Fcustom-validators-field-constraints\u002Fpydantic-v2-async-custom-validator","advanced-pydantic-validation-serialization\u002Fcustom-validators-field-constraints\u002Fpydantic-v2-async-custom-validator\u002Findex",[41],{"title":37,"path":38,"stem":39},{"title":43,"path":44,"stem":45,"children":46},"JSON Schema Customization in Pydantic and FastAPI","\u002Fadvanced-pydantic-validation-serialization\u002Fjson-schema-customization","advanced-pydantic-validation-serialization\u002Fjson-schema-customization\u002Findex",[47,48,54,60],{"title":43,"path":44,"stem":45},{"title":49,"path":50,"stem":51,"children":52},"Customizing OpenAPI Schema Generation in FastAPI","\u002Fadvanced-pydantic-validation-serialization\u002Fjson-schema-customization\u002Fcustomizing-openapi-schema-generation-in-fastapi","advanced-pydantic-validation-serialization\u002Fjson-schema-customization\u002Fcustomizing-openapi-schema-generation-in-fastapi\u002Findex",[53],{"title":49,"path":50,"stem":51},{"title":55,"path":56,"stem":57,"children":58},"Discriminated Unions in OpenAPI with Pydantic","\u002Fadvanced-pydantic-validation-serialization\u002Fjson-schema-customization\u002Fdiscriminated-unions-in-openapi","advanced-pydantic-validation-serialization\u002Fjson-schema-customization\u002Fdiscriminated-unions-in-openapi\u002Findex",[59],{"title":55,"path":56,"stem":57},{"title":61,"path":62,"stem":63,"children":64},"Examples in the OpenAPI Schema with FastAPI","\u002Fadvanced-pydantic-validation-serialization\u002Fjson-schema-customization\u002Fexamples-in-openapi-schema","advanced-pydantic-validation-serialization\u002Fjson-schema-customization\u002Fexamples-in-openapi-schema\u002Findex",[65],{"title":61,"path":62,"stem":63},{"title":67,"path":68,"stem":69,"children":70},"Nested Model Serialization in FastAPI","\u002Fadvanced-pydantic-validation-serialization\u002Fnested-model-serialization","advanced-pydantic-validation-serialization\u002Fnested-model-serialization\u002Findex",[71,72,78,84],{"title":67,"path":68,"stem":69},{"title":73,"path":74,"stem":75,"children":76},"Excluding Fields Per Endpoint in FastAPI","\u002Fadvanced-pydantic-validation-serialization\u002Fnested-model-serialization\u002Fexcluding-fields-per-endpoint","advanced-pydantic-validation-serialization\u002Fnested-model-serialization\u002Fexcluding-fields-per-endpoint\u002Findex",[77],{"title":73,"path":74,"stem":75},{"title":79,"path":80,"stem":81,"children":82},"Handling Deeply Nested JSON Models Efficiently","\u002Fadvanced-pydantic-validation-serialization\u002Fnested-model-serialization\u002Fhandling-deeply-nested-json-models-efficiently","advanced-pydantic-validation-serialization\u002Fnested-model-serialization\u002Fhandling-deeply-nested-json-models-efficiently\u002Findex",[83],{"title":79,"path":80,"stem":81},{"title":85,"path":86,"stem":87,"children":88},"Self-Referencing and Recursive Models in Pydantic v2","\u002Fadvanced-pydantic-validation-serialization\u002Fnested-model-serialization\u002Fself-referencing-and-recursive-models","advanced-pydantic-validation-serialization\u002Fnested-model-serialization\u002Fself-referencing-and-recursive-models\u002Findex",[89],{"title":85,"path":86,"stem":87},{"title":91,"path":92,"stem":93,"children":94},"Performance Optimization for Pydantic Models in FastAPI","\u002Fadvanced-pydantic-validation-serialization\u002Fperformance-optimization-for-models","advanced-pydantic-validation-serialization\u002Fperformance-optimization-for-models\u002Findex",[95,96,102,108],{"title":91,"path":92,"stem":93},{"title":97,"path":98,"stem":99,"children":100},"model_construct and When to Skip Validation in Pydantic","\u002Fadvanced-pydantic-validation-serialization\u002Fperformance-optimization-for-models\u002Fmodel-construct-when-to-skip-validation","advanced-pydantic-validation-serialization\u002Fperformance-optimization-for-models\u002Fmodel-construct-when-to-skip-validation\u002Findex",[101],{"title":97,"path":98,"stem":99},{"title":103,"path":104,"stem":105,"children":106},"Pydantic Model Serialization Performance in FastAPI","\u002Fadvanced-pydantic-validation-serialization\u002Fperformance-optimization-for-models\u002Fpydantic-model-serialization-performance","advanced-pydantic-validation-serialization\u002Fperformance-optimization-for-models\u002Fpydantic-model-serialization-performance\u002Findex",[107],{"title":103,"path":104,"stem":105},{"title":109,"path":110,"stem":111,"children":112},"TypeAdapter for Non-Model Types in Pydantic","\u002Fadvanced-pydantic-validation-serialization\u002Fperformance-optimization-for-models\u002Ftypeadapter-for-non-model-types","advanced-pydantic-validation-serialization\u002Fperformance-optimization-for-models\u002Ftypeadapter-for-non-model-types\u002Findex",[113],{"title":109,"path":110,"stem":111},{"title":115,"path":116,"stem":117,"children":118},"Pydantic V2 Migration Guide for FastAPI","\u002Fadvanced-pydantic-validation-serialization\u002Fpydantic-v2-migration-guide","advanced-pydantic-validation-serialization\u002Fpydantic-v2-migration-guide\u002Findex",[119,120,126,132,138,144],{"title":115,"path":116,"stem":117},{"title":121,"path":122,"stem":123,"children":124},"Migrate @validator to @field_validator in Pydantic v2","\u002Fadvanced-pydantic-validation-serialization\u002Fpydantic-v2-migration-guide\u002Fmigrate-validator-to-field-validator","advanced-pydantic-validation-serialization\u002Fpydantic-v2-migration-guide\u002Fmigrate-validator-to-field-validator\u002Findex",[125],{"title":121,"path":122,"stem":123},{"title":127,"path":128,"stem":129,"children":130},"Migrating from Pydantic v1 to v2 Without Breaking APIs","\u002Fadvanced-pydantic-validation-serialization\u002Fpydantic-v2-migration-guide\u002Fmigrating-from-pydantic-v1-to-v2-without-breaking-apis","advanced-pydantic-validation-serialization\u002Fpydantic-v2-migration-guide\u002Fmigrating-from-pydantic-v1-to-v2-without-breaking-apis\u002Findex",[131],{"title":127,"path":128,"stem":129},{"title":133,"path":134,"stem":135,"children":136},"model_config vs class Config in Pydantic v2","\u002Fadvanced-pydantic-validation-serialization\u002Fpydantic-v2-migration-guide\u002Fmodel-config-vs-class-config","advanced-pydantic-validation-serialization\u002Fpydantic-v2-migration-guide\u002Fmodel-config-vs-class-config\u002Findex",[137],{"title":133,"path":134,"stem":135},{"title":139,"path":140,"stem":141,"children":142},"Replacing json_encoders with field_serializer in Pydantic v2","\u002Fadvanced-pydantic-validation-serialization\u002Fpydantic-v2-migration-guide\u002Freplacing-json-encoders-with-field-serializer","advanced-pydantic-validation-serialization\u002Fpydantic-v2-migration-guide\u002Freplacing-json-encoders-with-field-serializer\u002Findex",[143],{"title":139,"path":140,"stem":141},{"title":145,"path":146,"stem":147,"children":148},"Migrating @root_validator to @model_validator in Pydantic v2","\u002Fadvanced-pydantic-validation-serialization\u002Fpydantic-v2-migration-guide\u002Froot-validator-to-model-validator","advanced-pydantic-validation-serialization\u002Fpydantic-v2-migration-guide\u002Froot-validator-to-model-validator\u002Findex",[149],{"title":145,"path":146,"stem":147},{"title":151,"path":152,"stem":153,"children":154},"Request Validation Patterns in FastAPI","\u002Fadvanced-pydantic-validation-serialization\u002Frequest-validation-patterns","advanced-pydantic-validation-serialization\u002Frequest-validation-patterns\u002Findex",[155,156,162,168],{"title":151,"path":152,"stem":153},{"title":157,"path":158,"stem":159,"children":160},"Optional vs Nullable Fields in Pydantic and FastAPI","\u002Fadvanced-pydantic-validation-serialization\u002Frequest-validation-patterns\u002Foptional-vs-nullable-fields","advanced-pydantic-validation-serialization\u002Frequest-validation-patterns\u002Foptional-vs-nullable-fields\u002Findex",[161],{"title":157,"path":158,"stem":159},{"title":163,"path":164,"stem":165,"children":166},"Query, Path and Body Parameter Validation in FastAPI","\u002Fadvanced-pydantic-validation-serialization\u002Frequest-validation-patterns\u002Fquery-path-and-body-parameter-validation","advanced-pydantic-validation-serialization\u002Frequest-validation-patterns\u002Fquery-path-and-body-parameter-validation\u002Findex",[167],{"title":163,"path":164,"stem":165},{"title":169,"path":170,"stem":171,"children":172},"Validating File Uploads and Forms in FastAPI","\u002Fadvanced-pydantic-validation-serialization\u002Frequest-validation-patterns\u002Fvalidating-file-uploads-and-forms","advanced-pydantic-validation-serialization\u002Frequest-validation-patterns\u002Fvalidating-file-uploads-and-forms\u002Findex",[173],{"title":169,"path":170,"stem":171},{"title":175,"path":176,"stem":177,"children":178},"Type Hinting and IDE Integration in FastAPI","\u002Fadvanced-pydantic-validation-serialization\u002Ftype-hinting-ide-integration","advanced-pydantic-validation-serialization\u002Ftype-hinting-ide-integration\u002Findex",[179,180],{"title":175,"path":176,"stem":177},{"title":181,"path":182,"stem":183,"children":184},"Annotated Dependencies and Reusable Types in FastAPI","\u002Fadvanced-pydantic-validation-serialization\u002Ftype-hinting-ide-integration\u002Fannotated-dependencies-and-reusable-types","advanced-pydantic-validation-serialization\u002Ftype-hinting-ide-integration\u002Fannotated-dependencies-and-reusable-types\u002Findex",[185],{"title":181,"path":182,"stem":183},{"title":187,"path":188,"stem":189,"children":190},"Async Background Tasks Observability","\u002Fasync-background-tasks-observability","async-background-tasks-observability",[191,194,224,254,284,308,338,362],{"title":192,"path":188,"stem":193},"Async, Background Tasks, and Observability in FastAPI","async-background-tasks-observability\u002Findex",{"title":195,"path":196,"stem":197,"children":198},"Async Correctness and Concurrency in FastAPI","\u002Fasync-background-tasks-observability\u002Fasync-correctness-concurrency","async-background-tasks-observability\u002Fasync-correctness-concurrency\u002Findex",[199,200,206,212,218],{"title":195,"path":196,"stem":197},{"title":201,"path":202,"stem":203,"children":204},"Concurrent Requests with asyncio.gather in FastAPI","\u002Fasync-background-tasks-observability\u002Fasync-correctness-concurrency\u002Fconcurrent-requests-with-asyncio-gather","async-background-tasks-observability\u002Fasync-correctness-concurrency\u002Fconcurrent-requests-with-asyncio-gather\u002Findex",[205],{"title":201,"path":202,"stem":203},{"title":207,"path":208,"stem":209,"children":210},"FastAPI async def vs def: Performance and When to Use Each","\u002Fasync-background-tasks-observability\u002Fasync-correctness-concurrency\u002Ffastapi-async-def-vs-def-performance","async-background-tasks-observability\u002Fasync-correctness-concurrency\u002Ffastapi-async-def-vs-def-performance\u002Findex",[211],{"title":207,"path":208,"stem":209},{"title":213,"path":214,"stem":215,"children":216},"Fixing Blocking Calls in Async FastAPI Routes","\u002Fasync-background-tasks-observability\u002Fasync-correctness-concurrency\u002Ffixing-blocking-calls-in-async-routes","async-background-tasks-observability\u002Fasync-correctness-concurrency\u002Ffixing-blocking-calls-in-async-routes\u002Findex",[217],{"title":213,"path":214,"stem":215},{"title":219,"path":220,"stem":221,"children":222},"Running Sync Code in a Threadpool in FastAPI","\u002Fasync-background-tasks-observability\u002Fasync-correctness-concurrency\u002Frunning-sync-code-in-a-threadpool","async-background-tasks-observability\u002Fasync-correctness-concurrency\u002Frunning-sync-code-in-a-threadpool\u002Findex",[223],{"title":219,"path":220,"stem":221},{"title":225,"path":226,"stem":227,"children":228},"Async Database Sessions in FastAPI","\u002Fasync-background-tasks-observability\u002Fasync-database-sessions","async-background-tasks-observability\u002Fasync-database-sessions\u002Findex",[229,230,236,242,248],{"title":225,"path":226,"stem":227},{"title":231,"path":232,"stem":233,"children":234},"Async SQLAlchemy Session per Request in FastAPI","\u002Fasync-background-tasks-observability\u002Fasync-database-sessions\u002Fasync-sqlalchemy-session-per-request","async-background-tasks-observability\u002Fasync-database-sessions\u002Fasync-sqlalchemy-session-per-request\u002Findex",[235],{"title":231,"path":232,"stem":233},{"title":237,"path":238,"stem":239,"children":240},"Fixing asyncpg Connection Pool Exhaustion in FastAPI","\u002Fasync-background-tasks-observability\u002Fasync-database-sessions\u002Ffixing-asyncpg-pool-exhaustion","async-background-tasks-observability\u002Fasync-database-sessions\u002Ffixing-asyncpg-pool-exhaustion\u002Findex",[241],{"title":237,"path":238,"stem":239},{"title":243,"path":244,"stem":245,"children":246},"Testing with Async Database Fixtures in FastAPI","\u002Fasync-background-tasks-observability\u002Fasync-database-sessions\u002Ftesting-with-async-database-fixtures","async-background-tasks-observability\u002Fasync-database-sessions\u002Ftesting-with-async-database-fixtures\u002Findex",[247],{"title":243,"path":244,"stem":245},{"title":249,"path":250,"stem":251,"children":252},"Transaction Management and Rollback in FastAPI","\u002Fasync-background-tasks-observability\u002Fasync-database-sessions\u002Ftransaction-management-and-rollback","async-background-tasks-observability\u002Fasync-database-sessions\u002Ftransaction-management-and-rollback\u002Findex",[253],{"title":249,"path":250,"stem":251},{"title":255,"path":256,"stem":257,"children":258},"Background Task Processing in FastAPI","\u002Fasync-background-tasks-observability\u002Fbackground-task-processing","async-background-tasks-observability\u002Fbackground-task-processing\u002Findex",[259,260,266,272,278],{"title":255,"path":256,"stem":257},{"title":261,"path":262,"stem":263,"children":264},"FastAPI BackgroundTasks vs Celery vs ARQ","\u002Fasync-background-tasks-observability\u002Fbackground-task-processing\u002Ffastapi-backgroundtasks-vs-celery-vs-arq","async-background-tasks-observability\u002Fbackground-task-processing\u002Ffastapi-backgroundtasks-vs-celery-vs-arq\u002Findex",[265],{"title":261,"path":262,"stem":263},{"title":267,"path":268,"stem":269,"children":270},"Retry and Idempotency for FastAPI Background Tasks","\u002Fasync-background-tasks-observability\u002Fbackground-task-processing\u002Fretry-and-idempotency-for-tasks","async-background-tasks-observability\u002Fbackground-task-processing\u002Fretry-and-idempotency-for-tasks\u002Findex",[271],{"title":267,"path":268,"stem":269},{"title":273,"path":274,"stem":275,"children":276},"Running ARQ Workers with FastAPI","\u002Fasync-background-tasks-observability\u002Fbackground-task-processing\u002Frunning-arq-workers-with-fastapi","async-background-tasks-observability\u002Fbackground-task-processing\u002Frunning-arq-workers-with-fastapi\u002Findex",[277],{"title":273,"path":274,"stem":275},{"title":279,"path":280,"stem":281,"children":282},"When FastAPI BackgroundTasks Silently Fails","\u002Fasync-background-tasks-observability\u002Fbackground-task-processing\u002Fwhen-backgroundtasks-silently-fails","async-background-tasks-observability\u002Fbackground-task-processing\u002Fwhen-backgroundtasks-silently-fails\u002Findex",[283],{"title":279,"path":280,"stem":281},{"title":285,"path":286,"stem":287,"children":288},"Caching Strategies in FastAPI","\u002Fasync-background-tasks-observability\u002Fcaching-strategies","async-background-tasks-observability\u002Fcaching-strategies\u002Findex",[289,290,296,302],{"title":285,"path":286,"stem":287},{"title":291,"path":292,"stem":293,"children":294},"Cache Invalidation Patterns in FastAPI","\u002Fasync-background-tasks-observability\u002Fcaching-strategies\u002Fcache-invalidation-patterns-in-fastapi","async-background-tasks-observability\u002Fcaching-strategies\u002Fcache-invalidation-patterns-in-fastapi\u002Findex",[295],{"title":291,"path":292,"stem":293},{"title":297,"path":298,"stem":299,"children":300},"Caching Dependency Results in FastAPI","\u002Fasync-background-tasks-observability\u002Fcaching-strategies\u002Fcaching-dependency-results","async-background-tasks-observability\u002Fcaching-strategies\u002Fcaching-dependency-results\u002Findex",[301],{"title":297,"path":298,"stem":299},{"title":303,"path":304,"stem":305,"children":306},"Redis Response Caching in FastAPI","\u002Fasync-background-tasks-observability\u002Fcaching-strategies\u002Fredis-response-caching-in-fastapi","async-background-tasks-observability\u002Fcaching-strategies\u002Fredis-response-caching-in-fastapi\u002Findex",[307],{"title":303,"path":304,"stem":305},{"title":309,"path":310,"stem":311,"children":312},"Observability and Tracing in FastAPI","\u002Fasync-background-tasks-observability\u002Fobservability-and-tracing","async-background-tasks-observability\u002Fobservability-and-tracing\u002Findex",[313,314,320,326,332],{"title":309,"path":310,"stem":311},{"title":315,"path":316,"stem":317,"children":318},"Correlating Logs, Traces and Errors in FastAPI","\u002Fasync-background-tasks-observability\u002Fobservability-and-tracing\u002Fcorrelating-logs-traces-and-errors","async-background-tasks-observability\u002Fobservability-and-tracing\u002Fcorrelating-logs-traces-and-errors\u002Findex",[319],{"title":315,"path":316,"stem":317},{"title":321,"path":322,"stem":323,"children":324},"Instrumenting FastAPI with OpenTelemetry","\u002Fasync-background-tasks-observability\u002Fobservability-and-tracing\u002Finstrumenting-fastapi-with-opentelemetry","async-background-tasks-observability\u002Fobservability-and-tracing\u002Finstrumenting-fastapi-with-opentelemetry\u002Findex",[325],{"title":321,"path":322,"stem":323},{"title":327,"path":328,"stem":329,"children":330},"Prometheus Metrics for FastAPI","\u002Fasync-background-tasks-observability\u002Fobservability-and-tracing\u002Fprometheus-metrics-for-fastapi","async-background-tasks-observability\u002Fobservability-and-tracing\u002Fprometheus-metrics-for-fastapi\u002Findex",[331],{"title":327,"path":328,"stem":329},{"title":333,"path":334,"stem":335,"children":336},"Structured JSON Logging with Request IDs in FastAPI","\u002Fasync-background-tasks-observability\u002Fobservability-and-tracing\u002Fstructured-json-logging-with-request-ids","async-background-tasks-observability\u002Fobservability-and-tracing\u002Fstructured-json-logging-with-request-ids\u002Findex",[337],{"title":333,"path":334,"stem":335},{"title":339,"path":340,"stem":341,"children":342},"Rate Limiting and Throttling in FastAPI","\u002Fasync-background-tasks-observability\u002Frate-limiting-throttling","async-background-tasks-observability\u002Frate-limiting-throttling\u002Findex",[343,344,350,356],{"title":339,"path":340,"stem":341},{"title":345,"path":346,"stem":347,"children":348},"FastAPI Rate Limiting with Redis and SlowAPI","\u002Fasync-background-tasks-observability\u002Frate-limiting-throttling\u002Ffastapi-rate-limiting-with-redis-slowapi","async-background-tasks-observability\u002Frate-limiting-throttling\u002Ffastapi-rate-limiting-with-redis-slowapi\u002Findex",[349],{"title":345,"path":346,"stem":347},{"title":351,"path":352,"stem":353,"children":354},"Per-User Token Bucket Throttling in FastAPI","\u002Fasync-background-tasks-observability\u002Frate-limiting-throttling\u002Fper-user-token-bucket-throttling","async-background-tasks-observability\u002Frate-limiting-throttling\u002Fper-user-token-bucket-throttling\u002Findex",[355],{"title":351,"path":352,"stem":353},{"title":357,"path":358,"stem":359,"children":360},"Rate Limit Headers and 429 Responses in FastAPI","\u002Fasync-background-tasks-observability\u002Frate-limiting-throttling\u002Frate-limit-headers-and-429-responses","async-background-tasks-observability\u002Frate-limiting-throttling\u002Frate-limit-headers-and-429-responses\u002Findex",[361],{"title":357,"path":358,"stem":359},{"title":363,"path":364,"stem":365,"children":366},"Testing FastAPI Applications","\u002Fasync-background-tasks-observability\u002Ftesting-fastapi-applications","async-background-tasks-observability\u002Ftesting-fastapi-applications\u002Findex",[367,368,374,380],{"title":363,"path":364,"stem":365},{"title":369,"path":370,"stem":371,"children":372},"Mocking External Services in FastAPI Tests","\u002Fasync-background-tasks-observability\u002Ftesting-fastapi-applications\u002Fmocking-external-services-in-tests","async-background-tasks-observability\u002Ftesting-fastapi-applications\u002Fmocking-external-services-in-tests\u002Findex",[373],{"title":369,"path":370,"stem":371},{"title":375,"path":376,"stem":377,"children":378},"TestClient vs httpx AsyncClient in FastAPI","\u002Fasync-background-tasks-observability\u002Ftesting-fastapi-applications\u002Ftestclient-vs-httpx-asyncclient","async-background-tasks-observability\u002Ftesting-fastapi-applications\u002Ftestclient-vs-httpx-asyncclient\u002Findex",[379],{"title":375,"path":376,"stem":377},{"title":381,"path":382,"stem":383,"children":384},"Testing Async FastAPI Endpoints with pytest-asyncio","\u002Fasync-background-tasks-observability\u002Ftesting-fastapi-applications\u002Ftesting-async-endpoints-with-pytest-asyncio","async-background-tasks-observability\u002Ftesting-fastapi-applications\u002Ftesting-async-endpoints-with-pytest-asyncio\u002Findex",[385],{"title":381,"path":382,"stem":383},{"title":387,"path":388,"stem":389,"children":390},"Core Architecture Routing Patterns","\u002Fcore-architecture-routing-patterns","core-architecture-routing-patterns",[391,394,412,436,472,496,526,556],{"title":392,"path":388,"stem":393},"FastAPI Core Architecture and Routing Patterns","core-architecture-routing-patterns\u002Findex",{"title":395,"path":396,"stem":397,"children":398},"Application Factory Patterns in FastAPI","\u002Fcore-architecture-routing-patterns\u002Fapplication-factory-patterns","core-architecture-routing-patterns\u002Fapplication-factory-patterns\u002Findex",[399,400,406],{"title":395,"path":396,"stem":397},{"title":401,"path":402,"stem":403,"children":404},"FastAPI App Factory Pattern for Testing and Deployment","\u002Fcore-architecture-routing-patterns\u002Fapplication-factory-patterns\u002Ffastapi-app-factory-pattern-for-testing-and-deployment","core-architecture-routing-patterns\u002Fapplication-factory-patterns\u002Ffastapi-app-factory-pattern-for-testing-and-deployment\u002Findex",[405],{"title":401,"path":402,"stem":403},{"title":407,"path":408,"stem":409,"children":410},"Lifespan Events vs Startup and Shutdown in FastAPI","\u002Fcore-architecture-routing-patterns\u002Fapplication-factory-patterns\u002Flifespan-events-vs-startup-shutdown","core-architecture-routing-patterns\u002Fapplication-factory-patterns\u002Flifespan-events-vs-startup-shutdown\u002Findex",[411],{"title":407,"path":408,"stem":409},{"title":413,"path":414,"stem":415,"children":416},"Configuration Management in FastAPI","\u002Fcore-architecture-routing-patterns\u002Fconfiguration-management","core-architecture-routing-patterns\u002Fconfiguration-management\u002Findex",[417,418,424,430],{"title":413,"path":414,"stem":415},{"title":419,"path":420,"stem":421,"children":422},"Managing Environment Variables with Pydantic Settings","\u002Fcore-architecture-routing-patterns\u002Fconfiguration-management\u002Fmanaging-environment-variables-with-pydantic-settings","core-architecture-routing-patterns\u002Fconfiguration-management\u002Fmanaging-environment-variables-with-pydantic-settings\u002Findex",[423],{"title":419,"path":420,"stem":421},{"title":425,"path":426,"stem":427,"children":428},"Pydantic Settings vs Dynaconf vs python-decouple","\u002Fcore-architecture-routing-patterns\u002Fconfiguration-management\u002Fpydantic-settings-vs-dynaconf-vs-python-decouple","core-architecture-routing-patterns\u002Fconfiguration-management\u002Fpydantic-settings-vs-dynaconf-vs-python-decouple\u002Findex",[429],{"title":425,"path":426,"stem":427},{"title":431,"path":432,"stem":433,"children":434},"Secrets and .env Files Per Environment in FastAPI","\u002Fcore-architecture-routing-patterns\u002Fconfiguration-management\u002Fsecrets-and-env-files-per-environment","core-architecture-routing-patterns\u002Fconfiguration-management\u002Fsecrets-and-env-files-per-environment\u002Findex",[435],{"title":431,"path":432,"stem":433},{"title":437,"path":438,"stem":439,"children":440},"Dependency Injection Strategies in FastAPI","\u002Fcore-architecture-routing-patterns\u002Fdependency-injection-strategies","core-architecture-routing-patterns\u002Fdependency-injection-strategies\u002Findex",[441,442,448,454,460,466],{"title":437,"path":438,"stem":439},{"title":443,"path":444,"stem":445,"children":446},"Best Practices for FastAPI Dependency Injection","\u002Fcore-architecture-routing-patterns\u002Fdependency-injection-strategies\u002Fbest-practices-for-fastapi-dependency-injection","core-architecture-routing-patterns\u002Fdependency-injection-strategies\u002Fbest-practices-for-fastapi-dependency-injection\u002Findex",[447],{"title":443,"path":444,"stem":445},{"title":449,"path":450,"stem":451,"children":452},"Dependency Caching and use_cache in FastAPI","\u002Fcore-architecture-routing-patterns\u002Fdependency-injection-strategies\u002Fdependency-caching-and-use-cache","core-architecture-routing-patterns\u002Fdependency-injection-strategies\u002Fdependency-caching-and-use-cache\u002Findex",[453],{"title":449,"path":450,"stem":451},{"title":455,"path":456,"stem":457,"children":458},"Fixing FastAPI Dependency Injection Circular Imports","\u002Fcore-architecture-routing-patterns\u002Fdependency-injection-strategies\u002Ffastapi-dependency-injection-circular-import-fix","core-architecture-routing-patterns\u002Fdependency-injection-strategies\u002Ffastapi-dependency-injection-circular-import-fix\u002Findex",[459],{"title":455,"path":456,"stem":457},{"title":461,"path":462,"stem":463,"children":464},"Overriding Dependencies in FastAPI Tests","\u002Fcore-architecture-routing-patterns\u002Fdependency-injection-strategies\u002Foverriding-dependencies-in-tests","core-architecture-routing-patterns\u002Fdependency-injection-strategies\u002Foverriding-dependencies-in-tests\u002Findex",[465],{"title":461,"path":462,"stem":463},{"title":467,"path":468,"stem":469,"children":470},"Yield Dependencies and Cleanup Order in FastAPI","\u002Fcore-architecture-routing-patterns\u002Fdependency-injection-strategies\u002Fyield-dependencies-and-cleanup-order","core-architecture-routing-patterns\u002Fdependency-injection-strategies\u002Fyield-dependencies-and-cleanup-order\u002Findex",[471],{"title":467,"path":468,"stem":469},{"title":473,"path":474,"stem":475,"children":476},"Error Handling and Global Exceptions in FastAPI","\u002Fcore-architecture-routing-patterns\u002Ferror-handling-global-exceptions","core-architecture-routing-patterns\u002Ferror-handling-global-exceptions\u002Findex",[477,478,484,490],{"title":473,"path":474,"stem":475},{"title":479,"path":480,"stem":481,"children":482},"Customising Validation Error Responses in FastAPI","\u002Fcore-architecture-routing-patterns\u002Ferror-handling-global-exceptions\u002Fcustomising-validation-error-responses","core-architecture-routing-patterns\u002Ferror-handling-global-exceptions\u002Fcustomising-validation-error-responses\u002Findex",[483],{"title":479,"path":480,"stem":481},{"title":485,"path":486,"stem":487,"children":488},"Global Exception Handlers for Consistent API Responses","\u002Fcore-architecture-routing-patterns\u002Ferror-handling-global-exceptions\u002Fglobal-exception-handlers-for-consistent-api-responses","core-architecture-routing-patterns\u002Ferror-handling-global-exceptions\u002Fglobal-exception-handlers-for-consistent-api-responses\u002Findex",[489],{"title":485,"path":486,"stem":487},{"title":491,"path":492,"stem":493,"children":494},"HTTPException vs Custom Exception Classes in FastAPI","\u002Fcore-architecture-routing-patterns\u002Ferror-handling-global-exceptions\u002Fhttpexception-vs-custom-exception-classes","core-architecture-routing-patterns\u002Ferror-handling-global-exceptions\u002Fhttpexception-vs-custom-exception-classes\u002Findex",[495],{"title":491,"path":492,"stem":493},{"title":497,"path":498,"stem":499,"children":500},"Middleware Implementation in FastAPI","\u002Fcore-architecture-routing-patterns\u002Fmiddleware-implementation","core-architecture-routing-patterns\u002Fmiddleware-implementation\u002Findex",[501,502,508,514,520],{"title":497,"path":498,"stem":499},{"title":503,"path":504,"stem":505,"children":506},"CORS Middleware Configuration in FastAPI","\u002Fcore-architecture-routing-patterns\u002Fmiddleware-implementation\u002Fcors-middleware-configuration","core-architecture-routing-patterns\u002Fmiddleware-implementation\u002Fcors-middleware-configuration\u002Findex",[507],{"title":503,"path":504,"stem":505},{"title":509,"path":510,"stem":511,"children":512},"Implementing Custom Middleware for Request Tracing","\u002Fcore-architecture-routing-patterns\u002Fmiddleware-implementation\u002Fimplementing-custom-middleware-for-request-tracing","core-architecture-routing-patterns\u002Fmiddleware-implementation\u002Fimplementing-custom-middleware-for-request-tracing\u002Findex",[513],{"title":509,"path":510,"stem":511},{"title":515,"path":516,"stem":517,"children":518},"Middleware Execution Order in FastAPI","\u002Fcore-architecture-routing-patterns\u002Fmiddleware-implementation\u002Fmiddleware-execution-order","core-architecture-routing-patterns\u002Fmiddleware-implementation\u002Fmiddleware-execution-order\u002Findex",[519],{"title":515,"path":516,"stem":517},{"title":521,"path":522,"stem":523,"children":524},"Middleware vs Dependencies: When to Use Which","\u002Fcore-architecture-routing-patterns\u002Fmiddleware-implementation\u002Fmiddleware-vs-dependencies-when-to-use-which","core-architecture-routing-patterns\u002Fmiddleware-implementation\u002Fmiddleware-vs-dependencies-when-to-use-which\u002Findex",[525],{"title":521,"path":522,"stem":523},{"title":527,"path":528,"stem":529,"children":530},"Modular Router Organization in FastAPI","\u002Fcore-architecture-routing-patterns\u002Fmodular-router-organization","core-architecture-routing-patterns\u002Fmodular-router-organization\u002Findex",[531,532,538,544,550],{"title":527,"path":528,"stem":529},{"title":533,"path":534,"stem":535,"children":536},"APIRouter Prefix vs Sub-Application Mounting in FastAPI","\u002Fcore-architecture-routing-patterns\u002Fmodular-router-organization\u002Fapirouter-prefix-vs-sub-application-mounting","core-architecture-routing-patterns\u002Fmodular-router-organization\u002Fapirouter-prefix-vs-sub-application-mounting\u002Findex",[537],{"title":533,"path":534,"stem":535},{"title":539,"path":540,"stem":541,"children":542},"How to Structure Large FastAPI Projects for Scale","\u002Fcore-architecture-routing-patterns\u002Fmodular-router-organization\u002Fhow-to-structure-large-fastapi-projects-for-scale","core-architecture-routing-patterns\u002Fmodular-router-organization\u002Fhow-to-structure-large-fastapi-projects-for-scale\u002Findex",[543],{"title":539,"path":540,"stem":541},{"title":545,"path":546,"stem":547,"children":548},"Router Tags and OpenAPI Grouping in FastAPI","\u002Fcore-architecture-routing-patterns\u002Fmodular-router-organization\u002Frouter-tags-and-openapi-grouping","core-architecture-routing-patterns\u002Fmodular-router-organization\u002Frouter-tags-and-openapi-grouping\u002Findex",[549],{"title":545,"path":546,"stem":547},{"title":551,"path":552,"stem":553,"children":554},"Versioning APIs with FastAPI Routers","\u002Fcore-architecture-routing-patterns\u002Fmodular-router-organization\u002Fversioning-apis-with-routers","core-architecture-routing-patterns\u002Fmodular-router-organization\u002Fversioning-apis-with-routers\u002Findex",[555],{"title":551,"path":552,"stem":553},{"title":557,"path":558,"stem":559,"children":560},"The FastAPI Request\u002FResponse Lifecycle","\u002Fcore-architecture-routing-patterns\u002Frequest-response-lifecycle","core-architecture-routing-patterns\u002Frequest-response-lifecycle\u002Findex",[561,562,568,574],{"title":557,"path":558,"stem":559},{"title":563,"path":564,"stem":565,"children":566},"How a Request Flows Through FastAPI","\u002Fcore-architecture-routing-patterns\u002Frequest-response-lifecycle\u002Fhow-a-request-flows-through-fastapi","core-architecture-routing-patterns\u002Frequest-response-lifecycle\u002Fhow-a-request-flows-through-fastapi\u002Findex",[567],{"title":563,"path":564,"stem":565},{"title":569,"path":570,"stem":571,"children":572},"Response Model and Serialization Order","\u002Fcore-architecture-routing-patterns\u002Frequest-response-lifecycle\u002Fresponse-model-and-serialization-order","core-architecture-routing-patterns\u002Frequest-response-lifecycle\u002Fresponse-model-and-serialization-order\u002Findex",[573],{"title":569,"path":570,"stem":571},{"title":575,"path":576,"stem":577,"children":578},"Streaming and File Responses in FastAPI","\u002Fcore-architecture-routing-patterns\u002Frequest-response-lifecycle\u002Fstreaming-and-file-responses","core-architecture-routing-patterns\u002Frequest-response-lifecycle\u002Fstreaming-and-file-responses\u002Findex",[579],{"title":575,"path":576,"stem":577},{"id":581,"title":569,"body":582,"dateModified":2575,"datePublished":2575,"description":2576,"extension":2577,"faq":2578,"howto":2592,"meta":2593,"navigation":965,"path":570,"seo":2605,"stem":571,"type":2606,"__hash__":2607},"content\u002Fcore-architecture-routing-patterns\u002Frequest-response-lifecycle\u002Fresponse-model-and-serialization-order\u002Findex.md",{"type":583,"value":584,"toc":2564},"minimark",[585,589,596,635,651,770,775,794,805,808,816,830,845,852,863,867,873,1968,1975,1982,1986,2010,2029,2070,2079,2132,2162,2194,2213,2217,2220,2353,2363,2367,2375,2414,2417,2435,2439,2445,2463,2492,2501,2513,2517,2560],[586,587,569],"h1",{"id":588},"response-model-and-serialization-order",[590,591,592],"p",{},[593,594,595],"strong",{},"Key takeaways:",[597,598,599,612,619,622,632],"ul",{},[600,601,602,606,607,611],"li",{},[603,604,605],"code",{},"response_model="," overrides the return annotation; without it, the annotation ",[608,609,610],"em",{},"is"," the response model.",[600,613,614,615,618],{},"Returning a Pydantic model does ",[593,616,617],{},"not"," skip validation — FastAPI re-validates and rebuilds it.",[600,620,621],{},"Re-validation is what strips extra fields, which is why a subclass with a password hash is safe to return.",[600,623,624,627,628,631],{},[603,625,626],{},"exclude_unset"," drops never-assigned fields; ",[603,629,630],{},"exclude_none"," drops null-valued fields. They are not interchangeable.",[600,633,634],{},"A response that fails its own model is a 500, not a 422, because the fault is server-side.",[590,636,637,638,641,642,645,646,650],{},"Between your ",[603,639,640],{},"return"," statement and the bytes on the wire, FastAPI does considerably more than call ",[603,643,644],{},"json.dumps",". This page is about that gap. It is the detailed view of stage five in ",[647,648,557],"a",{"href":649},"\u002Fcore-architecture-routing-patterns\u002Frequest-response-lifecycle\u002F",", and it exists because the gap contains three genuinely surprising behaviours that bite production applications.",[652,653,659,660,659,664,659,668,659,677,659,684,659,689,659,694,659,698,659,703,659,707,659,710,659,713,659,717,659,720,659,723,659,728,659,733,659,737,659,741,659,745,659,749,659,753,659,756,659,761,659,766],"svg",{"viewBox":654,"role":655,"ariaLabel":656,"xmlns":657,"style":658},"0 0 720 300","img","Pipeline showing a handler return value passing through response model validation, exclude filtering, encoding and byte serialization","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg","width:100%;height:auto;max-width:720px;margin:2rem 0","\n  ",[661,662,663],"title",{},"What happens to a handler's return value before it becomes bytes",[665,666,667],"desc",{},"A left-to-right pipeline of four stages. The handler's return value enters, is validated against the response field, then filtered by the exclude options, then passed through jsonable_encoder, then encoded to JSON bytes. A separate lower path shows that returning a Response instance bypasses all four stages.",[669,670],"rect",{"x":671,"y":672,"width":673,"height":674,"rx":675,"style":676},"14","46","150","56","8","fill:none;stroke:currentColor;stroke-width:1.4",[678,679,683],"text",{"x":680,"y":681,"style":682},"89","70","text-anchor:middle;fill:currentColor;font:600 12px sans-serif","return value",[678,685,688],{"x":680,"y":686,"style":687},"88","text-anchor:middle;fill:currentColor;font:400 11px sans-serif","dict \u002F model \u002F list",[690,691],"path",{"d":692,"style":693},"M168 74 L192 74","fill:none;stroke:#00796B;stroke-width:2",[669,695],{"x":696,"y":672,"width":673,"height":674,"rx":675,"style":697},"196","fill:none;stroke:#00796B;stroke-width:1.6",[678,699,702],{"x":700,"y":681,"style":701},"271","text-anchor:middle;fill:#00796B;font:600 12px sans-serif","validate",[678,704,706],{"x":700,"y":686,"style":705},"text-anchor:middle;fill:#00796B;font:400 11px sans-serif","against response field",[690,708],{"d":709,"style":693},"M350 74 L374 74",[669,711],{"x":712,"y":672,"width":673,"height":674,"rx":675,"style":697},"378",[678,714,716],{"x":715,"y":681,"style":701},"453","filter",[678,718,719],{"x":715,"y":686,"style":705},"exclude_unset \u002F none",[690,721],{"d":722,"style":693},"M532 74 L556 74",[669,724],{"x":725,"y":672,"width":726,"height":674,"rx":675,"style":727},"560","146","fill:#00796B;stroke:#00796B;stroke-width:1.4",[678,729,732],{"x":730,"y":681,"style":731},"633","text-anchor:middle;fill:#ffffff;font:600 12px sans-serif","encode",[678,734,736],{"x":730,"y":686,"style":735},"text-anchor:middle;fill:#ffffff;font:400 11px sans-serif","jsonable + bytes",[669,738],{"x":671,"y":739,"width":673,"height":740,"rx":675,"style":676},"164","52",[678,742,744],{"x":680,"y":743,"style":682},"186","Response instance",[678,746,748],{"x":680,"y":747,"style":687},"204","returned directly",[690,750],{"d":751,"style":752},"M168 190 L556 190","fill:none;stroke:currentColor;stroke-width:1.6;stroke-dasharray:6 5",[690,754],{"d":755,"style":752},"M632 190 L632 106",[678,757,760],{"x":758,"y":759,"style":687},"360","180","bypasses validation, filtering and encoding entirely",[678,762,765],{"x":758,"y":763,"style":764},"256","text-anchor:middle;fill:currentColor;font:400 12px sans-serif","All four stages run inside the router, before any middleware",[678,767,769],{"x":758,"y":768,"style":764},"278","sees the response. Middleware only ever observes the bytes.",[771,772,774],"h2",{"id":773},"the-scenario","The scenario",[590,776,777,778,781,782,785,786,789,790,793],{},"A code review flags that your handler returns ",[603,779,780],{},"UserInDb",", which carries ",[603,783,784],{},"password_hash",", while the endpoint is documented as returning ",[603,787,788],{},"UserOut",", which does not. Someone says \"that leaks the hash.\" Someone else says \"no, ",[603,791,792],{},"response_model"," filters it.\" Both have seen it go both ways, because the answer depends on a keyword argument two lines above the function.",[590,795,796,797,800,801,804],{},"Separately, an endpoint that has worked for months starts returning 500s after a schema change, and the log says ",[603,798,799],{},"ResponseValidationError"," — a class half your team has never seen. And an integration partner complains that fields they were told are optional keep arriving as ",[603,802,803],{},"null",".",[590,806,807],{},"These are three faces of one mechanism.",[771,809,811,812,815],{"id":810},"why-it-happens-what-serialize_response-really-does","Why it happens: what ",[603,813,814],{},"serialize_response"," really does",[590,817,818,819,822,823,825,826,829],{},"When you declare a route, FastAPI decides on a ",[593,820,821],{},"response field",". The rule is short: if ",[603,824,605],{}," is passed, that is the response field. If it is not passed, FastAPI reads the return type annotation and uses that. If ",[603,827,828],{},"response_model=None"," is passed explicitly, there is no response field and validation is skipped entirely — which is precisely why that escape hatch exists, for handlers whose return annotation is something FastAPI cannot or should not turn into a schema.",[590,831,832,833,836,837,840,841,844],{},"At request time, whatever your handler returned is passed through ",[603,834,835],{},"serialize_response()",", which validates the value against that field. The critical word is ",[608,838,839],{},"validates",". It does not check whether the object is already an instance of the right class and shortcut. It runs Pydantic validation, producing a ",[593,842,843],{},"new"," object built only from the fields the response model declares.",[590,846,847,848,804],{},"That single fact explains almost everything else on this page. Extra attributes are dropped because they were never copied into the new object. A different model class works if its data happens to satisfy the target, and fails if it does not, regardless of how valid it was on its own terms. And the cost is real, because it is a full validation pass on every response — the topic of ",[647,849,851],{"href":850},"\u002Fadvanced-pydantic-validation-serialization\u002Fperformance-optimization-for-models\u002Fpydantic-model-serialization-performance\u002F","Pydantic Model Serialization Performance",[590,853,854,855,858,859,862],{},"Only then do the ",[603,856,857],{},"exclude_*"," options apply, and only then does ",[603,860,861],{},"jsonable_encoder"," reduce the result to primitives that the response class can encode.",[771,864,866],{"id":865},"the-demonstration","The demonstration",[590,868,869,870,872],{},"One application, ten endpoints, each isolating a single behaviour. The only unusual thing here is the ",[603,871,799],{}," handler, which exists purely so the transcript shows the real error detail instead of an opaque 500.",[874,875,880],"pre",{"className":876,"code":877,"language":878,"meta":879,"style":879},"language-python shiki shiki-themes github-light-high-contrast","\"\"\"What response_model actually does: re-validation, filtering, and the exclude_* switches.\"\"\"\nfrom fastapi import FastAPI, Request\nfrom fastapi.encoders import jsonable_encoder\nfrom fastapi.exceptions import ResponseValidationError\nfrom fastapi.responses import JSONResponse\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\n\n@app.exception_handler(ResponseValidationError)\nasync def response_validation_handler(request: Request, exc: ResponseValidationError):\n    # Registered only so the transcript can show the real error instead of a bare 500.\n    errors = jsonable_encoder(exc.errors())\n    return JSONResponse(status_code=500, content={\"response_validation_errors\": errors})\n\n\nclass UserOut(BaseModel):\n    id: int\n    name: str\n    nickname: str | None = None\n    tier: str = \"free\"\n\n\nclass UserInDb(UserOut):\n    password_hash: str\n\n\nSTORED = UserInDb(id=1, name=\"Ada\", password_hash=\"pbkdf2$deadbeef\")\n\n\n@app.get(\"\u002Fannotated\", response_model=None)\nasync def annotated_only() -> UserOut:\n    \"\"\"No response_model kwarg: the return annotation IS the response model.\"\"\"\n    return STORED\n\n\n@app.get(\"\u002Fannotated-enforced\")\nasync def annotated_enforced() -> UserOut:\n    return STORED\n\n\n@app.get(\"\u002Fkwarg-wins\", response_model=UserOut)\nasync def kwarg_wins() -> UserInDb:\n    \"\"\"response_model= overrides the return annotation, so password_hash is stripped.\"\"\"\n    return STORED\n\n\n@app.get(\"\u002Ffrom-dict\", response_model=UserOut)\nasync def from_dict() -> dict:\n    return {\"id\": 2, \"name\": \"Grace\", \"password_hash\": \"leaked?\", \"tier\": \"pro\"}\n\n\n@app.get(\"\u002Fexclude-unset\", response_model=UserOut, response_model_exclude_unset=True)\nasync def exclude_unset() -> UserOut:\n    return UserOut(id=3, name=\"Katherine\")\n\n\n@app.get(\"\u002Fexclude-none\", response_model=UserOut, response_model_exclude_none=True)\nasync def exclude_none() -> UserOut:\n    return UserOut(id=4, name=\"Radia\", nickname=None, tier=\"pro\")\n\n\n@app.get(\"\u002Fexclude-fields\", response_model=UserOut, response_model_exclude={\"tier\"})\nasync def exclude_fields() -> UserOut:\n    return UserOut(id=5, name=\"Barbara\", nickname=\"Barb\")\n\n\nclass Partial(BaseModel):\n    \"\"\"Perfectly valid on its own terms — but not a UserOut.\"\"\"\n\n    id: int\n\n\n@app.get(\"\u002Frevalidated\", response_model=UserOut)\nasync def revalidated():\n    \"\"\"A *valid* Pydantic object of the wrong shape still fails: it is re-validated.\"\"\"\n    return Partial(id=6)\n\n\n@app.get(\"\u002Fbad-type\", response_model=UserOut)\nasync def bad_type():\n    return {\"id\": \"not-an-int\", \"name\": \"Hedy\"}\n\n\n@app.get(\"\u002Fno-model\", response_model=None)\nasync def no_model() -> UserInDb:\n    \"\"\"response_model=None switches validation off entirely — the hash leaks.\"\"\"\n    return STORED\n","python","",[603,881,882,891,908,921,934,947,960,967,979,984,989,999,1014,1021,1032,1068,1073,1078,1096,1108,1117,1138,1151,1156,1161,1175,1183,1188,1193,1234,1239,1244,1266,1279,1285,1293,1298,1303,1315,1327,1334,1339,1344,1363,1376,1382,1389,1394,1399,1417,1436,1485,1490,1495,1524,1536,1562,1567,1572,1599,1611,1654,1659,1664,1694,1706,1740,1745,1750,1764,1770,1775,1784,1789,1794,1812,1825,1831,1848,1853,1858,1876,1888,1913,1918,1923,1943,1955,1961],{"__ignoreMap":879},[883,884,887],"span",{"class":885,"line":886},"line",1,[883,888,890],{"class":889},"sYEJz","\"\"\"What response_model actually does: re-validation, filtering, and the exclude_* switches.\"\"\"\n",[883,892,894,898,902,905],{"class":885,"line":893},2,[883,895,897],{"class":896},"sTJeM","from",[883,899,901],{"class":900},"sigWx"," fastapi ",[883,903,904],{"class":896},"import",[883,906,907],{"class":900}," FastAPI, Request\n",[883,909,911,913,916,918],{"class":885,"line":910},3,[883,912,897],{"class":896},[883,914,915],{"class":900}," fastapi.encoders ",[883,917,904],{"class":896},[883,919,920],{"class":900}," jsonable_encoder\n",[883,922,924,926,929,931],{"class":885,"line":923},4,[883,925,897],{"class":896},[883,927,928],{"class":900}," fastapi.exceptions ",[883,930,904],{"class":896},[883,932,933],{"class":900}," ResponseValidationError\n",[883,935,937,939,942,944],{"class":885,"line":936},5,[883,938,897],{"class":896},[883,940,941],{"class":900}," fastapi.responses ",[883,943,904],{"class":896},[883,945,946],{"class":900}," JSONResponse\n",[883,948,950,952,955,957],{"class":885,"line":949},6,[883,951,897],{"class":896},[883,953,954],{"class":900}," pydantic ",[883,956,904],{"class":896},[883,958,959],{"class":900}," BaseModel\n",[883,961,963],{"class":885,"line":962},7,[883,964,966],{"emptyLinePlaceholder":965},true,"\n",[883,968,970,973,976],{"class":885,"line":969},8,[883,971,972],{"class":900},"app ",[883,974,975],{"class":896},"=",[883,977,978],{"class":900}," FastAPI()\n",[883,980,982],{"class":885,"line":981},9,[883,983,966],{"emptyLinePlaceholder":965},[883,985,987],{"class":885,"line":986},10,[883,988,966],{"emptyLinePlaceholder":965},[883,990,992,996],{"class":885,"line":991},11,[883,993,995],{"class":994},"s3dhs","@app.exception_handler",[883,997,998],{"class":900},"(ResponseValidationError)\n",[883,1000,1002,1005,1008,1011],{"class":885,"line":1001},12,[883,1003,1004],{"class":896},"async",[883,1006,1007],{"class":896}," def",[883,1009,1010],{"class":994}," response_validation_handler",[883,1012,1013],{"class":900},"(request: Request, exc: ResponseValidationError):\n",[883,1015,1017],{"class":885,"line":1016},13,[883,1018,1020],{"class":1019},"sFeEa","    # Registered only so the transcript can show the real error instead of a bare 500.\n",[883,1022,1024,1027,1029],{"class":885,"line":1023},14,[883,1025,1026],{"class":900},"    errors ",[883,1028,975],{"class":896},[883,1030,1031],{"class":900}," jsonable_encoder(exc.errors())\n",[883,1033,1035,1038,1041,1045,1047,1051,1054,1057,1059,1062,1065],{"class":885,"line":1034},15,[883,1036,1037],{"class":896},"    return",[883,1039,1040],{"class":900}," JSONResponse(",[883,1042,1044],{"class":1043},"sV4o_","status_code",[883,1046,975],{"class":896},[883,1048,1050],{"class":1049},"sacAq","500",[883,1052,1053],{"class":900},", ",[883,1055,1056],{"class":1043},"content",[883,1058,975],{"class":896},[883,1060,1061],{"class":900},"{",[883,1063,1064],{"class":889},"\"response_validation_errors\"",[883,1066,1067],{"class":900},": errors})\n",[883,1069,1071],{"class":885,"line":1070},16,[883,1072,966],{"emptyLinePlaceholder":965},[883,1074,1076],{"class":885,"line":1075},17,[883,1077,966],{"emptyLinePlaceholder":965},[883,1079,1081,1084,1087,1090,1093],{"class":885,"line":1080},18,[883,1082,1083],{"class":896},"class",[883,1085,1086],{"class":1043}," UserOut",[883,1088,1089],{"class":900},"(",[883,1091,1092],{"class":1049},"BaseModel",[883,1094,1095],{"class":900},"):\n",[883,1097,1099,1102,1105],{"class":885,"line":1098},19,[883,1100,1101],{"class":1049},"    id",[883,1103,1104],{"class":900},": ",[883,1106,1107],{"class":1049},"int\n",[883,1109,1111,1114],{"class":885,"line":1110},20,[883,1112,1113],{"class":900},"    name: ",[883,1115,1116],{"class":1049},"str\n",[883,1118,1120,1123,1126,1129,1132,1135],{"class":885,"line":1119},21,[883,1121,1122],{"class":900},"    nickname: ",[883,1124,1125],{"class":1049},"str",[883,1127,1128],{"class":896}," |",[883,1130,1131],{"class":1049}," None",[883,1133,1134],{"class":896}," =",[883,1136,1137],{"class":1049}," None\n",[883,1139,1141,1144,1146,1148],{"class":885,"line":1140},22,[883,1142,1143],{"class":900},"    tier: ",[883,1145,1125],{"class":1049},[883,1147,1134],{"class":896},[883,1149,1150],{"class":889}," \"free\"\n",[883,1152,1154],{"class":885,"line":1153},23,[883,1155,966],{"emptyLinePlaceholder":965},[883,1157,1159],{"class":885,"line":1158},24,[883,1160,966],{"emptyLinePlaceholder":965},[883,1162,1164,1166,1169,1171,1173],{"class":885,"line":1163},25,[883,1165,1083],{"class":896},[883,1167,1168],{"class":1043}," UserInDb",[883,1170,1089],{"class":900},[883,1172,788],{"class":1049},[883,1174,1095],{"class":900},[883,1176,1178,1181],{"class":885,"line":1177},26,[883,1179,1180],{"class":900},"    password_hash: ",[883,1182,1116],{"class":1049},[883,1184,1186],{"class":885,"line":1185},27,[883,1187,966],{"emptyLinePlaceholder":965},[883,1189,1191],{"class":885,"line":1190},28,[883,1192,966],{"emptyLinePlaceholder":965},[883,1194,1196,1199,1201,1204,1207,1209,1212,1214,1217,1219,1222,1224,1226,1228,1231],{"class":885,"line":1195},29,[883,1197,1198],{"class":1049},"STORED",[883,1200,1134],{"class":896},[883,1202,1203],{"class":900}," UserInDb(",[883,1205,1206],{"class":1043},"id",[883,1208,975],{"class":896},[883,1210,1211],{"class":1049},"1",[883,1213,1053],{"class":900},[883,1215,1216],{"class":1043},"name",[883,1218,975],{"class":896},[883,1220,1221],{"class":889},"\"Ada\"",[883,1223,1053],{"class":900},[883,1225,784],{"class":1043},[883,1227,975],{"class":896},[883,1229,1230],{"class":889},"\"pbkdf2$deadbeef\"",[883,1232,1233],{"class":900},")\n",[883,1235,1237],{"class":885,"line":1236},30,[883,1238,966],{"emptyLinePlaceholder":965},[883,1240,1242],{"class":885,"line":1241},31,[883,1243,966],{"emptyLinePlaceholder":965},[883,1245,1247,1250,1252,1255,1257,1259,1261,1264],{"class":885,"line":1246},32,[883,1248,1249],{"class":994},"@app.get",[883,1251,1089],{"class":900},[883,1253,1254],{"class":889},"\"\u002Fannotated\"",[883,1256,1053],{"class":900},[883,1258,792],{"class":1043},[883,1260,975],{"class":896},[883,1262,1263],{"class":1049},"None",[883,1265,1233],{"class":900},[883,1267,1269,1271,1273,1276],{"class":885,"line":1268},33,[883,1270,1004],{"class":896},[883,1272,1007],{"class":896},[883,1274,1275],{"class":994}," annotated_only",[883,1277,1278],{"class":900},"() -> UserOut:\n",[883,1280,1282],{"class":885,"line":1281},34,[883,1283,1284],{"class":889},"    \"\"\"No response_model kwarg: the return annotation IS the response model.\"\"\"\n",[883,1286,1288,1290],{"class":885,"line":1287},35,[883,1289,1037],{"class":896},[883,1291,1292],{"class":1049}," STORED\n",[883,1294,1296],{"class":885,"line":1295},36,[883,1297,966],{"emptyLinePlaceholder":965},[883,1299,1301],{"class":885,"line":1300},37,[883,1302,966],{"emptyLinePlaceholder":965},[883,1304,1306,1308,1310,1313],{"class":885,"line":1305},38,[883,1307,1249],{"class":994},[883,1309,1089],{"class":900},[883,1311,1312],{"class":889},"\"\u002Fannotated-enforced\"",[883,1314,1233],{"class":900},[883,1316,1318,1320,1322,1325],{"class":885,"line":1317},39,[883,1319,1004],{"class":896},[883,1321,1007],{"class":896},[883,1323,1324],{"class":994}," annotated_enforced",[883,1326,1278],{"class":900},[883,1328,1330,1332],{"class":885,"line":1329},40,[883,1331,1037],{"class":896},[883,1333,1292],{"class":1049},[883,1335,1337],{"class":885,"line":1336},41,[883,1338,966],{"emptyLinePlaceholder":965},[883,1340,1342],{"class":885,"line":1341},42,[883,1343,966],{"emptyLinePlaceholder":965},[883,1345,1347,1349,1351,1354,1356,1358,1360],{"class":885,"line":1346},43,[883,1348,1249],{"class":994},[883,1350,1089],{"class":900},[883,1352,1353],{"class":889},"\"\u002Fkwarg-wins\"",[883,1355,1053],{"class":900},[883,1357,792],{"class":1043},[883,1359,975],{"class":896},[883,1361,1362],{"class":900},"UserOut)\n",[883,1364,1366,1368,1370,1373],{"class":885,"line":1365},44,[883,1367,1004],{"class":896},[883,1369,1007],{"class":896},[883,1371,1372],{"class":994}," kwarg_wins",[883,1374,1375],{"class":900},"() -> UserInDb:\n",[883,1377,1379],{"class":885,"line":1378},45,[883,1380,1381],{"class":889},"    \"\"\"response_model= overrides the return annotation, so password_hash is stripped.\"\"\"\n",[883,1383,1385,1387],{"class":885,"line":1384},46,[883,1386,1037],{"class":896},[883,1388,1292],{"class":1049},[883,1390,1392],{"class":885,"line":1391},47,[883,1393,966],{"emptyLinePlaceholder":965},[883,1395,1397],{"class":885,"line":1396},48,[883,1398,966],{"emptyLinePlaceholder":965},[883,1400,1402,1404,1406,1409,1411,1413,1415],{"class":885,"line":1401},49,[883,1403,1249],{"class":994},[883,1405,1089],{"class":900},[883,1407,1408],{"class":889},"\"\u002Ffrom-dict\"",[883,1410,1053],{"class":900},[883,1412,792],{"class":1043},[883,1414,975],{"class":896},[883,1416,1362],{"class":900},[883,1418,1420,1422,1424,1427,1430,1433],{"class":885,"line":1419},50,[883,1421,1004],{"class":896},[883,1423,1007],{"class":896},[883,1425,1426],{"class":994}," from_dict",[883,1428,1429],{"class":900},"() -> ",[883,1431,1432],{"class":1049},"dict",[883,1434,1435],{"class":900},":\n",[883,1437,1439,1441,1444,1447,1449,1452,1454,1457,1459,1462,1464,1467,1469,1472,1474,1477,1479,1482],{"class":885,"line":1438},51,[883,1440,1037],{"class":896},[883,1442,1443],{"class":900}," {",[883,1445,1446],{"class":889},"\"id\"",[883,1448,1104],{"class":900},[883,1450,1451],{"class":1049},"2",[883,1453,1053],{"class":900},[883,1455,1456],{"class":889},"\"name\"",[883,1458,1104],{"class":900},[883,1460,1461],{"class":889},"\"Grace\"",[883,1463,1053],{"class":900},[883,1465,1466],{"class":889},"\"password_hash\"",[883,1468,1104],{"class":900},[883,1470,1471],{"class":889},"\"leaked?\"",[883,1473,1053],{"class":900},[883,1475,1476],{"class":889},"\"tier\"",[883,1478,1104],{"class":900},[883,1480,1481],{"class":889},"\"pro\"",[883,1483,1484],{"class":900},"}\n",[883,1486,1488],{"class":885,"line":1487},52,[883,1489,966],{"emptyLinePlaceholder":965},[883,1491,1493],{"class":885,"line":1492},53,[883,1494,966],{"emptyLinePlaceholder":965},[883,1496,1498,1500,1502,1505,1507,1509,1511,1514,1517,1519,1522],{"class":885,"line":1497},54,[883,1499,1249],{"class":994},[883,1501,1089],{"class":900},[883,1503,1504],{"class":889},"\"\u002Fexclude-unset\"",[883,1506,1053],{"class":900},[883,1508,792],{"class":1043},[883,1510,975],{"class":896},[883,1512,1513],{"class":900},"UserOut, ",[883,1515,1516],{"class":1043},"response_model_exclude_unset",[883,1518,975],{"class":896},[883,1520,1521],{"class":1049},"True",[883,1523,1233],{"class":900},[883,1525,1527,1529,1531,1534],{"class":885,"line":1526},55,[883,1528,1004],{"class":896},[883,1530,1007],{"class":896},[883,1532,1533],{"class":994}," exclude_unset",[883,1535,1278],{"class":900},[883,1537,1539,1541,1544,1546,1548,1551,1553,1555,1557,1560],{"class":885,"line":1538},56,[883,1540,1037],{"class":896},[883,1542,1543],{"class":900}," UserOut(",[883,1545,1206],{"class":1043},[883,1547,975],{"class":896},[883,1549,1550],{"class":1049},"3",[883,1552,1053],{"class":900},[883,1554,1216],{"class":1043},[883,1556,975],{"class":896},[883,1558,1559],{"class":889},"\"Katherine\"",[883,1561,1233],{"class":900},[883,1563,1565],{"class":885,"line":1564},57,[883,1566,966],{"emptyLinePlaceholder":965},[883,1568,1570],{"class":885,"line":1569},58,[883,1571,966],{"emptyLinePlaceholder":965},[883,1573,1575,1577,1579,1582,1584,1586,1588,1590,1593,1595,1597],{"class":885,"line":1574},59,[883,1576,1249],{"class":994},[883,1578,1089],{"class":900},[883,1580,1581],{"class":889},"\"\u002Fexclude-none\"",[883,1583,1053],{"class":900},[883,1585,792],{"class":1043},[883,1587,975],{"class":896},[883,1589,1513],{"class":900},[883,1591,1592],{"class":1043},"response_model_exclude_none",[883,1594,975],{"class":896},[883,1596,1521],{"class":1049},[883,1598,1233],{"class":900},[883,1600,1602,1604,1606,1609],{"class":885,"line":1601},60,[883,1603,1004],{"class":896},[883,1605,1007],{"class":896},[883,1607,1608],{"class":994}," exclude_none",[883,1610,1278],{"class":900},[883,1612,1614,1616,1618,1620,1622,1625,1627,1629,1631,1634,1636,1639,1641,1643,1645,1648,1650,1652],{"class":885,"line":1613},61,[883,1615,1037],{"class":896},[883,1617,1543],{"class":900},[883,1619,1206],{"class":1043},[883,1621,975],{"class":896},[883,1623,1624],{"class":1049},"4",[883,1626,1053],{"class":900},[883,1628,1216],{"class":1043},[883,1630,975],{"class":896},[883,1632,1633],{"class":889},"\"Radia\"",[883,1635,1053],{"class":900},[883,1637,1638],{"class":1043},"nickname",[883,1640,975],{"class":896},[883,1642,1263],{"class":1049},[883,1644,1053],{"class":900},[883,1646,1647],{"class":1043},"tier",[883,1649,975],{"class":896},[883,1651,1481],{"class":889},[883,1653,1233],{"class":900},[883,1655,1657],{"class":885,"line":1656},62,[883,1658,966],{"emptyLinePlaceholder":965},[883,1660,1662],{"class":885,"line":1661},63,[883,1663,966],{"emptyLinePlaceholder":965},[883,1665,1667,1669,1671,1674,1676,1678,1680,1682,1685,1687,1689,1691],{"class":885,"line":1666},64,[883,1668,1249],{"class":994},[883,1670,1089],{"class":900},[883,1672,1673],{"class":889},"\"\u002Fexclude-fields\"",[883,1675,1053],{"class":900},[883,1677,792],{"class":1043},[883,1679,975],{"class":896},[883,1681,1513],{"class":900},[883,1683,1684],{"class":1043},"response_model_exclude",[883,1686,975],{"class":896},[883,1688,1061],{"class":900},[883,1690,1476],{"class":889},[883,1692,1693],{"class":900},"})\n",[883,1695,1697,1699,1701,1704],{"class":885,"line":1696},65,[883,1698,1004],{"class":896},[883,1700,1007],{"class":896},[883,1702,1703],{"class":994}," exclude_fields",[883,1705,1278],{"class":900},[883,1707,1709,1711,1713,1715,1717,1720,1722,1724,1726,1729,1731,1733,1735,1738],{"class":885,"line":1708},66,[883,1710,1037],{"class":896},[883,1712,1543],{"class":900},[883,1714,1206],{"class":1043},[883,1716,975],{"class":896},[883,1718,1719],{"class":1049},"5",[883,1721,1053],{"class":900},[883,1723,1216],{"class":1043},[883,1725,975],{"class":896},[883,1727,1728],{"class":889},"\"Barbara\"",[883,1730,1053],{"class":900},[883,1732,1638],{"class":1043},[883,1734,975],{"class":896},[883,1736,1737],{"class":889},"\"Barb\"",[883,1739,1233],{"class":900},[883,1741,1743],{"class":885,"line":1742},67,[883,1744,966],{"emptyLinePlaceholder":965},[883,1746,1748],{"class":885,"line":1747},68,[883,1749,966],{"emptyLinePlaceholder":965},[883,1751,1753,1755,1758,1760,1762],{"class":885,"line":1752},69,[883,1754,1083],{"class":896},[883,1756,1757],{"class":1043}," Partial",[883,1759,1089],{"class":900},[883,1761,1092],{"class":1049},[883,1763,1095],{"class":900},[883,1765,1767],{"class":885,"line":1766},70,[883,1768,1769],{"class":889},"    \"\"\"Perfectly valid on its own terms — but not a UserOut.\"\"\"\n",[883,1771,1773],{"class":885,"line":1772},71,[883,1774,966],{"emptyLinePlaceholder":965},[883,1776,1778,1780,1782],{"class":885,"line":1777},72,[883,1779,1101],{"class":1049},[883,1781,1104],{"class":900},[883,1783,1107],{"class":1049},[883,1785,1787],{"class":885,"line":1786},73,[883,1788,966],{"emptyLinePlaceholder":965},[883,1790,1792],{"class":885,"line":1791},74,[883,1793,966],{"emptyLinePlaceholder":965},[883,1795,1797,1799,1801,1804,1806,1808,1810],{"class":885,"line":1796},75,[883,1798,1249],{"class":994},[883,1800,1089],{"class":900},[883,1802,1803],{"class":889},"\"\u002Frevalidated\"",[883,1805,1053],{"class":900},[883,1807,792],{"class":1043},[883,1809,975],{"class":896},[883,1811,1362],{"class":900},[883,1813,1815,1817,1819,1822],{"class":885,"line":1814},76,[883,1816,1004],{"class":896},[883,1818,1007],{"class":896},[883,1820,1821],{"class":994}," revalidated",[883,1823,1824],{"class":900},"():\n",[883,1826,1828],{"class":885,"line":1827},77,[883,1829,1830],{"class":889},"    \"\"\"A *valid* Pydantic object of the wrong shape still fails: it is re-validated.\"\"\"\n",[883,1832,1834,1836,1839,1841,1843,1846],{"class":885,"line":1833},78,[883,1835,1037],{"class":896},[883,1837,1838],{"class":900}," Partial(",[883,1840,1206],{"class":1043},[883,1842,975],{"class":896},[883,1844,1845],{"class":1049},"6",[883,1847,1233],{"class":900},[883,1849,1851],{"class":885,"line":1850},79,[883,1852,966],{"emptyLinePlaceholder":965},[883,1854,1856],{"class":885,"line":1855},80,[883,1857,966],{"emptyLinePlaceholder":965},[883,1859,1861,1863,1865,1868,1870,1872,1874],{"class":885,"line":1860},81,[883,1862,1249],{"class":994},[883,1864,1089],{"class":900},[883,1866,1867],{"class":889},"\"\u002Fbad-type\"",[883,1869,1053],{"class":900},[883,1871,792],{"class":1043},[883,1873,975],{"class":896},[883,1875,1362],{"class":900},[883,1877,1879,1881,1883,1886],{"class":885,"line":1878},82,[883,1880,1004],{"class":896},[883,1882,1007],{"class":896},[883,1884,1885],{"class":994}," bad_type",[883,1887,1824],{"class":900},[883,1889,1891,1893,1895,1897,1899,1902,1904,1906,1908,1911],{"class":885,"line":1890},83,[883,1892,1037],{"class":896},[883,1894,1443],{"class":900},[883,1896,1446],{"class":889},[883,1898,1104],{"class":900},[883,1900,1901],{"class":889},"\"not-an-int\"",[883,1903,1053],{"class":900},[883,1905,1456],{"class":889},[883,1907,1104],{"class":900},[883,1909,1910],{"class":889},"\"Hedy\"",[883,1912,1484],{"class":900},[883,1914,1916],{"class":885,"line":1915},84,[883,1917,966],{"emptyLinePlaceholder":965},[883,1919,1921],{"class":885,"line":1920},85,[883,1922,966],{"emptyLinePlaceholder":965},[883,1924,1926,1928,1930,1933,1935,1937,1939,1941],{"class":885,"line":1925},86,[883,1927,1249],{"class":994},[883,1929,1089],{"class":900},[883,1931,1932],{"class":889},"\"\u002Fno-model\"",[883,1934,1053],{"class":900},[883,1936,792],{"class":1043},[883,1938,975],{"class":896},[883,1940,1263],{"class":1049},[883,1942,1233],{"class":900},[883,1944,1946,1948,1950,1953],{"class":885,"line":1945},87,[883,1947,1004],{"class":896},[883,1949,1007],{"class":896},[883,1951,1952],{"class":994}," no_model",[883,1954,1375],{"class":900},[883,1956,1958],{"class":885,"line":1957},88,[883,1959,1960],{"class":889},"    \"\"\"response_model=None switches validation off entirely — the hash leaks.\"\"\"\n",[883,1962,1964,1966],{"class":885,"line":1963},89,[883,1965,1037],{"class":896},[883,1967,1292],{"class":1049},[590,1969,1970,1971,1974],{},"Real output from running this app in-process (",[603,1972,1973],{},"_verify\u002Fexamples\u002Farch-response-model.py","):",[874,1976,1980],{"className":1977,"code":1979,"language":678,"meta":879},[1978],"language-text","$ GET \u002Fannotated\n200 OK\n{\n  \"id\": 1,\n  \"name\": \"Ada\",\n  \"nickname\": null,\n  \"tier\": \"free\",\n  \"password_hash\": \"pbkdf2$deadbeef\"\n}\n\n$ GET \u002Fannotated-enforced\n200 OK\n{\n  \"id\": 1,\n  \"name\": \"Ada\",\n  \"nickname\": null,\n  \"tier\": \"free\"\n}\n\n$ GET \u002Fkwarg-wins\n200 OK\n{\n  \"id\": 1,\n  \"name\": \"Ada\",\n  \"nickname\": null,\n  \"tier\": \"free\"\n}\n\n$ GET \u002Ffrom-dict\n200 OK\n{\n  \"id\": 2,\n  \"name\": \"Grace\",\n  \"nickname\": null,\n  \"tier\": \"pro\"\n}\n\n$ GET \u002Fexclude-unset\n200 OK\n{\n  \"id\": 3,\n  \"name\": \"Katherine\"\n}\n\n$ GET \u002Fexclude-none\n200 OK\n{\n  \"id\": 4,\n  \"name\": \"Radia\",\n  \"tier\": \"pro\"\n}\n\n$ GET \u002Fexclude-fields\n200 OK\n{\n  \"id\": 5,\n  \"name\": \"Barbara\",\n  \"nickname\": \"Barb\"\n}\n\n$ GET \u002Frevalidated\n500 Internal Server Error\n{\n  \"response_validation_errors\": [\n    {\n      \"type\": \"missing\",\n      \"loc\": [\n        \"response\",\n        \"name\"\n      ],\n      \"msg\": \"Field required\",\n      \"input\": {\n        \"id\": 6\n      }\n    }\n  ]\n}\n\n$ GET \u002Fbad-type\n500 Internal Server Error\n{\n  \"response_validation_errors\": [\n    {\n      \"type\": \"int_parsing\",\n      \"loc\": [\n        \"response\",\n        \"id\"\n      ],\n      \"msg\": \"Input should be a valid integer, unable to parse string as an integer\",\n      \"input\": \"not-an-int\"\n    }\n  ]\n}\n\n$ GET \u002Fno-model\n200 OK\n{\n  \"id\": 1,\n  \"name\": \"Ada\",\n  \"nickname\": null,\n  \"tier\": \"free\",\n  \"password_hash\": \"pbkdf2$deadbeef\"\n}\n",[603,1981,1979],{"__ignoreMap":879},[771,1983,1985],{"id":1984},"what-each-result-proves","What each result proves",[590,1987,1988,1991,1992,1995,1996,1999,2000,2003,2004,2006,2007,2009],{},[593,1989,1990],{},"The annotation is enforced unless you opt out."," ",[603,1993,1994],{},"\u002Fannotated"," and ",[603,1997,1998],{},"\u002Fannotated-enforced"," have the same body, the same ",[603,2001,2002],{},"-> UserOut"," annotation, and the same returned object — the only difference is ",[603,2005,828],{}," on the first. The first leaked ",[603,2008,784],{},". The second did not. If you have ever added a return annotation for type-checker friendliness and been surprised that fields vanished from your API, this pair is why.",[590,2011,2012,1991,2017,2020,2021,2024,2025,2028],{},[593,2013,2014,2016],{},[603,2015,605],{}," beats the annotation.",[603,2018,2019],{},"\u002Fkwarg-wins"," is annotated ",[603,2022,2023],{},"-> UserInDb"," but declared ",[603,2026,2027],{},"response_model=UserOut",", and the hash is gone. The keyword argument is authoritative; the annotation is only a fallback.",[590,2030,2031,2034,2035,2037,2038,2040,2041,2043,2044,2047,2048,2051,2052,2055,2056,2059,2060,2062,2063,2066,2067,2069],{},[593,2032,2033],{},"Returning a Pydantic model does not skip validation."," This is the headline. ",[603,2036,2019],{}," returned a real ",[603,2039,780],{}," instance — a fully constructed, already-validated Pydantic object — and FastAPI still ran it through ",[603,2042,788],{}," validation and produced a new object with four fields. It did not check ",[603,2045,2046],{},"isinstance"," and pass the object along. The proof that it is genuinely re-validating rather than merely filtering is ",[603,2049,2050],{},"\u002Frevalidated",": a ",[603,2053,2054],{},"Partial(id=6)"," object is perfectly valid ",[603,2057,2058],{},"Partial",", but validating it as ",[603,2061,788],{}," fails with ",[603,2064,2065],{},"missing"," on ",[603,2068,1216],{},". Nothing about \"it is already a model\" grants immunity.",[590,2071,2072,2075,2076,2078],{},[603,2073,2074],{},"\u002Ffrom-dict"," shows the same filtering applied to a plain dict, and it is worth noting that the stray ",[603,2077,784],{}," key was silently dropped rather than raising. Extra data is discarded, missing data is an error.",[590,2080,2081,1991,2088,2091,2092,2095,2096,1995,2098,2100,2101,1995,2103,2105,2106,2108,2109,2112,2113,2091,2116,2119,2120,1053,2122,1995,2124,1104,2126,2128,2129,2131],{},[593,2082,2083,1995,2085,2087],{},[603,2084,626],{},[603,2086,630],{}," are different tools.",[603,2089,2090],{},"\u002Fexclude-unset"," constructed ",[603,2093,2094],{},"UserOut(id=3, name=\"Katherine\")"," and got back only ",[603,2097,1206],{},[603,2099,1216],{}," — ",[603,2102,1638],{},[603,2104,1647],{}," were never assigned, so both defaults disappeared even though ",[603,2107,1647],{}," has the non-null value ",[603,2110,2111],{},"\"free\"",". ",[603,2114,2115],{},"\u002Fexclude-none",[603,2117,2118],{},"UserOut(id=4, name=\"Radia\", nickname=None, tier=\"pro\")",", explicitly setting every field, and got back ",[603,2121,1206],{},[603,2123,1216],{},[603,2125,1647],{},[603,2127,1638],{}," was dropped for being ",[603,2130,1263],{}," despite having been set deliberately.",[590,2133,2134,2135,2137,2138,2140,2141,2143,2144,2146,2147,2149,2150,2153,2154,2157,2158,804],{},"Put the two side by side and the rule is clear. ",[603,2136,626],{}," asks \"did anyone assign this?\" and ",[603,2139,630],{}," asks \"is this null?\" Use ",[603,2142,626],{}," for PATCH-style responses where the distinction between \"unspecified\" and \"explicitly null\" carries meaning. Use ",[603,2145,630],{}," to keep payloads compact for clients that treat a missing key and a null the same way. Do not use ",[603,2148,626],{}," on a response built from a database row, because ORM-derived models generally have every field assigned and the option will do nothing. ",[603,2151,2152],{},"\u002Fexclude-fields"," shows the blunter instrument, ",[603,2155,2156],{},"response_model_exclude={\"tier\"}",", which is per-endpoint rather than per-value; managing that across many endpoints is covered in ",[647,2159,2161],{"href":2160},"\u002Fadvanced-pydantic-validation-serialization\u002Fnested-model-serialization\u002Fexcluding-fields-per-endpoint\u002F","Excluding Fields Per Endpoint",[590,2163,2164,2167,2168,1995,2170,2173,2174,2178,2179,2181,2182,2185,2186,2189,2190,2193],{},[593,2165,2166],{},"A bad response is a 500, not a 422."," Both ",[603,2169,2050],{},[603,2171,2172],{},"\u002Fbad-type"," returned 500. This is a deliberate distinction: a 422 tells the caller their input was wrong, and the shape of that body is discussed in ",[647,2175,2177],{"href":2176},"\u002Fcore-architecture-routing-patterns\u002Ferror-handling-global-exceptions\u002Fcustomising-validation-error-responses\u002F","Customising Validation Error Responses",". A response that violates its own contract is nobody's fault but yours, so it raises ",[603,2180,799],{},", which has no default handler and reaches the outermost frame as an unhandled error. Note the ",[603,2183,2184],{},"loc"," in both transcripts begins with ",[603,2187,2188],{},"\"response\""," rather than ",[603,2191,2192],{},"\"body\""," — that prefix is the fastest way to identify which side of the request failed when you are reading a log at 3am.",[590,2195,2196,2199,2200,2202,2203,2205,2206,2208,2209,2212],{},[593,2197,2198],{},"Ordering is fixed."," In every transcript above, ",[603,2201,803],{}," values appear only where the model kept them, and filtering was applied after validation. There is no configuration that lets filtering run first, and ",[603,2204,626],{}," cannot rescue a response that fails validation — ",[603,2207,2050],{}," would have failed identically with ",[603,2210,2211],{},"exclude_unset=True",", because validation happens first.",[771,2214,2216],{"id":2215},"verification","Verification",[590,2218,2219],{},"Two assertions are worth having permanently in your test suite for any endpoint that touches sensitive fields.",[874,2221,2223],{"className":876,"code":2222,"language":878,"meta":879,"style":879},"def test_internal_fields_never_leak(client):\n    body = client.get(\"\u002Fkwarg-wins\").json()\n    # Assert absence explicitly. A schema change that widens the response model\n    # will fail here rather than in a security review six months later.\n    assert \"password_hash\" not in body\n    assert set(body) == {\"id\", \"name\", \"nickname\", \"tier\"}\n\n\ndef test_response_matches_its_own_schema(client):\n    # A 500 with ResponseValidationError is invisible in a smoke test that only\n    # checks status \u003C 400 on the happy path; assert the exact code.\n    assert client.get(\"\u002Frevalidated\").status_code == 500\n",[603,2224,2225,2236,2251,2256,2261,2278,2310,2314,2318,2327,2332,2337],{"__ignoreMap":879},[883,2226,2227,2230,2233],{"class":885,"line":886},[883,2228,2229],{"class":896},"def",[883,2231,2232],{"class":994}," test_internal_fields_never_leak",[883,2234,2235],{"class":900},"(client):\n",[883,2237,2238,2241,2243,2246,2248],{"class":885,"line":893},[883,2239,2240],{"class":900},"    body ",[883,2242,975],{"class":896},[883,2244,2245],{"class":900}," client.get(",[883,2247,1353],{"class":889},[883,2249,2250],{"class":900},").json()\n",[883,2252,2253],{"class":885,"line":910},[883,2254,2255],{"class":1019},"    # Assert absence explicitly. A schema change that widens the response model\n",[883,2257,2258],{"class":885,"line":923},[883,2259,2260],{"class":1019},"    # will fail here rather than in a security review six months later.\n",[883,2262,2263,2266,2269,2272,2275],{"class":885,"line":936},[883,2264,2265],{"class":896},"    assert",[883,2267,2268],{"class":889}," \"password_hash\"",[883,2270,2271],{"class":896}," not",[883,2273,2274],{"class":896}," in",[883,2276,2277],{"class":900}," body\n",[883,2279,2280,2282,2285,2288,2291,2293,2295,2297,2299,2301,2304,2306,2308],{"class":885,"line":949},[883,2281,2265],{"class":896},[883,2283,2284],{"class":1049}," set",[883,2286,2287],{"class":900},"(body) ",[883,2289,2290],{"class":896},"==",[883,2292,1443],{"class":900},[883,2294,1446],{"class":889},[883,2296,1053],{"class":900},[883,2298,1456],{"class":889},[883,2300,1053],{"class":900},[883,2302,2303],{"class":889},"\"nickname\"",[883,2305,1053],{"class":900},[883,2307,1476],{"class":889},[883,2309,1484],{"class":900},[883,2311,2312],{"class":885,"line":962},[883,2313,966],{"emptyLinePlaceholder":965},[883,2315,2316],{"class":885,"line":969},[883,2317,966],{"emptyLinePlaceholder":965},[883,2319,2320,2322,2325],{"class":885,"line":981},[883,2321,2229],{"class":896},[883,2323,2324],{"class":994}," test_response_matches_its_own_schema",[883,2326,2235],{"class":900},[883,2328,2329],{"class":885,"line":986},[883,2330,2331],{"class":1019},"    # A 500 with ResponseValidationError is invisible in a smoke test that only\n",[883,2333,2334],{"class":885,"line":991},[883,2335,2336],{"class":1019},"    # checks status \u003C 400 on the happy path; assert the exact code.\n",[883,2338,2339,2341,2343,2345,2348,2350],{"class":885,"line":1001},[883,2340,2265],{"class":896},[883,2342,2245],{"class":900},[883,2344,1803],{"class":889},[883,2346,2347],{"class":900},").status_code ",[883,2349,2290],{"class":896},[883,2351,2352],{"class":1049}," 500\n",[590,2354,2355,2356,2358,2359,804],{},"The second test is the one people skip. Response validation failures are conditional on data — an endpoint can pass every test and still 500 in production the first time a row has a null in a column your model declares non-optional. If you run structured logging, alert on ",[603,2357,799],{}," by name; the correlation approach is in ",[647,2360,2362],{"href":2361},"\u002Fasync-background-tasks-observability\u002Fobservability-and-tracing\u002Fstructured-json-logging-with-request-ids\u002F","Structured JSON Logging with Request IDs",[771,2364,2366],{"id":2365},"trade-offs-and-when-not-to","Trade-offs and when not to",[590,2368,2369,2371,2372,2374],{},[603,2370,792],{}," is not free. Every response pays a full Pydantic validation pass plus a ",[603,2373,861],{}," walk, and both scale with payload size and nesting depth. For an endpoint returning ten thousand rows, that is a measurable slice of the request. The options, in rough order of preference:",[597,2376,2377,2383,2400],{},[600,2378,2379,2382],{},[593,2380,2381],{},"Keep it."," For almost every endpoint, the schema documentation and the leak prevention are worth more than the CPU.",[600,2384,2385,2392,2393,2396,2397,2399],{},[593,2386,2387,2388,2391],{},"Return a ",[603,2389,2390],{},"Response"," directly."," If you have already produced correct JSON — from a cache, or from a database that serialized it for you — returning ",[603,2394,2395],{},"JSONResponse(content=...)"," or a ",[603,2398,2390],{}," with pre-encoded bytes skips the entire pipeline. You lose validation, and your OpenAPI schema is then a promise rather than a guarantee.",[600,2401,2402,2405,2406,2409,2410,804],{},[593,2403,2404],{},"Skip validation deliberately"," with ",[603,2407,2408],{},"model_construct"," when you can prove the data is already valid, as discussed in ",[647,2411,2413],{"href":2412},"\u002Fadvanced-pydantic-validation-serialization\u002Fperformance-optimization-for-models\u002Fmodel-construct-when-to-skip-validation\u002F","Model Construct: When to Skip Validation",[590,2415,2416],{},"The honest trade-off is that every one of these optimisations moves you from \"the framework guarantees the response matches the schema\" to \"I guarantee it.\" That is a fine trade for one hot endpoint and a bad default for an API.",[590,2418,2419,2420,2422,2423,2425,2426,2430,2431,2434],{},"One more limit worth stating plainly: ",[603,2421,792],{}," does nothing at all when your handler returns a ",[603,2424,2390],{}," instance. FastAPI passes it through untouched, and the declared model becomes documentation with no enforcement behind it. That is the entire basis of ",[647,2427,2429],{"href":2428},"\u002Fcore-architecture-routing-patterns\u002Frequest-response-lifecycle\u002Fstreaming-and-file-responses\u002F","Streaming and File Responses",", and it is a trap when a handler returns a model on one branch and a ",[603,2432,2433],{},"JSONResponse"," on another.",[771,2436,2438],{"id":2437},"faq","FAQ",[590,2440,2441,2444],{},[593,2442,2443],{},"Does returning a Pydantic model skip response validation?","\nNo. FastAPI validates whatever the handler returns against the response field, even when the returned object is already an instance of the declared model. Returning an instance of a different model that happens to be valid on its own terms still fails if it does not satisfy the response model, and a subclass has its extra fields stripped.",[590,2446,2447,2453,2454,2456,2457,2459,2460,2462],{},[593,2448,2449,2450,2452],{},"Which wins, ",[603,2451,792],{}," or the return type annotation?","\nThe ",[603,2455,792],{}," keyword argument wins. FastAPI uses the return annotation as the response model only when ",[603,2458,792],{}," is not supplied. Passing ",[603,2461,828],{}," disables response validation entirely and is the documented way to keep a return annotation that FastAPI should not enforce.",[590,2464,2465,2473,2475,2476,2112,2478,2480,2481,2483,2484,2486,2487,2489,2490,804],{},[593,2466,2467,2468,1995,2470,2472],{},"What is the difference between ",[603,2469,1516],{},[603,2471,1592],{},"?",[603,2474,626],{}," drops fields that were never explicitly assigned, so defaults disappear even if their value is not ",[603,2477,1263],{},[603,2479,630],{}," drops fields whose value is ",[603,2482,1263],{}," regardless of whether they were set explicitly. A field explicitly set to ",[603,2485,1263],{}," survives ",[603,2488,626],{}," but is removed by ",[603,2491,630],{},[590,2493,2494,2497,2498,2500],{},[593,2495,2496],{},"Why does a response validation failure return 500 rather than 422?","\nA 422 means the client sent something invalid. A response that does not match its own declared model is a server bug, so FastAPI raises ",[603,2499,799],{},", which is unhandled by default and surfaces as a 500. The status code is telling you the fault is yours, not the caller's.",[590,2502,2503,2509,2510,2512],{},[593,2504,2505,2506,2508],{},"Does ",[603,2507,792],{}," cost measurable CPU on large list responses?","\nYes. Validation builds a fresh object graph and ",[603,2511,861],{}," walks it again before encoding, so the cost scales with the size and nesting depth of the payload. It is a correctness and documentation feature you pay for on every response, and it is usually worth paying.",[771,2514,2516],{"id":2515},"related-reading","Related Reading",[597,2518,2519,2527,2536,2543,2553],{},[600,2520,2521,1991,2524,2526],{},[593,2522,2523],{},"Up to the guide:",[647,2525,557],{"href":649}," places this stage in the wider sequence.",[600,2528,2529,1991,2532,2535],{},[593,2530,2531],{},"Where the stage sits in a real trace:",[647,2533,563],{"href":2534},"\u002Fcore-architecture-routing-patterns\u002Frequest-response-lifecycle\u002Fhow-a-request-flows-through-fastapi\u002F"," shows serialization happening before any middleware sees the response.",[600,2537,2538,1991,2541,804],{},[593,2539,2540],{},"The bypass path:",[647,2542,2429],{"href":2428},[600,2544,2545,1991,2548,1995,2550,804],{},[593,2546,2547],{},"Field-level control:",[647,2549,2161],{"href":2160},[647,2551,79],{"href":2552},"\u002Fadvanced-pydantic-validation-serialization\u002Fnested-model-serialization\u002Fhandling-deeply-nested-json-models-efficiently\u002F",[600,2554,2555,1991,2558,804],{},[593,2556,2557],{},"The cost side:",[647,2559,851],{"href":850},[2561,2562,2563],"style",{},"html pre.shiki code .sYEJz, html code.shiki .sYEJz{--shiki-default:#032563}html pre.shiki code .sTJeM, html code.shiki .sTJeM{--shiki-default:#A0111F}html pre.shiki code .sigWx, html code.shiki .sigWx{--shiki-default:#0E1116}html pre.shiki code .s3dhs, html code.shiki .s3dhs{--shiki-default:#622CBC}html pre.shiki code .sFeEa, html code.shiki .sFeEa{--shiki-default:#66707B}html pre.shiki code .sV4o_, html code.shiki .sV4o_{--shiki-default:#702C00}html pre.shiki code .sacAq, html code.shiki .sacAq{--shiki-default:#023B95}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"title":879,"searchDepth":893,"depth":893,"links":2565},[2566,2567,2569,2570,2571,2572,2573,2574],{"id":773,"depth":893,"text":774},{"id":810,"depth":893,"text":2568},"Why it happens: what serialize_response really does",{"id":865,"depth":893,"text":866},{"id":1984,"depth":893,"text":1985},{"id":2215,"depth":893,"text":2216},{"id":2365,"depth":893,"text":2366},{"id":2437,"depth":893,"text":2438},{"id":2515,"depth":893,"text":2516},"2026-07-20","How response_model, return annotations and the exclude switches interact in FastAPI, and why returning a Pydantic model never skips response re-validation.","md",[2579,2581,2584,2587,2589],{"q":2443,"a":2580},"No. FastAPI validates whatever the handler returns against the response field, even when the returned object is already an instance of the declared model. Returning an instance of a different model that happens to be valid on its own terms still fails if it does not satisfy the response model, and a subclass has its extra fields stripped.",{"q":2582,"a":2583},"Which wins, response_model or the return type annotation?","The response_model keyword argument wins. FastAPI uses the return annotation as the response model only when response_model is not supplied. Passing response_model=None disables response validation entirely and is the documented way to keep a return annotation that FastAPI should not enforce.",{"q":2585,"a":2586},"What is the difference between response_model_exclude_unset and response_model_exclude_none?","exclude_unset drops fields that were never explicitly assigned, so defaults disappear even if their value is not None. exclude_none drops fields whose value is None regardless of whether they were set explicitly. A field explicitly set to None survives exclude_unset but is removed by exclude_none.",{"q":2496,"a":2588},"A 422 means the client sent something invalid. A response that does not match its own declared model is a server bug, so FastAPI raises ResponseValidationError, which is unhandled by default and surfaces as a 500. The status code is telling you the fault is yours, not the caller's.",{"q":2590,"a":2591},"Does response_model cost measurable CPU on large list responses?","Yes. Validation builds a fresh object graph and jsonable_encoder walks it again before encoding, so the cost scales with the size and nesting depth of the payload. It is a correctness and documentation feature you pay for on every response, and it is usually worth paying.",null,{"slug":588,"breadcrumb":2594},[2595,2598,2601,2603],{"label":2596,"path":2597},"Home","\u002F",{"label":2599,"path":2600},"Core Architecture & Routing Patterns","\u002Fcore-architecture-routing-patterns\u002F",{"label":2602,"path":649},"Request\u002FResponse Lifecycle",{"label":569,"path":2604},"\u002Fcore-architecture-routing-patterns\u002Frequest-response-lifecycle\u002Fresponse-model-and-serialization-order\u002F",{"title":569,"description":2576},"article","WG8RVny1pjkqFuUTG7_0BmWrqEp3FejU_3VDgGjMdjQ",[2592,2592],1784588202739]