[{"data":1,"prerenderedAt":1940},["ShallowReactive",2],{"nav":3,"page-\u002Fadvanced-pydantic-validation-serialization\u002Fperformance-optimization-for-models\u002Ftypeadapter-for-non-model-types\u002F":580,"surround-\u002Fadvanced-pydantic-validation-serialization\u002Fperformance-optimization-for-models\u002Ftypeadapter-for-non-model-types\u002F":1939},[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":109,"body":582,"dateModified":1908,"datePublished":1908,"description":1909,"extension":1910,"faq":1911,"howto":1922,"meta":1923,"navigation":726,"path":110,"seo":1936,"stem":111,"type":1937,"__hash__":1938},"content\u002Fadvanced-pydantic-validation-serialization\u002Fperformance-optimization-for-models\u002Ftypeadapter-for-non-model-types\u002Findex.md",{"type":583,"value":584,"toc":1897},"minimark",[585,589,596,642,651,656,674,677,752,758,860,864,870,890,893,903,911,915,918,1346,1364,1367,1374,1377,1399,1410,1425,1439,1444,1447,1453,1456,1462,1472,1476,1479,1631,1638,1641,1717,1721,1733,1739,1760,1773,1785,1800,1804,1813,1819,1838,1848,1854,1858,1893],[586,587,109],"h1",{"id":588},"typeadapter-for-non-model-types-in-pydantic",[590,591,592],"p",{},[593,594,595],"strong",{},"Key takeaways:",[597,598,599,611,614,621,631],"ul",{},[600,601,602,606,607,610],"li",{},[603,604,605],"code",{},"TypeAdapter(list[int])"," validates a bare type with no ",[603,608,609],{},"BaseModel"," wrapper and no envelope key.",[600,612,613],{},"Build every adapter once at module level; constructing one compiles a validator and is the expensive part.",[600,615,616,617,620],{},"It handles dataclasses, ",[603,618,619],{},"TypedDict","s, unions, primitives and any nesting of them, with the usual coercion.",[600,622,623,626,627,630],{},[603,624,625],{},"validate_json"," parses and validates in one pass instead of ",[603,628,629],{},"json.loads"," then walk.",[600,632,633,634,637,638,641],{},"Errors are ordinary ",[603,635,636],{},"ValidationError","s, so the ",[603,639,640],{},"loc"," paths and error types you already handle still work.",[590,643,644,645,650],{},"This guide sits under ",[646,647,649],"a",{"href":648},"\u002Fadvanced-pydantic-validation-serialization\u002Fperformance-optimization-for-models\u002F","Performance Optimization for Models",", and it is as much about removing pointless indirection as about speed.",[652,653,655],"h2",{"id":654},"the-problem-this-solves","The Problem This Solves",[590,657,658,659,662,663,666,667,670,671,673],{},"A queue message is a JSON array of integers. A cache entry is a ",[603,660,661],{},"dict[str, float]",". A worker hands you a ",[603,664,665],{},"list[Sensor]"," where ",[603,668,669],{},"Sensor"," is a dataclass that has existed since long before Pydantic showed up in the project. None of these is an object with named fields, and none of them wants to be a ",[603,672,609],{},".",[590,675,676],{},"The usual workaround is to wrap:",[678,679,684],"pre",{"className":680,"code":681,"language":682,"meta":683,"style":683},"language-python shiki shiki-themes github-light-high-contrast","class _IdsWrapper(BaseModel):\n    items: list[int]\n\nids = _IdsWrapper(items=payload).items      # a class, an envelope key, and an unwrap\n","python","",[603,685,686,709,721,728],{"__ignoreMap":683},[687,688,691,695,699,703,706],"span",{"class":689,"line":690},"line",1,[687,692,694],{"class":693},"sTJeM","class",[687,696,698],{"class":697},"sV4o_"," _IdsWrapper",[687,700,702],{"class":701},"sigWx","(",[687,704,609],{"class":705},"sacAq",[687,707,708],{"class":701},"):\n",[687,710,712,715,718],{"class":689,"line":711},2,[687,713,714],{"class":701},"    items: list[",[687,716,717],{"class":705},"int",[687,719,720],{"class":701},"]\n",[687,722,724],{"class":689,"line":723},3,[687,725,727],{"emptyLinePlaceholder":726},true,"\n",[687,729,731,734,737,740,743,745,748],{"class":689,"line":730},4,[687,732,733],{"class":701},"ids ",[687,735,736],{"class":693},"=",[687,738,739],{"class":701}," _IdsWrapper(",[687,741,742],{"class":697},"items",[687,744,736],{"class":693},[687,746,747],{"class":701},"payload).items      ",[687,749,751],{"class":750},"sFeEa","# a class, an envelope key, and an unwrap\n",[590,753,754,755,757],{},"That is three artefacts to express \"this should be a list of ints\". The wrapper leaks into type hints, the ",[603,756,742],{}," key has to be remembered at every call site, and if the wrapper ever ends up in a response model the envelope leaks into your API too.",[759,760,766,770,774,785,792,797,801,804,808,812,815,818,822,827,831,834,837,839,841,843,846,848,851,856],"svg",{"viewBox":761,"role":762,"ariaLabel":763,"xmlns":764,"style":765},"0 0 720 270","img","Wrapping a bare type in a BaseModel versus validating it directly with TypeAdapter","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg","width:100%;height:auto;max-width:720px;margin:2rem 0",[767,768,769],"title",{},"BaseModel wrapper versus TypeAdapter",[771,772,773],"desc",{},"The upper path wraps a raw JSON list in a BaseModel and has to unwrap an envelope key afterwards. The lower path passes the same payload through a module-level TypeAdapter and gets a validated list directly.",[775,776],"rect",{"x":777,"y":778,"width":779,"height":780,"rx":781,"fill":782,"stroke":783,"strokeWidth":784},"20","42","200","56","8","none","currentColor","1.5",[786,787,791],"text",{"x":788,"y":789,"style":790},"120","76","text-anchor:middle;fill:currentColor;font:400 12px sans-serif","raw JSON list",[689,793],{"x1":794,"y1":795,"x2":796,"y2":795,"stroke":783,"strokeWidth":784},"220","70","252",[798,799],"polygon",{"points":800,"fill":783},"252,65 262,70 252,75",[775,802],{"x":803,"y":778,"width":779,"height":780,"rx":781,"fill":782,"stroke":783,"strokeWidth":784},"262",[786,805,807],{"x":806,"y":789,"style":790},"362","wrap in a BaseModel",[689,809],{"x1":810,"y1":795,"x2":811,"y2":795,"stroke":783,"strokeWidth":784},"462","494",[798,813],{"points":814,"fill":783},"494,65 504,70 494,75",[775,816],{"x":817,"y":778,"width":779,"height":780,"rx":781,"fill":782,"stroke":783,"strokeWidth":784},"504",[786,819,821],{"x":820,"y":789,"style":790},"604","unwrap .items again",[775,823],{"x":777,"y":824,"width":779,"height":780,"rx":781,"fill":782,"stroke":825,"strokeWidth":826},"140","#00796B","2",[786,828,791],{"x":788,"y":829,"style":830},"174","text-anchor:middle;fill:#00796B;font:400 12px sans-serif",[689,832],{"x1":794,"y1":833,"x2":796,"y2":833,"stroke":825,"strokeWidth":784},"168",[798,835],{"points":836,"fill":825},"252,163 262,168 252,173",[775,838],{"x":803,"y":824,"width":779,"height":780,"rx":781,"fill":782,"stroke":825,"strokeWidth":826},[786,840,605],{"x":806,"y":829,"style":830},[689,842],{"x1":810,"y1":833,"x2":811,"y2":833,"stroke":825,"strokeWidth":784},[798,844],{"points":845,"fill":825},"494,163 504,168 494,173",[775,847],{"x":817,"y":824,"width":779,"height":780,"rx":781,"fill":782,"stroke":825,"strokeWidth":826},[786,849,850],{"x":820,"y":829,"style":830},"validated list[int]",[786,852,855],{"x":853,"y":854,"style":790},"360","232","Build the adapter once at import — never inside the handler.",[786,857,859],{"x":853,"y":858,"style":790},"254","Constructing it compiles the validator; calling it is cheap.",[652,861,863],{"id":862},"why-it-happens","Why It Happens",[590,865,866,867,869],{},"A ",[603,868,609],{}," subclass is two things at once: a schema and a namespace. When you define one, Pydantic's metaclass inspects the annotations, builds a core schema, and compiles it into a Rust validator and a Rust serializer that are then cached on the class.",[590,871,872,875,876,879,880,882,883,885,886,889],{},[603,873,874],{},"TypeAdapter"," separates those two roles. It takes any type expression — ",[603,877,878],{},"list[int]",", ",[603,881,661],{},", a dataclass, a ",[603,884,619],{},", an ",[603,887,888],{},"Annotated[...]"," with constraints, a discriminated union — and performs exactly the same compilation step, but stores the result on an ordinary object instead of on a class. You get the validator without needing a namespace to hang fields on.",[590,891,892],{},"This is not an obscure corner of the library. It is the machinery FastAPI itself uses: every query parameter, path parameter and non-model response annotation on your routes is validated through an adapter built from the function signature at import time.",[590,894,895,896,898,899,902],{},"Which points at the one performance rule that matters. Constructing a ",[603,897,874],{}," runs the schema build and the compile. Calling ",[603,900,901],{},"validate_python"," runs the compiled validator. The first is expensive and the second is cheap, so an adapter constructed inside a request handler pays the compile cost on every single request — a mistake with the same shape as compiling a regular expression in a loop, and about as costly.",[590,904,905,907,908,910],{},[603,906,625],{}," is a second, separate win. Handing Pydantic the raw bytes lets it parse and validate in a single pass in Rust, rather than having ",[603,909,629],{}," materialise a full tree of Python objects that the validator then walks and discards. The direction of that difference is reliable; the size depends entirely on your payloads, so measure rather than assume a figure.",[652,912,914],{"id":913},"the-fix","The Fix",[590,916,917],{},"Build one adapter per type, at module level, and call it wherever the payload arrives.",[678,919,921],{"className":680,"code":920,"language":682,"meta":683,"style":683},"\"\"\"Validate list[int], dicts and dataclasses with TypeAdapter — no BaseModel wrapper.\"\"\"\nfrom dataclasses import dataclass\nfrom typing import Annotated, TypedDict\n\nfrom pydantic import Field, TypeAdapter, ValidationError\n\n# Adapters are built ONCE at import time. Building one per call is the whole performance trap.\nIntList = TypeAdapter(list[int])\nPositiveIntList = TypeAdapter(list[Annotated[int, Field(gt=0)]])\nScoreMap = TypeAdapter(dict[str, float])\n\n\n@dataclass\nclass Sensor:\n    id: str\n    celsius: float\n    calibrated: bool = False\n\n\nSensorAdapter = TypeAdapter(Sensor)\nSensorListAdapter = TypeAdapter(list[Sensor])\n\n\nclass RowDict(TypedDict):\n    sku: str\n    quantity: int\n\n\nRowAdapter = TypeAdapter(RowDict)\n\n\ndef attempt(adapter: TypeAdapter, value: object) -> dict:\n    \"\"\"Validate and report the real result or the real error, never a summary of one.\"\"\"\n    try:\n        result = adapter.validate_python(value)\n    except ValidationError as exc:\n        return {\"ok\": False, \"errors\": exc.errors(include_url=False)}\n    return {\"ok\": True, \"value\": adapter.dump_python(result, mode=\"json\")}\n",[603,922,923,929,943,955,959,972,977,983,999,1026,1047,1052,1057,1064,1075,1087,1096,1111,1116,1121,1132,1143,1148,1153,1167,1175,1184,1189,1194,1205,1210,1215,1238,1244,1252,1263,1278,1313],{"__ignoreMap":683},[687,924,925],{"class":689,"line":690},[687,926,928],{"class":927},"sYEJz","\"\"\"Validate list[int], dicts and dataclasses with TypeAdapter — no BaseModel wrapper.\"\"\"\n",[687,930,931,934,937,940],{"class":689,"line":711},[687,932,933],{"class":693},"from",[687,935,936],{"class":701}," dataclasses ",[687,938,939],{"class":693},"import",[687,941,942],{"class":701}," dataclass\n",[687,944,945,947,950,952],{"class":689,"line":723},[687,946,933],{"class":693},[687,948,949],{"class":701}," typing ",[687,951,939],{"class":693},[687,953,954],{"class":701}," Annotated, TypedDict\n",[687,956,957],{"class":689,"line":730},[687,958,727],{"emptyLinePlaceholder":726},[687,960,962,964,967,969],{"class":689,"line":961},5,[687,963,933],{"class":693},[687,965,966],{"class":701}," pydantic ",[687,968,939],{"class":693},[687,970,971],{"class":701}," Field, TypeAdapter, ValidationError\n",[687,973,975],{"class":689,"line":974},6,[687,976,727],{"emptyLinePlaceholder":726},[687,978,980],{"class":689,"line":979},7,[687,981,982],{"class":750},"# Adapters are built ONCE at import time. Building one per call is the whole performance trap.\n",[687,984,986,989,991,994,996],{"class":689,"line":985},8,[687,987,988],{"class":701},"IntList ",[687,990,736],{"class":693},[687,992,993],{"class":701}," TypeAdapter(list[",[687,995,717],{"class":705},[687,997,998],{"class":701},"])\n",[687,1000,1002,1005,1007,1010,1012,1015,1018,1020,1023],{"class":689,"line":1001},9,[687,1003,1004],{"class":701},"PositiveIntList ",[687,1006,736],{"class":693},[687,1008,1009],{"class":701}," TypeAdapter(list[Annotated[",[687,1011,717],{"class":705},[687,1013,1014],{"class":701},", Field(",[687,1016,1017],{"class":697},"gt",[687,1019,736],{"class":693},[687,1021,1022],{"class":705},"0",[687,1024,1025],{"class":701},")]])\n",[687,1027,1029,1032,1034,1037,1040,1042,1045],{"class":689,"line":1028},10,[687,1030,1031],{"class":701},"ScoreMap ",[687,1033,736],{"class":693},[687,1035,1036],{"class":701}," TypeAdapter(dict[",[687,1038,1039],{"class":705},"str",[687,1041,879],{"class":701},[687,1043,1044],{"class":705},"float",[687,1046,998],{"class":701},[687,1048,1050],{"class":689,"line":1049},11,[687,1051,727],{"emptyLinePlaceholder":726},[687,1053,1055],{"class":689,"line":1054},12,[687,1056,727],{"emptyLinePlaceholder":726},[687,1058,1060],{"class":689,"line":1059},13,[687,1061,1063],{"class":1062},"s3dhs","@dataclass\n",[687,1065,1067,1069,1072],{"class":689,"line":1066},14,[687,1068,694],{"class":693},[687,1070,1071],{"class":697}," Sensor",[687,1073,1074],{"class":701},":\n",[687,1076,1078,1081,1084],{"class":689,"line":1077},15,[687,1079,1080],{"class":705},"    id",[687,1082,1083],{"class":701},": ",[687,1085,1086],{"class":705},"str\n",[687,1088,1090,1093],{"class":689,"line":1089},16,[687,1091,1092],{"class":701},"    celsius: ",[687,1094,1095],{"class":705},"float\n",[687,1097,1099,1102,1105,1108],{"class":689,"line":1098},17,[687,1100,1101],{"class":701},"    calibrated: ",[687,1103,1104],{"class":705},"bool",[687,1106,1107],{"class":693}," =",[687,1109,1110],{"class":705}," False\n",[687,1112,1114],{"class":689,"line":1113},18,[687,1115,727],{"emptyLinePlaceholder":726},[687,1117,1119],{"class":689,"line":1118},19,[687,1120,727],{"emptyLinePlaceholder":726},[687,1122,1124,1127,1129],{"class":689,"line":1123},20,[687,1125,1126],{"class":701},"SensorAdapter ",[687,1128,736],{"class":693},[687,1130,1131],{"class":701}," TypeAdapter(Sensor)\n",[687,1133,1135,1138,1140],{"class":689,"line":1134},21,[687,1136,1137],{"class":701},"SensorListAdapter ",[687,1139,736],{"class":693},[687,1141,1142],{"class":701}," TypeAdapter(list[Sensor])\n",[687,1144,1146],{"class":689,"line":1145},22,[687,1147,727],{"emptyLinePlaceholder":726},[687,1149,1151],{"class":689,"line":1150},23,[687,1152,727],{"emptyLinePlaceholder":726},[687,1154,1156,1158,1161,1163,1165],{"class":689,"line":1155},24,[687,1157,694],{"class":693},[687,1159,1160],{"class":697}," RowDict",[687,1162,702],{"class":701},[687,1164,619],{"class":705},[687,1166,708],{"class":701},[687,1168,1170,1173],{"class":689,"line":1169},25,[687,1171,1172],{"class":701},"    sku: ",[687,1174,1086],{"class":705},[687,1176,1178,1181],{"class":689,"line":1177},26,[687,1179,1180],{"class":701},"    quantity: ",[687,1182,1183],{"class":705},"int\n",[687,1185,1187],{"class":689,"line":1186},27,[687,1188,727],{"emptyLinePlaceholder":726},[687,1190,1192],{"class":689,"line":1191},28,[687,1193,727],{"emptyLinePlaceholder":726},[687,1195,1197,1200,1202],{"class":689,"line":1196},29,[687,1198,1199],{"class":701},"RowAdapter ",[687,1201,736],{"class":693},[687,1203,1204],{"class":701}," TypeAdapter(RowDict)\n",[687,1206,1208],{"class":689,"line":1207},30,[687,1209,727],{"emptyLinePlaceholder":726},[687,1211,1213],{"class":689,"line":1212},31,[687,1214,727],{"emptyLinePlaceholder":726},[687,1216,1218,1221,1224,1227,1230,1233,1236],{"class":689,"line":1217},32,[687,1219,1220],{"class":693},"def",[687,1222,1223],{"class":1062}," attempt",[687,1225,1226],{"class":701},"(adapter: TypeAdapter, value: ",[687,1228,1229],{"class":705},"object",[687,1231,1232],{"class":701},") -> ",[687,1234,1235],{"class":705},"dict",[687,1237,1074],{"class":701},[687,1239,1241],{"class":689,"line":1240},33,[687,1242,1243],{"class":927},"    \"\"\"Validate and report the real result or the real error, never a summary of one.\"\"\"\n",[687,1245,1247,1250],{"class":689,"line":1246},34,[687,1248,1249],{"class":693},"    try",[687,1251,1074],{"class":701},[687,1253,1255,1258,1260],{"class":689,"line":1254},35,[687,1256,1257],{"class":701},"        result ",[687,1259,736],{"class":693},[687,1261,1262],{"class":701}," adapter.validate_python(value)\n",[687,1264,1266,1269,1272,1275],{"class":689,"line":1265},36,[687,1267,1268],{"class":693},"    except",[687,1270,1271],{"class":701}," ValidationError ",[687,1273,1274],{"class":693},"as",[687,1276,1277],{"class":701}," exc:\n",[687,1279,1281,1284,1287,1290,1292,1295,1297,1300,1303,1306,1308,1310],{"class":689,"line":1280},37,[687,1282,1283],{"class":693},"        return",[687,1285,1286],{"class":701}," {",[687,1288,1289],{"class":927},"\"ok\"",[687,1291,1083],{"class":701},[687,1293,1294],{"class":705},"False",[687,1296,879],{"class":701},[687,1298,1299],{"class":927},"\"errors\"",[687,1301,1302],{"class":701},": exc.errors(",[687,1304,1305],{"class":697},"include_url",[687,1307,736],{"class":693},[687,1309,1294],{"class":705},[687,1311,1312],{"class":701},")}\n",[687,1314,1316,1319,1321,1323,1325,1328,1330,1333,1336,1339,1341,1344],{"class":689,"line":1315},38,[687,1317,1318],{"class":693},"    return",[687,1320,1286],{"class":701},[687,1322,1289],{"class":927},[687,1324,1083],{"class":701},[687,1326,1327],{"class":705},"True",[687,1329,879],{"class":701},[687,1331,1332],{"class":927},"\"value\"",[687,1334,1335],{"class":701},": adapter.dump_python(result, ",[687,1337,1338],{"class":697},"mode",[687,1340,736],{"class":693},[687,1342,1343],{"class":927},"\"json\"",[687,1345,1312],{"class":701},[590,1347,1348,1351,1352,1355,1356,1360,1361,1363],{},[603,1349,1350],{},"PositiveIntList"," is the one to look at twice. ",[603,1353,1354],{},"Annotated[int, Field(gt=0)]"," applies a constraint to the ",[1357,1358,1359],"em",{},"element"," type, which a ",[603,1362,609],{}," cannot express without inventing a field to hold the list. This is a class of validation that only exists once you can annotate bare types.",[590,1365,1366],{},"Here is what all of it actually does. Real output:",[678,1368,1372],{"className":1369,"code":1371,"language":786,"meta":683},[1370],"language-text","$ GET \u002Fvalidate\n200 OK\n{\n  \"list_of_int_from_strings\": {\n    \"ok\": true,\n    \"value\": [\n      1,\n      2,\n      3\n    ]\n  },\n  \"list_of_int_rejects_text\": {\n    \"ok\": false,\n    \"errors\": [\n      {\n        \"type\": \"int_parsing\",\n        \"loc\": [\n          1\n        ],\n        \"msg\": \"Input should be a valid integer, unable to parse string as an integer\",\n        \"input\": \"two\"\n      }\n    ]\n  },\n  \"positive_int_list_rejects_zero\": {\n    \"ok\": false,\n    \"errors\": [\n      {\n        \"type\": \"greater_than\",\n        \"loc\": [\n          1\n        ],\n        \"msg\": \"Input should be greater than 0\",\n        \"input\": 0,\n        \"ctx\": {\n          \"gt\": 0\n        }\n      }\n    ]\n  },\n  \"dict_of_float\": {\n    \"ok\": true,\n    \"value\": {\n      \"latency_p99\": 12.5,\n      \"error_rate\": 0.0\n    }\n  },\n  \"dataclass_from_dict\": {\n    \"ok\": true,\n    \"value\": {\n      \"id\": \"s-1\",\n      \"celsius\": 21.5,\n      \"calibrated\": false\n    }\n  },\n  \"dataclass_rejects_bad_field\": {\n    \"ok\": false,\n    \"errors\": [\n      {\n        \"type\": \"float_parsing\",\n        \"loc\": [\n          \"celsius\"\n        ],\n        \"msg\": \"Input should be a valid number, unable to parse string as a number\",\n        \"input\": \"warm\"\n      }\n    ]\n  },\n  \"list_of_dataclasses\": {\n    \"ok\": true,\n    \"value\": [\n      {\n        \"id\": \"s-1\",\n        \"celsius\": 21.5,\n        \"calibrated\": false\n      },\n      {\n        \"id\": \"s-2\",\n        \"celsius\": 19.0,\n        \"calibrated\": false\n      }\n    ]\n  },\n  \"typed_dict\": {\n    \"ok\": true,\n    \"value\": {\n      \"sku\": \"SKU-1\",\n      \"quantity\": 4\n    }\n  },\n  \"typed_dict_missing_key\": {\n    \"ok\": false,\n    \"errors\": [\n      {\n        \"type\": \"missing\",\n        \"loc\": [\n          \"quantity\"\n        ],\n        \"msg\": \"Field required\",\n        \"input\": {\n          \"sku\": \"SKU-1\"\n        }\n      }\n    ]\n  }\n}\n",[603,1373,1371],{"__ignoreMap":683},[590,1375,1376],{},"Several things in that output are worth naming.",[590,1378,1379,1380,1383,1384,1387,1388,1391,1392,1395,1396,1398],{},"Coercion is identical to a model field. ",[603,1381,1382],{},"[\"1\", \"2\", \"3\"]"," became ",[603,1385,1386],{},"[1, 2, 3]",", and the dataclass accepted ",[603,1389,1390],{},"\"celsius\": \"21.5\""," and produced the float ",[603,1393,1394],{},"21.5",". Nothing about being outside a ",[603,1397,609],{}," changes the rules.",[590,1400,1401,1402,1405,1406,1409],{},"Error locations are positional for sequences. The bad element in ",[603,1403,1404],{},"[1, \"two\", 3]"," reported ",[603,1407,1408],{},"\"loc\": [1]"," — the index, not a field name — which maps straight onto the input the caller sent. The element-level constraint behaved identically, flagging index 1 for the zero.",[590,1411,1412,1413,1416,1417,1420,1421,1424],{},"And the plain dataclass behaved like a model. It applied its own default for ",[603,1414,1415],{},"calibrated",", rejected an unparseable ",[603,1418,1419],{},"celsius",", and round-tripped through ",[603,1422,1423],{},"dump_python(mode=\"json\")",". No inheritance change, no decorator, no touching the existing class.",[590,1426,1427,1428,1430,1431,1434,1435,1438],{},"The ",[603,1429,619],{}," case is the one that most often surprises people: a missing key is a ",[603,1432,1433],{},"missing"," error located at the key name, exactly as a required model field would be, even though ",[603,1436,1437],{},"RowDict"," is a plain annotation over a dict.",[1440,1441,1443],"h3",{"id":1442},"schemas-and-raw-bytes","Schemas and raw bytes",[590,1445,1446],{},"An adapter documents itself, which matters when the payload you are describing is not an object:",[678,1448,1451],{"className":1449,"code":1450,"language":786,"meta":683},[1370],"$ GET \u002Fschema\n200 OK\n{\n  \"list_of_int\": {\n    \"items\": {\n      \"type\": \"integer\"\n    },\n    \"type\": \"array\"\n  },\n  \"dataclass\": {\n    \"properties\": {\n      \"id\": {\n        \"title\": \"Id\",\n        \"type\": \"string\"\n      },\n      \"celsius\": {\n        \"title\": \"Celsius\",\n        \"type\": \"number\"\n      },\n      \"calibrated\": {\n        \"default\": false,\n        \"title\": \"Calibrated\",\n        \"type\": \"boolean\"\n      }\n    },\n    \"required\": [\n      \"id\",\n      \"celsius\"\n    ],\n    \"title\": \"Sensor\",\n    \"type\": \"object\"\n  }\n}\n",[603,1452,1450],{"__ignoreMap":683},[590,1454,1455],{},"And parsing bytes straight from a queue or a socket skips the intermediate Python objects entirely:",[678,1457,1460],{"className":1458,"code":1459,"language":786,"meta":683},[1370],"$ GET \u002Fparse-bytes\n200 OK\n{\n  \"parsed\": [\n    {\n      \"id\": \"s-9\",\n      \"celsius\": 30.25,\n      \"calibrated\": true\n    }\n  ]\n}\n",[603,1461,1459],{"__ignoreMap":683},[590,1463,1464,1465,1468,1469,1471],{},"That result came from ",[603,1466,1467],{},"SensorListAdapter.validate_json(b'[{\"id\":\"s-9\",\"celsius\":30.25,\"calibrated\":true}]')"," — raw bytes to validated dataclasses in one call, with no ",[603,1470,629],{}," in between.",[652,1473,1475],{"id":1474},"verification","Verification",[590,1477,1478],{},"The regression that costs you real latency is an adapter built in the wrong place, and it is easy to assert against:",[678,1480,1482],{"className":680,"code":1481,"language":682,"meta":683,"style":683},"def test_adapters_are_module_level():\n    \"\"\"A TypeAdapter constructed per call recompiles the validator every time.\"\"\"\n    source = Path(\"app\").rglob(\"*.py\")\n    for path in source:\n        for lineno, line in enumerate(path.read_text().splitlines(), 1):\n            if \"TypeAdapter(\" in line and line.startswith((\" \", \"\\t\")):\n                raise AssertionError(f\"{path}:{lineno} builds an adapter inside a function\")\n",[603,1483,1484,1494,1499,1521,1535,1556,1592],{"__ignoreMap":683},[687,1485,1486,1488,1491],{"class":689,"line":690},[687,1487,1220],{"class":693},[687,1489,1490],{"class":1062}," test_adapters_are_module_level",[687,1492,1493],{"class":701},"():\n",[687,1495,1496],{"class":689,"line":711},[687,1497,1498],{"class":927},"    \"\"\"A TypeAdapter constructed per call recompiles the validator every time.\"\"\"\n",[687,1500,1501,1504,1506,1509,1512,1515,1518],{"class":689,"line":723},[687,1502,1503],{"class":701},"    source ",[687,1505,736],{"class":693},[687,1507,1508],{"class":701}," Path(",[687,1510,1511],{"class":927},"\"app\"",[687,1513,1514],{"class":701},").rglob(",[687,1516,1517],{"class":927},"\"*.py\"",[687,1519,1520],{"class":701},")\n",[687,1522,1523,1526,1529,1532],{"class":689,"line":730},[687,1524,1525],{"class":693},"    for",[687,1527,1528],{"class":701}," path ",[687,1530,1531],{"class":693},"in",[687,1533,1534],{"class":701}," source:\n",[687,1536,1537,1540,1543,1545,1548,1551,1554],{"class":689,"line":961},[687,1538,1539],{"class":693},"        for",[687,1541,1542],{"class":701}," lineno, line ",[687,1544,1531],{"class":693},[687,1546,1547],{"class":705}," enumerate",[687,1549,1550],{"class":701},"(path.read_text().splitlines(), ",[687,1552,1553],{"class":705},"1",[687,1555,708],{"class":701},[687,1557,1558,1561,1564,1567,1570,1573,1576,1579,1581,1584,1587,1589],{"class":689,"line":974},[687,1559,1560],{"class":693},"            if",[687,1562,1563],{"class":927}," \"TypeAdapter(\"",[687,1565,1566],{"class":693}," in",[687,1568,1569],{"class":701}," line ",[687,1571,1572],{"class":693},"and",[687,1574,1575],{"class":701}," line.startswith((",[687,1577,1578],{"class":927},"\" \"",[687,1580,879],{"class":701},[687,1582,1583],{"class":927},"\"",[687,1585,1586],{"class":693},"\\t",[687,1588,1583],{"class":927},[687,1590,1591],{"class":701},")):\n",[687,1593,1594,1597,1600,1602,1605,1607,1610,1613,1616,1619,1621,1624,1626,1629],{"class":689,"line":979},[687,1595,1596],{"class":693},"                raise",[687,1598,1599],{"class":705}," AssertionError",[687,1601,702],{"class":701},[687,1603,1604],{"class":693},"f",[687,1606,1583],{"class":927},[687,1608,1609],{"class":693},"{",[687,1611,1612],{"class":701},"path",[687,1614,1615],{"class":693},"}",[687,1617,1618],{"class":927},":",[687,1620,1609],{"class":693},[687,1622,1623],{"class":701},"lineno",[687,1625,1615],{"class":693},[687,1627,1628],{"class":927}," builds an adapter inside a function\"",[687,1630,1520],{"class":701},[590,1632,1633,1634,1637],{},"Crude, and it catches the thing. If you prefer a runtime check, profile a handler and look for ",[603,1635,1636],{},"_pydantic_core.SchemaValidator"," construction in the trace — it should not appear once the process has warmed up.",[590,1639,1640],{},"Then assert the behaviour you actually depend on. Adapters are usually applied at trust boundaries, so the failure case is the interesting one:",[678,1642,1644],{"className":680,"code":1643,"language":682,"meta":683,"style":683},"def test_queue_payload_rejects_bad_element():\n    with pytest.raises(ValidationError) as excinfo:\n        IntList.validate_python([1, \"two\", 3])\n    assert excinfo.value.errors()[0][\"loc\"] == (1,)\n",[603,1645,1646,1655,1668,1687],{"__ignoreMap":683},[687,1647,1648,1650,1653],{"class":689,"line":690},[687,1649,1220],{"class":693},[687,1651,1652],{"class":1062}," test_queue_payload_rejects_bad_element",[687,1654,1493],{"class":701},[687,1656,1657,1660,1663,1665],{"class":689,"line":711},[687,1658,1659],{"class":693},"    with",[687,1661,1662],{"class":701}," pytest.raises(ValidationError) ",[687,1664,1274],{"class":693},[687,1666,1667],{"class":701}," excinfo:\n",[687,1669,1670,1673,1675,1677,1680,1682,1685],{"class":689,"line":723},[687,1671,1672],{"class":701},"        IntList.validate_python([",[687,1674,1553],{"class":705},[687,1676,879],{"class":701},[687,1678,1679],{"class":927},"\"two\"",[687,1681,879],{"class":701},[687,1683,1684],{"class":705},"3",[687,1686,998],{"class":701},[687,1688,1689,1692,1695,1697,1700,1703,1706,1709,1712,1714],{"class":689,"line":730},[687,1690,1691],{"class":693},"    assert",[687,1693,1694],{"class":701}," excinfo.value.errors()[",[687,1696,1022],{"class":705},[687,1698,1699],{"class":701},"][",[687,1701,1702],{"class":927},"\"loc\"",[687,1704,1705],{"class":701},"] ",[687,1707,1708],{"class":693},"==",[687,1710,1711],{"class":701}," (",[687,1713,1553],{"class":705},[687,1715,1716],{"class":701},",)\n",[652,1718,1720],{"id":1719},"trade-offs-and-when-not-to","Trade-offs and When Not To",[590,1722,1723,1729,1730,1732],{},[593,1724,1725,1726,1728],{},"Use a ",[603,1727,609],{}," when the thing genuinely is an object."," A request body with named fields belongs in a model — you get the class as a namespace for validators, computed fields, config and methods, and FastAPI gets a named schema in the OpenAPI document. ",[603,1731,874],{}," is for the cases where that namespace would be empty.",[590,1734,1735,1738],{},[593,1736,1737],{},"Adapters are not free to hold."," Each one keeps a compiled validator and serializer alive. A handful per module is nothing; generating them dynamically per tenant or per request in a long-lived process is a slow memory leak. If you must build them dynamically, cache them in a dict keyed by type.",[590,1740,1741,1744,1745,1748,1749,1752,1753,1755,1756,1759],{},[593,1742,1743],{},"A dataclass is not upgraded by being adapted."," ",[603,1746,1747],{},"TypeAdapter(Sensor)"," validates data ",[1357,1750,1751],{},"into"," a ",[603,1754,669],{},"; it does not make ",[603,1757,1758],{},"Sensor(celsius=\"warm\")"," raise. Constructing the dataclass directly still bypasses everything, so the adapter has to be on the path the data actually takes.",[590,1761,1762,1765,1766,1768,1769,1772],{},[593,1763,1764],{},"Errors have no model name to anchor on."," A model's ",[603,1767,636],{}," says which model failed. An adapter's says ",[603,1770,1771],{},"loc: [1]",", which is precise about position and silent about what was being parsed. When you surface these to users, add the context yourself — \"message 47 in batch 12\" is what makes index 1 actionable.",[590,1774,1775,1778,1779,1781,1782,1784],{},[593,1776,1777],{},"FastAPI request bodies do not need this."," Annotating a route parameter as ",[603,1780,878],{}," already causes FastAPI to build an adapter for you. Reach for an explicit ",[603,1783,874],{}," for data that arrives outside the request cycle: queue messages, cached values, JSON columns, third-party webhooks parsed after a signature check, and background jobs.",[590,1786,1787,1788,1791,1792,1795,1796,673],{},"For the serialization side of the same problem — ",[603,1789,1790],{},"dump_python"," versus ",[603,1793,1794],{},"model_dump_json",", and where the time goes — see ",[646,1797,1799],{"href":1798},"\u002Fadvanced-pydantic-validation-serialization\u002Fperformance-optimization-for-models\u002Fpydantic-model-serialization-performance\u002F","Pydantic Model Serialization Performance",[652,1801,1803],{"id":1802},"faq","FAQ",[590,1805,1806,1809,1810,1812],{},[593,1807,1808],{},"When should I use TypeAdapter instead of a BaseModel?","\nWhenever the thing you are validating is not naturally an object with named fields — a bare list, a mapping, a dataclass you already own, or a union. Wrapping those in a ",[603,1811,609],{}," adds an envelope key that then has to be unwrapped everywhere, and buys nothing.",[590,1814,1815,1818],{},[593,1816,1817],{},"Why must a TypeAdapter be built once and reused?","\nConstructing one compiles a validator and a serializer for the type, which is the expensive part. Building it inside a request handler pays that cost on every request; building it at module level pays it once at import, which is the same thing FastAPI does for your route signatures.",[590,1820,1821,1824,1825,1827,1828,1831,1832,1834,1835,1837],{},[593,1822,1823],{},"Does TypeAdapter validate dataclasses and TypedDicts?","\nYes. It handles standard library dataclasses, ",[603,1826,619],{},"s, ",[603,1829,1830],{},"NamedTuple","s, unions, primitives and any nesting of them, applying the same coercion and constraint rules a ",[603,1833,609],{}," field would get. A real run coerced the string ",[603,1836,1394],{}," into a float on a plain dataclass.",[590,1839,1840,1843,1844,1847],{},[593,1841,1842],{},"How do I get JSON Schema for a bare type?","\nCall ",[603,1845,1846],{},"json_schema()"," on the adapter. It returns the same schema fragment the type would generate as a model field, which is what you need when documenting a payload that is a list or a union rather than an object.",[590,1849,1850,1853],{},[593,1851,1852],{},"Is validate_json faster than json.loads plus validate_python?","\nIt does strictly less work, because Pydantic parses the JSON and validates in one pass in Rust rather than building intermediate Python objects and then walking them. Measure it against your own payloads, but the direction is reliable for large documents.",[652,1855,1857],{"id":1856},"related-reading","Related Reading",[597,1859,1860,1867,1872,1879,1886],{},[600,1861,1862,1744,1865,673],{},[593,1863,1864],{},"Up to the topic:",[646,1866,649],{"href":648},[600,1868,1869,1870,673],{},"The serialization half of the story: ",[646,1871,1799],{"href":1798},[600,1873,1874,1875,673],{},"The other way to spend less time validating, and what it costs: ",[646,1876,1878],{"href":1877},"\u002Fadvanced-pydantic-validation-serialization\u002Fperformance-optimization-for-models\u002Fmodel-construct-when-to-skip-validation\u002F","model_construct and When to Skip Validation",[600,1880,1881,1882,673],{},"Adapting a tagged union outside a request body: ",[646,1883,1885],{"href":1884},"\u002Fadvanced-pydantic-validation-serialization\u002Fjson-schema-customization\u002Fdiscriminated-unions-in-openapi\u002F","Discriminated Unions in OpenAPI",[600,1887,1888,1889,673],{},"Reusing annotated types across a codebase: ",[646,1890,1892],{"href":1891},"\u002Fadvanced-pydantic-validation-serialization\u002Ftype-hinting-ide-integration\u002Fannotated-dependencies-and-reusable-types\u002F","Annotated Dependencies and Reusable Types",[1894,1895,1896],"style",{},"html pre.shiki code .sTJeM, html code.shiki .sTJeM{--shiki-default:#A0111F}html pre.shiki code .sV4o_, html code.shiki .sV4o_{--shiki-default:#702C00}html pre.shiki code .sigWx, html code.shiki .sigWx{--shiki-default:#0E1116}html pre.shiki code .sacAq, html code.shiki .sacAq{--shiki-default:#023B95}html pre.shiki code .sFeEa, html code.shiki .sFeEa{--shiki-default:#66707B}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);}html pre.shiki code .sYEJz, html code.shiki .sYEJz{--shiki-default:#032563}html pre.shiki code .s3dhs, html code.shiki .s3dhs{--shiki-default:#622CBC}",{"title":683,"searchDepth":711,"depth":711,"links":1898},[1899,1900,1901,1904,1905,1906,1907],{"id":654,"depth":711,"text":655},{"id":862,"depth":711,"text":863},{"id":913,"depth":711,"text":914,"children":1902},[1903],{"id":1442,"depth":723,"text":1443},{"id":1474,"depth":711,"text":1475},{"id":1719,"depth":711,"text":1720},{"id":1802,"depth":711,"text":1803},{"id":1856,"depth":711,"text":1857},"2026-07-20","Validate list[int], dicts, dataclasses and TypedDicts with Pydantic's TypeAdapter instead of a BaseModel wrapper, and reuse one compiled adapter per type.","md",[1912,1914,1916,1918,1920],{"q":1808,"a":1913},"Whenever the thing you are validating is not naturally an object with named fields — a bare list, a mapping, a dataclass you already own, or a union. Wrapping those in a BaseModel adds an envelope key that then has to be unwrapped everywhere, and buys nothing.",{"q":1817,"a":1915},"Constructing one compiles a validator and a serializer for the type, which is the expensive part. Building it inside a request handler pays that cost on every request; building it at module level pays it once at import, which is the same thing FastAPI does for your route signatures.",{"q":1823,"a":1917},"Yes. It handles standard library dataclasses, TypedDicts, NamedTuples, unions, primitives and any nesting of them, applying the same coercion and constraint rules a BaseModel field would get. A real run coerced the string 21.5 into a float on a plain dataclass.",{"q":1842,"a":1919},"Call json_schema() on the adapter. It returns the same schema fragment the type would generate as a model field, which is what you need when documenting a payload that is a list or a union rather than an object.",{"q":1852,"a":1921},"It does strictly less work, because Pydantic parses the JSON and validates in one pass in Rust rather than building intermediate Python objects and then walking them. Measure it against your own payloads, but the direction is reliable for large documents.",null,{"slug":1924,"breadcrumb":1925},"typeadapter-for-non-model-types",[1926,1929,1932,1933],{"label":1927,"path":1928},"Home","\u002F",{"label":1930,"path":1931},"Advanced Pydantic Validation & Serialization","\u002Fadvanced-pydantic-validation-serialization\u002F",{"label":649,"path":648},{"label":1934,"path":1935},"TypeAdapter for Non-Model Types","\u002Fadvanced-pydantic-validation-serialization\u002Fperformance-optimization-for-models\u002Ftypeadapter-for-non-model-types\u002F",{"title":109,"description":1909},"article","ypKEBpTi9kEeLFqUUVmiaAQeshoqdRLbY7b6MsuEEv8",[1922,1922],1784588202620]