FastAPI to Relational Database
The connection generator wires a FastAPI to a Python Relational Database project, injecting a typed SQLModel session into your route handlers via a FastAPI dependency.
Prerequisites
Section titled “Prerequisites”Before using this generator, ensure you have:
- A
py#fast-apiproject - A
py#rdbproject
Run the Generator
Section titled “Run the Generator”- Install the Nx Console VSCode Plugin if you haven't already
- Open the Nx Console in VSCode
- Click
Generate (UI)in the "Common Nx Commands" section - Search for
@aws/nx-plugin - connection - Fill in the required parameters
- Click
Generate
pnpm nx g @aws/nx-plugin:connectionyarn nx g @aws/nx-plugin:connectionnpx nx g @aws/nx-plugin:connectionbunx nx g @aws/nx-plugin:connectionYou can also perform a dry-run to see what files would be changed
pnpm nx g @aws/nx-plugin:connection --dry-runyarn nx g @aws/nx-plugin:connection --dry-runnpx nx g @aws/nx-plugin:connection --dry-runbunx nx g @aws/nx-plugin:connection --dry-runSelect your FastAPI project as the source and your relational database project as the target.
Options
Section titled “Options”| Parameter | Type | Default | Description |
|---|---|---|---|
| sourceProject Required | string | - | The source project |
| targetProject Required | string | - | The target project to connect to |
| sourceComponent | string | - | The source component to connect from (component name, path relative to source project root, or generator id). Use '.' to explicitly select the project as the source. |
| targetComponent | string | - | The target component to connect to (component name, path relative to target project root, or generator id). Use '.' to explicitly select the project as the target. |
| preferInstallDependencies | boolean | true | Whether to prefer installing dependencies after the generator runs. Set to false to defer installing when batching multiple generators (an install still runs if needed so subsequent generators can compute the Nx project graph); install once at the end. |
Generator Output
Section titled “Generator Output”The generator modifies your FastAPI project:
Directorypackages/my_api
- project.json Adds a dependency from
devon the database’sdevtarget - pyproject.toml Adds the database package as a workspace dependency
Directorymy_api
Directorydependencies
- my_db.py FastAPI
MyDbSessiondependency for the database session
- my_db.py FastAPI
- project.json Adds a dependency from
Using the Database in Route Handlers
Section titled “Using the Database in Route Handlers”This generator configures an injectable FastAPI Dependency which you can use in your route handlers:
from sqlmodel import selectfrom my_api.dependencies.my_db import MyDbSessionfrom my_scope.my_db.models.example import ExampleModel
@app.get("/examples")async def list_examples(my_db: MyDbSession): return (await my_db.execute(select(ExampleModel))).all()
@app.post("/examples")async def create_example(name: str, my_db: MyDbSession): item = ExampleModel(name=name) my_db.add(item) await my_db.commit() await my_db.refresh(item) return itemFastAPI automatically opens a new session per request and closes it when the handler returns.
Infrastructure
Section titled “Infrastructure”To allow the FastAPI Lambda function to connect to the database at runtime, it must be deployed into the same VPC as the database and granted network and IAM access.
In your application stack, deploy the API into the same VPC as the database, then call allowDefaultPortFrom and grantConnect to open the network path and grant IAM rds-db:connect permission to the Lambda handler:
import { MyDatabase } from ':my-scope/common-constructs';
const db = new MyDatabase(this, 'Db', { vpc, ... });
const api = new MyApi(this, 'Api', { integrations: MyApi.defaultIntegrations(this) .withDefaultOptions({ vpc, vpcSubnets: { subnetType: SubnetType.PRIVATE_WITH_EGRESS }, }) .build(),});
Object.entries(api.integrations).forEach(([operation, integration]) => { db.allowDefaultPortFrom(integration.handler, `Allow ${operation} to connect to the database`); db.grantConnect(integration.handler);});Deploy the API Lambda functions into a private subnet with egress, not a private isolated subnet. At runtime, session_context() retrieves database configuration from AWS AppConfig, which is a public AWS service endpoint that requires outbound internet access.
Deploy the API into the same VPC as the database, grant it rds-db:connect via additional_iam_policy_statements, and open the network path with a pair of security group rules:
The example below references the VPC resources from the Python Relational Database deployment guide: aws_subnet.database subnets have no internet route, while aws_subnet.private subnets have NAT egress.
module "my_database" { source = "../../common/terraform/src/app/dbs/my-database" vpc_id = aws_vpc.main.id database_subnet_ids = aws_subnet.database[*].id lambda_subnet_ids = aws_subnet.private[*].id}
module "api" { source = "../../common/terraform/src/app/apis/my-api" enable_vpc = true vpc_id = aws_vpc.main.id subnet_ids = aws_subnet.private[*].id
appconfig_application_id = module.runtime_config_appconfig.application_id appconfig_application_arn = module.runtime_config_appconfig.application_arn
additional_iam_policy_statements = [ { Effect = "Allow" Action = ["rds-db:connect"] Resource = [ "arn:aws:rds-db:${data.aws_region.current.region}:${data.aws_caller_identity.current.account_id}:dbuser:${module.my_database.connect_resource_id}/${module.my_database.database_runtime_user}" ] } ]}
resource "aws_vpc_security_group_ingress_rule" "api_to_database" { description = "Allow the API Lambda functions to connect to the database" security_group_id = module.my_database.security_group_id referenced_security_group_id = module.api.security_group_id from_port = module.my_database.cluster_port to_port = module.my_database.cluster_port ip_protocol = "tcp"}
resource "aws_vpc_security_group_egress_rule" "api_to_database" { description = "Allow outbound traffic from the API Lambda functions to the database" security_group_id = module.api.security_group_id referenced_security_group_id = module.my_database.security_group_id from_port = module.my_database.cluster_port to_port = module.my_database.cluster_port ip_protocol = "tcp"}Deploy the API Lambda functions into private subnets with egress, not private isolated subnets. appconfig_application_id/appconfig_application_arn come from the shared runtime configuration AppConfig application declared once in your root module, not from the database module — passing them sets RUNTIME_CONFIG_APP_ID on the Lambda functions and grants them read access to the application.
The AppConfig application must expose the database namespace so the database module’s runtime configuration entry is deployed. Include it in the namespaces when instantiating the runtime-config/appconfig module:
module "runtime_config_appconfig" { source = "../../common/terraform/src/core/runtime-config/appconfig"
application_name = "my-app-runtime-config" namespaces = ["connection", "agentcore", "database"]}Local Development
Section titled “Local Development”pnpm nx dev <project-name>yarn nx dev <project-name>npx nx dev <project-name>bunx nx dev <project-name>This starts the FastAPI and all connected databases. The LOCAL_DEV=true environment variable causes the database client to connect to its local Docker database instead of Aurora.