[{"data":1,"prerenderedAt":2317},["ShallowReactive",2],{"nav":3,"page-\u002Fcore-architecture-routing-patterns\u002Fdependency-injection-strategies\u002Fdependency-caching-and-use-cache\u002F":580,"surround-\u002Fcore-architecture-routing-patterns\u002Fdependency-injection-strategies\u002Fdependency-caching-and-use-cache\u002F":2316},[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":449,"body":582,"dateModified":2285,"datePublished":2285,"description":2286,"extension":2287,"faq":2288,"howto":2299,"meta":2300,"navigation":921,"path":450,"seo":2313,"stem":451,"type":2314,"__hash__":2315},"content\u002Fcore-architecture-routing-patterns\u002Fdependency-injection-strategies\u002Fdependency-caching-and-use-cache\u002Findex.md",{"type":583,"value":584,"toc":2275},"minimark",[585,589,596,623,636,641,656,659,798,802,809,818,821,840,857,860,864,871,1773,1776,1782,1785,1799,1822,1849,1860,1864,1867,1952,1964,1968,1971,2087,2102,2109,2113,2126,2144,2154,2173,2177,2186,2192,2198,2204,2222,2226,2271],[586,587,449],"h1",{"id":588},"dependency-caching-and-use_cache-in-fastapi",[590,591,592],"p",{},[593,594,595],"strong",{},"Key takeaways:",[597,598,599,603,606,613,620],"ul",{},[600,601,602],"li",{},"Within one request, a dependency callable is resolved once and every later consumer gets the cached value — this is why fine-grained dependencies are cheap.",[600,604,605],{},"The cache key is the callable object plus its security scopes, compared by identity. Two functions that look identical are two cache entries.",[600,607,608,612],{},[609,610,611],"code",{},"Depends(fn, use_cache=False)"," forces re-evaluation at that declaration site only; it does not disable caching for the rest of the graph.",[600,614,615,616,619],{},"The cache is per request, not per process. For something genuinely global, wrap the provider in ",[609,617,618],{},"functools.lru_cache",".",[600,621,622],{},"A dependency that \"runs twice for no reason\" is nearly always two distinct callable objects, not a caching bug.",[590,624,625,626,631,632,635],{},"This page drills into one specific behaviour of ",[627,628,630],"a",{"href":629},"\u002Fcore-architecture-routing-patterns\u002Fdependency-injection-strategies\u002F","dependency injection strategies",": what FastAPI remembers between two ",[609,633,634],{},"Depends()"," declarations in the same request, and what it deliberately does not.",[637,638,640],"h2",{"id":639},"the-problem-this-solves","The Problem This Solves",[590,642,643,644,647,648,651,652,655],{},"You add a ",[609,645,646],{},"get_settings"," dependency, then a ",[609,649,650],{},"get_current_user"," that depends on it, then a ",[609,653,654],{},"get_db"," that also depends on it. Three consumers, one provider. Does the provider run once or three times? If it opens a file, decodes a JWT, or hits Redis, the answer decides whether your dependency graph is free or is quietly tripling your per-request work.",[590,657,658],{},"The opposite failure is just as common: you deliberately want a dependency to run once per declaration — an audit hook, a rate-limit counter — and it silently collapses into a single call because FastAPI cached it.",[660,661,662,794],"figure",{},[663,664,672,673,672,677,672,681,672,690,672,697,672,702,672,709,672,714,672,717,672,720,672,725,672,731,672,735,672,741,672,744,672,748,672,755,672,757,672,761,672,767,672,769,672,773,672,779,672,784,672,789],"svg",{"viewBox":665,"role":666,"ariaLabelledBy":667,"xmlns":670,"style":671},"0 0 720 320","img",[668,669],"cache-t","cache-d","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg","width:100%;height:auto;max-width:720px;margin:2rem 0","\n  ",[674,675,676],"title",{"id":668},"Per-request dependency cache with one shared provider",[678,679,680],"desc",{"id":669},"A handler depends on get_db and get_user; both depend on get_settings. get_settings executes once and the second consumer receives a cache hit. A third declaration marked use_cache equals False bypasses the cache and executes again.",[682,683],"rect",{"x":684,"y":685,"width":686,"height":687,"rx":688,"style":689},"255","16","210","46","8","fill:#E0F2F1;stroke:#00796B;stroke-width:2px",[691,692,696],"text",{"x":693,"y":694,"style":695},"360","38","text-anchor:middle;fill:#00695C;font:700 13px sans-serif","Route handler",[691,698,701],{"x":693,"y":699,"style":700},"54","text-anchor:middle;fill:#4B5563;font:400 11px sans-serif","one request",[682,703],{"x":704,"y":705,"width":706,"height":707,"rx":688,"style":708},"60","110","170","44","fill:#FFFFFF;stroke:currentColor;stroke-width:1.5px",[691,710,654],{"x":711,"y":712,"style":713},"145","137","text-anchor:middle;fill:currentColor;font:600 13px sans-serif",[682,715],{"x":716,"y":705,"width":706,"height":707,"rx":688,"style":708},"275",[691,718,719],{"x":693,"y":712,"style":713},"get_user",[682,721],{"x":722,"y":705,"width":723,"height":707,"rx":688,"style":724},"490","180","fill:#FFFFFF;stroke:#00796B;stroke-width:1.5px",[691,726,730],{"x":727,"y":728,"style":729},"580","130","text-anchor:middle;fill:currentColor;font:600 12px sans-serif","use_cache=False",[691,732,734],{"x":727,"y":733,"style":700},"146","bypasses the cache",[682,736],{"x":737,"y":738,"width":739,"height":740,"rx":688,"style":689},"230","216","260","52",[691,742,646],{"x":693,"y":743,"style":695},"238",[691,745,747],{"x":693,"y":746,"style":700},"256","executes once per request",[749,750],"line",{"x1":751,"y1":752,"x2":706,"y2":753,"style":754},"320","62","106","stroke:#00796B;stroke-width:1.6px",[749,756],{"x1":693,"y1":752,"x2":693,"y2":753,"style":754},[749,758],{"x1":759,"y1":752,"x2":760,"y2":753,"style":754},"400","555",[749,762],{"x1":763,"y1":764,"x2":765,"y2":766,"style":754},"160","154","270","214",[749,768],{"x1":693,"y1":764,"x2":693,"y2":766,"style":754},[749,770],{"x1":771,"y1":764,"x2":772,"y2":766,"style":754},"560","450",[691,774,778],{"x":775,"y":776,"style":777},"196","192","text-anchor:middle;fill:#00695C;font:600 11px sans-serif","miss: runs",[691,780,783],{"x":781,"y":776,"style":782},"372","text-anchor:start;fill:#00695C;font:600 11px sans-serif","hit: reused",[691,785,788],{"x":786,"y":776,"style":787},"524","text-anchor:middle;fill:#B00020;font:600 11px sans-serif","runs again",[691,790,793],{"x":693,"y":791,"style":792},"296","text-anchor:middle;fill:#4B5563;font:400 12px sans-serif","The cache is discarded when the request ends.",[795,796,797],"figcaption",{},"Within one request a provider resolves once; later consumers get the stored value unless they opt out.",[637,799,801],{"id":800},"why-it-happens-the-per-request-solved-cache","Why It Happens: the Per-Request Solved Cache",[590,803,804,805,808],{},"When a request arrives, FastAPI builds a ",[609,806,807],{},"dict"," of solved dependencies for that request and threads it through the whole resolution pass. Before it calls a provider, it constructs a cache key and checks that dict. The key is a two-part tuple:",[810,811,816],"pre",{"className":812,"code":814,"language":691,"meta":815},[813],"language-text","(the dependency callable object, tuple(sorted(security_scopes)))\n","",[609,817,814],{"__ignoreMap":815},[590,819,820],{},"Two things follow from that shape, and between them they explain nearly every caching surprise people hit in production.",[590,822,823,826,827,830,831,835,836,839],{},[593,824,825],{},"The callable is compared by identity, not by name or source."," ",[609,828,829],{},"dependency_overrides"," works on exactly the same principle, which is why ",[627,832,834],{"href":833},"\u002Fcore-architecture-routing-patterns\u002Fdependency-injection-strategies\u002Foverriding-dependencies-in-tests\u002F","overriding dependencies in tests"," silently does nothing if you hand it a different-but-equivalent function. A closure returned twice from a factory produces two objects, so it produces two cache entries — even though ",[609,837,838],{},"__name__"," is identical for both.",[590,841,842,845,846,848,849,852,853,856],{},[593,843,844],{},"Security scopes are part of the key."," The same ",[609,847,650],{}," requested with ",[609,850,851],{},"Security(get_current_user, scopes=[\"read\"])"," and with ",[609,854,855],{},"scopes=[\"write\"]"," resolves twice, because the scopes it is being asked for differ and the answer legitimately might too.",[590,858,859],{},"The cache dictionary is created per request and thrown away with it. There is no cross-request memoization anywhere in the DI machinery.",[637,861,863],{"id":862},"proving-it-real-call-counts","Proving It: Real Call Counts",[590,865,866,867,870],{},"The only convincing way to settle \"does it run once or three times\" is to count. This app increments a module-level ",[609,868,869],{},"Counter"," inside each provider, clears it at the start of every request in middleware, and returns the counts in the response body.",[810,872,876],{"className":873,"code":874,"language":875,"meta":815,"style":815},"language-python shiki shiki-themes github-light-high-contrast","\"\"\"use_cache semantics: when a dependency is evaluated once vs repeatedly in one request.\"\"\"\nfrom collections import Counter\nfrom typing import Annotated\n\nfrom fastapi import Depends, FastAPI, Request\n\napp = FastAPI()\n\nCALLS: Counter = Counter()\n\n\n@app.middleware(\"http\")\nasync def reset_counters(request: Request, call_next):\n    CALLS.clear()                      # Each transcript line starts from zero.\n    return await call_next(request)\n\n\nasync def get_settings() -> dict:\n    CALLS[\"get_settings\"] += 1\n    return {\"env\": \"prod\"}\n\n\nasync def get_db(settings: Annotated[dict, Depends(get_settings)]) -> str:\n    CALLS[\"get_db\"] += 1\n    return \"session\"\n\n\nasync def get_user(settings: Annotated[dict, Depends(get_settings)]) -> str:\n    CALLS[\"get_user\"] += 1\n    return \"alice\"\n\n\nasync def get_settings_uncached(\n    settings: Annotated[dict, Depends(get_settings, use_cache=False)],\n) -> dict:\n    return settings\n\n\ndef make_rate_limiter():\n    \"\"\"Two calls to this factory produce two distinct callables with the same __name__.\"\"\"\n\n    async def rate_limit() -> bool:\n        CALLS[\"rate_limit\"] += 1\n        return True\n\n    return rate_limit\n\n\nlimiter_a = make_rate_limiter()\nlimiter_b = make_rate_limiter()\n\n\n@app.get(\"\u002Fcached\")\nasync def cached(\n    db: Annotated[str, Depends(get_db)],\n    user: Annotated[str, Depends(get_user)],\n    settings: Annotated[dict, Depends(get_settings)],\n):\n    return {\"calls\": dict(CALLS)}\n\n\n@app.get(\"\u002Funcached\")\nasync def uncached(\n    db: Annotated[str, Depends(get_db)],\n    user: Annotated[str, Depends(get_user)],\n    fresh: Annotated[dict, Depends(get_settings_uncached)],\n    also_fresh: Annotated[dict, Depends(get_settings, use_cache=False)],\n):\n    return {\"calls\": dict(CALLS)}\n\n\n@app.get(\"\u002Ftwo-limiters\", dependencies=[Depends(limiter_a), Depends(limiter_b)])\nasync def two_limiters():\n    return {\n        \"same_name\": limiter_a.__name__ == limiter_b.__name__,\n        \"same_object\": limiter_a is limiter_b,\n        \"calls\": dict(CALLS),\n    }\n\n\n@app.get(\"\u002Fone-limiter\", dependencies=[Depends(limiter_a), Depends(limiter_a)])\nasync def one_limiter():\n    return {\"calls\": dict(CALLS)}\n","python",[609,877,878,886,903,916,923,936,941,953,958,973,978,983,999,1014,1027,1039,1044,1049,1067,1087,1107,1112,1117,1140,1156,1164,1169,1174,1194,1210,1218,1223,1228,1241,1264,1274,1282,1287,1292,1304,1310,1315,1333,1350,1359,1364,1372,1377,1382,1393,1403,1408,1413,1426,1438,1449,1460,1470,1476,1497,1502,1507,1519,1531,1540,1549,1560,1578,1583,1602,1607,1612,1633,1645,1653,1675,1690,1707,1713,1718,1723,1742,1754],{"__ignoreMap":815},[879,880,882],"span",{"class":749,"line":881},1,[879,883,885],{"class":884},"sYEJz","\"\"\"use_cache semantics: when a dependency is evaluated once vs repeatedly in one request.\"\"\"\n",[879,887,889,893,897,900],{"class":749,"line":888},2,[879,890,892],{"class":891},"sTJeM","from",[879,894,896],{"class":895},"sigWx"," collections ",[879,898,899],{"class":891},"import",[879,901,902],{"class":895}," Counter\n",[879,904,906,908,911,913],{"class":749,"line":905},3,[879,907,892],{"class":891},[879,909,910],{"class":895}," typing ",[879,912,899],{"class":891},[879,914,915],{"class":895}," Annotated\n",[879,917,919],{"class":749,"line":918},4,[879,920,922],{"emptyLinePlaceholder":921},true,"\n",[879,924,926,928,931,933],{"class":749,"line":925},5,[879,927,892],{"class":891},[879,929,930],{"class":895}," fastapi ",[879,932,899],{"class":891},[879,934,935],{"class":895}," Depends, FastAPI, Request\n",[879,937,939],{"class":749,"line":938},6,[879,940,922],{"emptyLinePlaceholder":921},[879,942,944,947,950],{"class":749,"line":943},7,[879,945,946],{"class":895},"app ",[879,948,949],{"class":891},"=",[879,951,952],{"class":895}," FastAPI()\n",[879,954,956],{"class":749,"line":955},8,[879,957,922],{"emptyLinePlaceholder":921},[879,959,961,965,968,970],{"class":749,"line":960},9,[879,962,964],{"class":963},"sacAq","CALLS",[879,966,967],{"class":895},": Counter ",[879,969,949],{"class":891},[879,971,972],{"class":895}," Counter()\n",[879,974,976],{"class":749,"line":975},10,[879,977,922],{"emptyLinePlaceholder":921},[879,979,981],{"class":749,"line":980},11,[879,982,922],{"emptyLinePlaceholder":921},[879,984,986,990,993,996],{"class":749,"line":985},12,[879,987,989],{"class":988},"s3dhs","@app.middleware",[879,991,992],{"class":895},"(",[879,994,995],{"class":884},"\"http\"",[879,997,998],{"class":895},")\n",[879,1000,1002,1005,1008,1011],{"class":749,"line":1001},13,[879,1003,1004],{"class":891},"async",[879,1006,1007],{"class":891}," def",[879,1009,1010],{"class":988}," reset_counters",[879,1012,1013],{"class":895},"(request: Request, call_next):\n",[879,1015,1017,1020,1023],{"class":749,"line":1016},14,[879,1018,1019],{"class":963},"    CALLS",[879,1021,1022],{"class":895},".clear()                      ",[879,1024,1026],{"class":1025},"sFeEa","# Each transcript line starts from zero.\n",[879,1028,1030,1033,1036],{"class":749,"line":1029},15,[879,1031,1032],{"class":891},"    return",[879,1034,1035],{"class":891}," await",[879,1037,1038],{"class":895}," call_next(request)\n",[879,1040,1042],{"class":749,"line":1041},16,[879,1043,922],{"emptyLinePlaceholder":921},[879,1045,1047],{"class":749,"line":1046},17,[879,1048,922],{"emptyLinePlaceholder":921},[879,1050,1052,1054,1056,1059,1062,1064],{"class":749,"line":1051},18,[879,1053,1004],{"class":891},[879,1055,1007],{"class":891},[879,1057,1058],{"class":988}," get_settings",[879,1060,1061],{"class":895},"() -> ",[879,1063,807],{"class":963},[879,1065,1066],{"class":895},":\n",[879,1068,1070,1072,1075,1078,1081,1084],{"class":749,"line":1069},19,[879,1071,1019],{"class":963},[879,1073,1074],{"class":895},"[",[879,1076,1077],{"class":884},"\"get_settings\"",[879,1079,1080],{"class":895},"] ",[879,1082,1083],{"class":891},"+=",[879,1085,1086],{"class":963}," 1\n",[879,1088,1090,1092,1095,1098,1101,1104],{"class":749,"line":1089},20,[879,1091,1032],{"class":891},[879,1093,1094],{"class":895}," {",[879,1096,1097],{"class":884},"\"env\"",[879,1099,1100],{"class":895},": ",[879,1102,1103],{"class":884},"\"prod\"",[879,1105,1106],{"class":895},"}\n",[879,1108,1110],{"class":749,"line":1109},21,[879,1111,922],{"emptyLinePlaceholder":921},[879,1113,1115],{"class":749,"line":1114},22,[879,1116,922],{"emptyLinePlaceholder":921},[879,1118,1120,1122,1124,1127,1130,1132,1135,1138],{"class":749,"line":1119},23,[879,1121,1004],{"class":891},[879,1123,1007],{"class":891},[879,1125,1126],{"class":988}," get_db",[879,1128,1129],{"class":895},"(settings: Annotated[",[879,1131,807],{"class":963},[879,1133,1134],{"class":895},", Depends(get_settings)]) -> ",[879,1136,1137],{"class":963},"str",[879,1139,1066],{"class":895},[879,1141,1143,1145,1147,1150,1152,1154],{"class":749,"line":1142},24,[879,1144,1019],{"class":963},[879,1146,1074],{"class":895},[879,1148,1149],{"class":884},"\"get_db\"",[879,1151,1080],{"class":895},[879,1153,1083],{"class":891},[879,1155,1086],{"class":963},[879,1157,1159,1161],{"class":749,"line":1158},25,[879,1160,1032],{"class":891},[879,1162,1163],{"class":884}," \"session\"\n",[879,1165,1167],{"class":749,"line":1166},26,[879,1168,922],{"emptyLinePlaceholder":921},[879,1170,1172],{"class":749,"line":1171},27,[879,1173,922],{"emptyLinePlaceholder":921},[879,1175,1177,1179,1181,1184,1186,1188,1190,1192],{"class":749,"line":1176},28,[879,1178,1004],{"class":891},[879,1180,1007],{"class":891},[879,1182,1183],{"class":988}," get_user",[879,1185,1129],{"class":895},[879,1187,807],{"class":963},[879,1189,1134],{"class":895},[879,1191,1137],{"class":963},[879,1193,1066],{"class":895},[879,1195,1197,1199,1201,1204,1206,1208],{"class":749,"line":1196},29,[879,1198,1019],{"class":963},[879,1200,1074],{"class":895},[879,1202,1203],{"class":884},"\"get_user\"",[879,1205,1080],{"class":895},[879,1207,1083],{"class":891},[879,1209,1086],{"class":963},[879,1211,1213,1215],{"class":749,"line":1212},30,[879,1214,1032],{"class":891},[879,1216,1217],{"class":884}," \"alice\"\n",[879,1219,1221],{"class":749,"line":1220},31,[879,1222,922],{"emptyLinePlaceholder":921},[879,1224,1226],{"class":749,"line":1225},32,[879,1227,922],{"emptyLinePlaceholder":921},[879,1229,1231,1233,1235,1238],{"class":749,"line":1230},33,[879,1232,1004],{"class":891},[879,1234,1007],{"class":891},[879,1236,1237],{"class":988}," get_settings_uncached",[879,1239,1240],{"class":895},"(\n",[879,1242,1244,1247,1249,1252,1256,1258,1261],{"class":749,"line":1243},34,[879,1245,1246],{"class":895},"    settings: Annotated[",[879,1248,807],{"class":963},[879,1250,1251],{"class":895},", Depends(get_settings, ",[879,1253,1255],{"class":1254},"sV4o_","use_cache",[879,1257,949],{"class":891},[879,1259,1260],{"class":963},"False",[879,1262,1263],{"class":895},")],\n",[879,1265,1267,1270,1272],{"class":749,"line":1266},35,[879,1268,1269],{"class":895},") -> ",[879,1271,807],{"class":963},[879,1273,1066],{"class":895},[879,1275,1277,1279],{"class":749,"line":1276},36,[879,1278,1032],{"class":891},[879,1280,1281],{"class":895}," settings\n",[879,1283,1285],{"class":749,"line":1284},37,[879,1286,922],{"emptyLinePlaceholder":921},[879,1288,1290],{"class":749,"line":1289},38,[879,1291,922],{"emptyLinePlaceholder":921},[879,1293,1295,1298,1301],{"class":749,"line":1294},39,[879,1296,1297],{"class":891},"def",[879,1299,1300],{"class":988}," make_rate_limiter",[879,1302,1303],{"class":895},"():\n",[879,1305,1307],{"class":749,"line":1306},40,[879,1308,1309],{"class":884},"    \"\"\"Two calls to this factory produce two distinct callables with the same __name__.\"\"\"\n",[879,1311,1313],{"class":749,"line":1312},41,[879,1314,922],{"emptyLinePlaceholder":921},[879,1316,1318,1321,1323,1326,1328,1331],{"class":749,"line":1317},42,[879,1319,1320],{"class":891},"    async",[879,1322,1007],{"class":891},[879,1324,1325],{"class":988}," rate_limit",[879,1327,1061],{"class":895},[879,1329,1330],{"class":963},"bool",[879,1332,1066],{"class":895},[879,1334,1336,1339,1341,1344,1346,1348],{"class":749,"line":1335},43,[879,1337,1338],{"class":963},"        CALLS",[879,1340,1074],{"class":895},[879,1342,1343],{"class":884},"\"rate_limit\"",[879,1345,1080],{"class":895},[879,1347,1083],{"class":891},[879,1349,1086],{"class":963},[879,1351,1353,1356],{"class":749,"line":1352},44,[879,1354,1355],{"class":891},"        return",[879,1357,1358],{"class":963}," True\n",[879,1360,1362],{"class":749,"line":1361},45,[879,1363,922],{"emptyLinePlaceholder":921},[879,1365,1367,1369],{"class":749,"line":1366},46,[879,1368,1032],{"class":891},[879,1370,1371],{"class":895}," rate_limit\n",[879,1373,1375],{"class":749,"line":1374},47,[879,1376,922],{"emptyLinePlaceholder":921},[879,1378,1380],{"class":749,"line":1379},48,[879,1381,922],{"emptyLinePlaceholder":921},[879,1383,1385,1388,1390],{"class":749,"line":1384},49,[879,1386,1387],{"class":895},"limiter_a ",[879,1389,949],{"class":891},[879,1391,1392],{"class":895}," make_rate_limiter()\n",[879,1394,1396,1399,1401],{"class":749,"line":1395},50,[879,1397,1398],{"class":895},"limiter_b ",[879,1400,949],{"class":891},[879,1402,1392],{"class":895},[879,1404,1406],{"class":749,"line":1405},51,[879,1407,922],{"emptyLinePlaceholder":921},[879,1409,1411],{"class":749,"line":1410},52,[879,1412,922],{"emptyLinePlaceholder":921},[879,1414,1416,1419,1421,1424],{"class":749,"line":1415},53,[879,1417,1418],{"class":988},"@app.get",[879,1420,992],{"class":895},[879,1422,1423],{"class":884},"\"\u002Fcached\"",[879,1425,998],{"class":895},[879,1427,1429,1431,1433,1436],{"class":749,"line":1428},54,[879,1430,1004],{"class":891},[879,1432,1007],{"class":891},[879,1434,1435],{"class":988}," cached",[879,1437,1240],{"class":895},[879,1439,1441,1444,1446],{"class":749,"line":1440},55,[879,1442,1443],{"class":895},"    db: Annotated[",[879,1445,1137],{"class":963},[879,1447,1448],{"class":895},", Depends(get_db)],\n",[879,1450,1452,1455,1457],{"class":749,"line":1451},56,[879,1453,1454],{"class":895},"    user: Annotated[",[879,1456,1137],{"class":963},[879,1458,1459],{"class":895},", Depends(get_user)],\n",[879,1461,1463,1465,1467],{"class":749,"line":1462},57,[879,1464,1246],{"class":895},[879,1466,807],{"class":963},[879,1468,1469],{"class":895},", Depends(get_settings)],\n",[879,1471,1473],{"class":749,"line":1472},58,[879,1474,1475],{"class":895},"):\n",[879,1477,1479,1481,1483,1486,1488,1490,1492,1494],{"class":749,"line":1478},59,[879,1480,1032],{"class":891},[879,1482,1094],{"class":895},[879,1484,1485],{"class":884},"\"calls\"",[879,1487,1100],{"class":895},[879,1489,807],{"class":963},[879,1491,992],{"class":895},[879,1493,964],{"class":963},[879,1495,1496],{"class":895},")}\n",[879,1498,1500],{"class":749,"line":1499},60,[879,1501,922],{"emptyLinePlaceholder":921},[879,1503,1505],{"class":749,"line":1504},61,[879,1506,922],{"emptyLinePlaceholder":921},[879,1508,1510,1512,1514,1517],{"class":749,"line":1509},62,[879,1511,1418],{"class":988},[879,1513,992],{"class":895},[879,1515,1516],{"class":884},"\"\u002Funcached\"",[879,1518,998],{"class":895},[879,1520,1522,1524,1526,1529],{"class":749,"line":1521},63,[879,1523,1004],{"class":891},[879,1525,1007],{"class":891},[879,1527,1528],{"class":988}," uncached",[879,1530,1240],{"class":895},[879,1532,1534,1536,1538],{"class":749,"line":1533},64,[879,1535,1443],{"class":895},[879,1537,1137],{"class":963},[879,1539,1448],{"class":895},[879,1541,1543,1545,1547],{"class":749,"line":1542},65,[879,1544,1454],{"class":895},[879,1546,1137],{"class":963},[879,1548,1459],{"class":895},[879,1550,1552,1555,1557],{"class":749,"line":1551},66,[879,1553,1554],{"class":895},"    fresh: Annotated[",[879,1556,807],{"class":963},[879,1558,1559],{"class":895},", Depends(get_settings_uncached)],\n",[879,1561,1563,1566,1568,1570,1572,1574,1576],{"class":749,"line":1562},67,[879,1564,1565],{"class":895},"    also_fresh: Annotated[",[879,1567,807],{"class":963},[879,1569,1251],{"class":895},[879,1571,1255],{"class":1254},[879,1573,949],{"class":891},[879,1575,1260],{"class":963},[879,1577,1263],{"class":895},[879,1579,1581],{"class":749,"line":1580},68,[879,1582,1475],{"class":895},[879,1584,1586,1588,1590,1592,1594,1596,1598,1600],{"class":749,"line":1585},69,[879,1587,1032],{"class":891},[879,1589,1094],{"class":895},[879,1591,1485],{"class":884},[879,1593,1100],{"class":895},[879,1595,807],{"class":963},[879,1597,992],{"class":895},[879,1599,964],{"class":963},[879,1601,1496],{"class":895},[879,1603,1605],{"class":749,"line":1604},70,[879,1606,922],{"emptyLinePlaceholder":921},[879,1608,1610],{"class":749,"line":1609},71,[879,1611,922],{"emptyLinePlaceholder":921},[879,1613,1615,1617,1619,1622,1625,1628,1630],{"class":749,"line":1614},72,[879,1616,1418],{"class":988},[879,1618,992],{"class":895},[879,1620,1621],{"class":884},"\"\u002Ftwo-limiters\"",[879,1623,1624],{"class":895},", ",[879,1626,1627],{"class":1254},"dependencies",[879,1629,949],{"class":891},[879,1631,1632],{"class":895},"[Depends(limiter_a), Depends(limiter_b)])\n",[879,1634,1636,1638,1640,1643],{"class":749,"line":1635},73,[879,1637,1004],{"class":891},[879,1639,1007],{"class":891},[879,1641,1642],{"class":988}," two_limiters",[879,1644,1303],{"class":895},[879,1646,1648,1650],{"class":749,"line":1647},74,[879,1649,1032],{"class":891},[879,1651,1652],{"class":895}," {\n",[879,1654,1656,1659,1662,1664,1667,1670,1672],{"class":749,"line":1655},75,[879,1657,1658],{"class":884},"        \"same_name\"",[879,1660,1661],{"class":895},": limiter_a.",[879,1663,838],{"class":963},[879,1665,1666],{"class":891}," ==",[879,1668,1669],{"class":895}," limiter_b.",[879,1671,838],{"class":963},[879,1673,1674],{"class":895},",\n",[879,1676,1678,1681,1684,1687],{"class":749,"line":1677},76,[879,1679,1680],{"class":884},"        \"same_object\"",[879,1682,1683],{"class":895},": limiter_a ",[879,1685,1686],{"class":891},"is",[879,1688,1689],{"class":895}," limiter_b,\n",[879,1691,1693,1696,1698,1700,1702,1704],{"class":749,"line":1692},77,[879,1694,1695],{"class":884},"        \"calls\"",[879,1697,1100],{"class":895},[879,1699,807],{"class":963},[879,1701,992],{"class":895},[879,1703,964],{"class":963},[879,1705,1706],{"class":895},"),\n",[879,1708,1710],{"class":749,"line":1709},78,[879,1711,1712],{"class":895},"    }\n",[879,1714,1716],{"class":749,"line":1715},79,[879,1717,922],{"emptyLinePlaceholder":921},[879,1719,1721],{"class":749,"line":1720},80,[879,1722,922],{"emptyLinePlaceholder":921},[879,1724,1726,1728,1730,1733,1735,1737,1739],{"class":749,"line":1725},81,[879,1727,1418],{"class":988},[879,1729,992],{"class":895},[879,1731,1732],{"class":884},"\"\u002Fone-limiter\"",[879,1734,1624],{"class":895},[879,1736,1627],{"class":1254},[879,1738,949],{"class":891},[879,1740,1741],{"class":895},"[Depends(limiter_a), Depends(limiter_a)])\n",[879,1743,1745,1747,1749,1752],{"class":749,"line":1744},82,[879,1746,1004],{"class":891},[879,1748,1007],{"class":891},[879,1750,1751],{"class":988}," one_limiter",[879,1753,1303],{"class":895},[879,1755,1757,1759,1761,1763,1765,1767,1769,1771],{"class":749,"line":1756},83,[879,1758,1032],{"class":891},[879,1760,1094],{"class":895},[879,1762,1485],{"class":884},[879,1764,1100],{"class":895},[879,1766,807],{"class":963},[879,1768,992],{"class":895},[879,1770,964],{"class":963},[879,1772,1496],{"class":895},[590,1774,1775],{},"Running that app under FastAPI 0.139.2 produces this transcript — it is the tool's real output, not a description of it:",[810,1777,1780],{"className":1778,"code":1779,"language":691,"meta":815},[813],"$ GET \u002Fcached\n200 OK\n{\n  \"calls\": {\n    \"get_settings\": 1,\n    \"get_db\": 1,\n    \"get_user\": 1\n  }\n}\n\n$ GET \u002Funcached\n200 OK\n{\n  \"calls\": {\n    \"get_settings\": 3,\n    \"get_db\": 1,\n    \"get_user\": 1\n  }\n}\n\n$ GET \u002Ftwo-limiters\n200 OK\n{\n  \"same_name\": true,\n  \"same_object\": false,\n  \"calls\": {\n    \"rate_limit\": 2\n  }\n}\n\n$ GET \u002Fone-limiter\n200 OK\n{\n  \"calls\": {\n    \"rate_limit\": 1\n  }\n}\n",[609,1781,1779],{"__ignoreMap":815},[590,1783,1784],{},"Read the four lines carefully, because each one settles a separate argument.",[590,1786,1787,1790,1791,1793,1794,1624,1796,1798],{},[609,1788,1789],{},"GET \u002Fcached"," — three consumers of ",[609,1792,646],{}," (",[609,1795,654],{},[609,1797,719],{},", and the handler itself), one execution. Caching is on by default and it works exactly as advertised.",[590,1800,1801,1804,1805,1807,1808,1810,1811,1813,1814,1816,1817,1810,1819,1821],{},[609,1802,1803],{},"GET \u002Funcached"," — ",[609,1806,646],{}," runs three times. One of those is the ordinary cached resolution feeding ",[609,1809,654],{}," and ",[609,1812,719],{},"; the other two come from the two declarations that passed ",[609,1815,730],{},". Note that ",[609,1818,654],{},[609,1820,719],{}," still ran once each: opting out at one declaration site does not poison the cache for the rest of the graph.",[590,1823,1824,1827,1828,1810,1831,1834,1835,1837,1838,1841,1842,1845,1846,1848],{},[609,1825,1826],{},"GET \u002Ftwo-limiters"," — this is the important one. ",[609,1829,1830],{},"limiter_a",[609,1832,1833],{},"limiter_b"," came out of the same factory. Their ",[609,1836,838],{}," is identical (",[609,1839,1840],{},"same_name: true",") and their bodies are the same source code, but they are different objects (",[609,1843,1844],{},"same_object: false","), so the counter reaches 2. FastAPI is not comparing functions structurally; it is comparing them with ",[609,1847,1686],{}," inside a dict lookup.",[590,1850,1851,1854,1855,1859],{},[609,1852,1853],{},"GET \u002Fone-limiter"," — declaring the ",[1856,1857,1858],"em",{},"same"," object twice on the same route collapses to one call, confirming the previous result was about object identity and nothing else.",[637,1861,1863],{"id":1862},"verification-in-your-own-app","Verification in Your Own App",[590,1865,1866],{},"You do not need a counter in production code. Two cheap checks:",[810,1868,1870],{"className":873,"code":1869,"language":875,"meta":815,"style":815},"def test_settings_resolved_once(client, monkeypatch):\n    calls = []\n    monkeypatch.setattr(app_module, \"_load_settings\", lambda: calls.append(1) or SETTINGS)\n    client.get(\"\u002Forders\u002F1\")\n    assert len(calls) == 1        # fails loudly if a second cache key appears\n",[609,1871,1872,1882,1892,1922,1932],{"__ignoreMap":815},[879,1873,1874,1876,1879],{"class":749,"line":881},[879,1875,1297],{"class":891},[879,1877,1878],{"class":988}," test_settings_resolved_once",[879,1880,1881],{"class":895},"(client, monkeypatch):\n",[879,1883,1884,1887,1889],{"class":749,"line":888},[879,1885,1886],{"class":895},"    calls ",[879,1888,949],{"class":891},[879,1890,1891],{"class":895}," []\n",[879,1893,1894,1897,1900,1902,1905,1908,1911,1914,1917,1920],{"class":749,"line":905},[879,1895,1896],{"class":895},"    monkeypatch.setattr(app_module, ",[879,1898,1899],{"class":884},"\"_load_settings\"",[879,1901,1624],{"class":895},[879,1903,1904],{"class":891},"lambda",[879,1906,1907],{"class":895},": calls.append(",[879,1909,1910],{"class":963},"1",[879,1912,1913],{"class":895},") ",[879,1915,1916],{"class":891},"or",[879,1918,1919],{"class":963}," SETTINGS",[879,1921,998],{"class":895},[879,1923,1924,1927,1930],{"class":749,"line":918},[879,1925,1926],{"class":895},"    client.get(",[879,1928,1929],{"class":884},"\"\u002Forders\u002F1\"",[879,1931,998],{"class":895},[879,1933,1934,1937,1940,1943,1946,1949],{"class":749,"line":925},[879,1935,1936],{"class":891},"    assert",[879,1938,1939],{"class":963}," len",[879,1941,1942],{"class":895},"(calls) ",[879,1944,1945],{"class":891},"==",[879,1947,1948],{"class":963}," 1",[879,1950,1951],{"class":1025},"        # fails loudly if a second cache key appears\n",[590,1953,1954,1955,1958,1959,1963],{},"And at runtime, log the provider's entry at ",[609,1956,1957],{},"DEBUG"," with the request ID from your ",[627,1960,1962],{"href":1961},"\u002Fcore-architecture-routing-patterns\u002Fmiddleware-implementation\u002Fimplementing-custom-middleware-for-request-tracing\u002F","request-tracing middleware",". Two lines with the same request ID means two cache keys, and the fix is upstream in how the dependency is referenced — not in the caching flag.",[637,1965,1967],{"id":1966},"request-cache-vs-process-cache","Request Cache vs Process Cache",[590,1969,1970],{},"The per-request cache is the wrong tool for something like parsed settings, which do not change between requests at all. The idiomatic pairing is both layers at once:",[810,1972,1974],{"className":873,"code":1973,"language":875,"meta":815,"style":815},"from functools import lru_cache\n\nfrom pydantic_settings import BaseSettings\n\n\nclass Settings(BaseSettings):\n    database_url: str\n    jwt_secret: str\n\n\n@lru_cache(maxsize=1)\ndef get_settings() -> Settings:\n    # lru_cache: once per process. FastAPI's DI cache: once per request.\n    return Settings()\n",[609,1975,1976,1988,1992,2004,2008,2012,2027,2035,2042,2046,2050,2066,2075,2080],{"__ignoreMap":815},[879,1977,1978,1980,1983,1985],{"class":749,"line":881},[879,1979,892],{"class":891},[879,1981,1982],{"class":895}," functools ",[879,1984,899],{"class":891},[879,1986,1987],{"class":895}," lru_cache\n",[879,1989,1990],{"class":749,"line":888},[879,1991,922],{"emptyLinePlaceholder":921},[879,1993,1994,1996,1999,2001],{"class":749,"line":905},[879,1995,892],{"class":891},[879,1997,1998],{"class":895}," pydantic_settings ",[879,2000,899],{"class":891},[879,2002,2003],{"class":895}," BaseSettings\n",[879,2005,2006],{"class":749,"line":918},[879,2007,922],{"emptyLinePlaceholder":921},[879,2009,2010],{"class":749,"line":925},[879,2011,922],{"emptyLinePlaceholder":921},[879,2013,2014,2017,2020,2022,2025],{"class":749,"line":938},[879,2015,2016],{"class":891},"class",[879,2018,2019],{"class":1254}," Settings",[879,2021,992],{"class":895},[879,2023,2024],{"class":963},"BaseSettings",[879,2026,1475],{"class":895},[879,2028,2029,2032],{"class":749,"line":943},[879,2030,2031],{"class":895},"    database_url: ",[879,2033,2034],{"class":963},"str\n",[879,2036,2037,2040],{"class":749,"line":955},[879,2038,2039],{"class":895},"    jwt_secret: ",[879,2041,2034],{"class":963},[879,2043,2044],{"class":749,"line":960},[879,2045,922],{"emptyLinePlaceholder":921},[879,2047,2048],{"class":749,"line":975},[879,2049,922],{"emptyLinePlaceholder":921},[879,2051,2052,2055,2057,2060,2062,2064],{"class":749,"line":980},[879,2053,2054],{"class":988},"@lru_cache",[879,2056,992],{"class":895},[879,2058,2059],{"class":1254},"maxsize",[879,2061,949],{"class":891},[879,2063,1910],{"class":963},[879,2065,998],{"class":895},[879,2067,2068,2070,2072],{"class":749,"line":985},[879,2069,1297],{"class":891},[879,2071,1058],{"class":988},[879,2073,2074],{"class":895},"() -> Settings:\n",[879,2076,2077],{"class":749,"line":1001},[879,2078,2079],{"class":1025},"    # lru_cache: once per process. FastAPI's DI cache: once per request.\n",[879,2081,2082,2084],{"class":749,"line":1016},[879,2083,1032],{"class":891},[879,2085,2086],{"class":895}," Settings()\n",[590,2088,2089,2092,2093,2096,2097,2101],{},[609,2090,2091],{},"lru_cache"," makes the parse happen once for the lifetime of the worker; FastAPI's cache then makes the ",[1856,2094,2095],{},"lookup"," happen once per request. This is the standard wiring described in ",[627,2098,2100],{"href":2099},"\u002Fcore-architecture-routing-patterns\u002Fconfiguration-management\u002Fmanaging-environment-variables-with-pydantic-settings\u002F","managing environment variables with pydantic-settings",", and it is worth understanding that the two caches are entirely independent mechanisms that happen to compose well.",[590,2103,2104,2105,619],{},"For results that should outlive a request but must expire — a permissions lookup, a feature flag set — neither layer is right, and you want the deliberate approach in ",[627,2106,2108],{"href":2107},"\u002Fasync-background-tasks-observability\u002Fcaching-strategies\u002Fcaching-dependency-results\u002F","caching dependency results",[637,2110,2112],{"id":2111},"trade-offs-and-when-not-to","Trade-Offs and When Not To",[590,2114,2115,2121,2122,2125],{},[593,2116,2117,2118,2120],{},"Do not reach for ",[609,2119,730],{}," to fix a staleness bug."," If a value changes mid-request, the more honest model is usually that the dependency should return a ",[1856,2123,2124],{},"handle"," (a session, a client, a repository) rather than a snapshot, and the caller asks it for fresh data. Turning caching off converts one cheap call into N calls at every declaration site, and N grows as the app does.",[590,2127,2128,2131,2132,2135,2136,2138,2139,2143],{},[593,2129,2130],{},"Yield dependencies interact with the cache in a way that matters."," A cached ",[609,2133,2134],{},"yield"," dependency has exactly one setup and one teardown. Setting ",[609,2137,730],{}," on a session provider gives you two independent sessions in one request, with two teardowns, which is almost never what anyone wants — see ",[627,2140,2142],{"href":2141},"\u002Fcore-architecture-routing-patterns\u002Fdependency-injection-strategies\u002Fyield-dependencies-and-cleanup-order\u002F","yield dependencies and cleanup order"," for what that teardown sequence actually looks like.",[590,2145,2146,2149,2150,2153],{},[593,2147,2148],{},"Caching hides accidental cost, it does not remove it."," A provider doing a database round trip is cheap ",[1856,2151,2152],{},"relative to being called five times",", but it is still a round trip on every request. Caching makes the graph tidy; it does not make an expensive dependency free.",[590,2155,2156,2159,2160,2163,2164,2167,2168,2172],{},[593,2157,2158],{},"Router-level and handler-level declarations of the same callable share the cache."," Attaching ",[609,2161,2162],{},"Depends(verify_api_key)"," to an ",[609,2165,2166],{},"APIRouter"," and also naming it in one handler's signature does not double-execute it, provided both refer to the same imported object. That is a feature: gates declared for a whole group of routes in ",[627,2169,2171],{"href":2170},"\u002Fcore-architecture-routing-patterns\u002Fmodular-router-organization\u002F","modular router organization"," stay idempotent.",[637,2174,2176],{"id":2175},"faq","FAQ",[590,2178,2179,2182,2183,2185],{},[593,2180,2181],{},"Is the FastAPI dependency cache shared between requests?","\nNo. The cache lives in the per-request solved-dependency dictionary and is discarded when the request finishes. A dependency shared by five consumers runs once per request, not once per process. For process-wide caching you need ",[609,2184,618],{}," on the provider itself.",[590,2187,2188,2191],{},[593,2189,2190],{},"What exactly is the cache key?","\nIt is a tuple of the dependency callable object and the sorted security scopes for that declaration. The callable is compared by identity, so two functions with the same name, same source and same behaviour are still two distinct keys.",[590,2193,2194,2197],{},[593,2195,2196],{},"When should I actually set use_cache=False?","\nWhen the dependency must produce a fresh value each time it is asked for within one request, such as a per-call timestamp, a fresh nonce, or a counter you want incremented once per declaration site. It is rarely the right answer for I\u002FO-backed providers.",[590,2199,2200,2203],{},[593,2201,2202],{},"Why does my dependency run twice even though caching is on?","\nAlmost always because the two declarations do not reference the same callable object. A dependency declared on the router and re-declared in the handler using a different alias, a re-imported module, or a factory-produced closure creates two cache keys.",[590,2205,2206,2209,2210,2213,2214,2216,2217,1810,2219,2221],{},[593,2207,2208],{},"Does use_cache=False re-run sub-dependencies too?","\nIt re-runs the dependency you marked, and that dependency's own sub-dependencies are resolved through the same request cache. Sub-dependencies that are already cached are reused, so only the uncached node is recomputed. The ",[609,2211,2212],{},"\u002Funcached"," transcript above shows exactly that: ",[609,2215,646],{}," climbs to three while ",[609,2218,654],{},[609,2220,719],{}," stay at one.",[637,2223,2225],{"id":2224},"related-reading","Related Reading",[597,2227,2228,2237,2246,2255,2263],{},[600,2229,2230,826,2233,2236],{},[593,2231,2232],{},"Up to the section:",[627,2234,2235],{"href":629},"Dependency Injection Strategies"," for the resolution model this page zooms into.",[600,2238,2239,826,2242,2245],{},[593,2240,2241],{},"The teardown half of the story:",[627,2243,2244],{"href":2141},"Yield Dependencies and Cleanup Order",", where the same identity rule decides how many teardowns run.",[600,2247,2248,826,2251,2254],{},[593,2249,2250],{},"Same identity rule, different consequence:",[627,2252,2253],{"href":833},"Overriding Dependencies in Tests"," explains why an override keyed on the wrong callable is a silent no-op.",[600,2256,2257,826,2260,619],{},[593,2258,2259],{},"Caching that outlives a request:",[627,2261,2262],{"href":2107},"Caching Dependency Results",[600,2264,2265,826,2268,619],{},[593,2266,2267],{},"Wider practice:",[627,2269,443],{"href":2270},"\u002Fcore-architecture-routing-patterns\u002Fdependency-injection-strategies\u002Fbest-practices-for-fastapi-dependency-injection\u002F",[2272,2273,2274],"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 .sacAq, html code.shiki .sacAq{--shiki-default:#023B95}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 .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":815,"searchDepth":888,"depth":888,"links":2276},[2277,2278,2279,2280,2281,2282,2283,2284],{"id":639,"depth":888,"text":640},{"id":800,"depth":888,"text":801},{"id":862,"depth":888,"text":863},{"id":1862,"depth":888,"text":1863},{"id":1966,"depth":888,"text":1967},{"id":2111,"depth":888,"text":2112},{"id":2175,"depth":888,"text":2176},{"id":2224,"depth":888,"text":2225},"2026-07-20","How FastAPI caches dependency results per request, when use_cache=False forces re-evaluation, and why two identical-looking callables are cached separately.","md",[2289,2291,2293,2295,2297],{"q":2181,"a":2290},"No. The cache lives in the per-request solved-dependency dictionary and is discarded when the request finishes. A dependency shared by five consumers runs once per request, not once per process. For process-wide caching you need functools.lru_cache on the provider itself.",{"q":2190,"a":2292},"It is a tuple of the dependency callable object and the sorted security scopes for that declaration. The callable is compared by identity, so two functions with the same name, same source and same behaviour are still two distinct keys.",{"q":2196,"a":2294},"When the dependency must produce a fresh value each time it is asked for within one request, such as a per-call timestamp, a fresh nonce, or a counter you want incremented once per declaration site. It is rarely the right answer for I\u002FO-backed providers.",{"q":2202,"a":2296},"Almost always because the two declarations do not reference the same callable object. A dependency declared on the router and re-declared in the handler using a different alias, a re-imported module, or a factory-produced closure creates two cache keys.",{"q":2208,"a":2298},"It re-runs the dependency you marked, and that dependency's own sub-dependencies are resolved through the same request cache. Sub-dependencies that are already cached are reused, so only the uncached node is recomputed.",null,{"slug":2301,"breadcrumb":2302},"dependency-caching-and-use-cache",[2303,2306,2309,2310],{"label":2304,"path":2305},"Home","\u002F",{"label":2307,"path":2308},"Core Architecture & Routing Patterns","\u002Fcore-architecture-routing-patterns\u002F",{"label":2235,"path":629},{"label":2311,"path":2312},"Dependency Caching and use_cache","\u002Fcore-architecture-routing-patterns\u002Fdependency-injection-strategies\u002Fdependency-caching-and-use-cache\u002F",{"title":449,"description":2286},"article","f0RD721ddIqsZnXUITyFtNQ47O7F6wACIgZ6pSAEW8E",[2299,2299],1784588202739]