FastAPI
FastAPI è un framework per la creazione di API in Python.
Il generatore FastAPI crea una nuova applicazione FastAPI con configurazione dell’infrastruttura AWS CDK o Terraform. Il backend generato utilizza AWS Lambda per il deployment serverless, esposto tramite un’API AWS API Gateway. Configura AWS Lambda Powertools per l’osservabilità, inclusi logging, tracciamento con AWS X-Ray e metriche CloudWatch.
Utilizzo
Sezione intitolata “Utilizzo”Generare una FastAPI
Sezione intitolata “Generare una FastAPI”Puoi generare una nuova FastAPI in due modi:
- Installa il Nx Console VSCode Plugin se non l'hai già fatto
- Apri la console Nx in VSCode
- Clicca su
Generate (UI)
nella sezione "Common Nx Commands" - Cerca
@aws/nx-plugin - py#fast-api
- Compila i parametri richiesti
- Clicca su
Generate
pnpm nx g @aws/nx-plugin:py#fast-api
yarn nx g @aws/nx-plugin:py#fast-api
npx nx g @aws/nx-plugin:py#fast-api
bunx nx g @aws/nx-plugin:py#fast-api
Puoi anche eseguire una prova per vedere quali file verrebbero modificati
pnpm nx g @aws/nx-plugin:py#fast-api --dry-run
yarn nx g @aws/nx-plugin:py#fast-api --dry-run
npx nx g @aws/nx-plugin:py#fast-api --dry-run
bunx nx g @aws/nx-plugin:py#fast-api --dry-run
Opzioni
Sezione intitolata “Opzioni”Parametro | Tipo | Predefinito | Descrizione |
---|---|---|---|
name Obbligatorio | string | - | Name of the API project to generate |
computeType | string | ServerlessApiGatewayRestApi | The type of compute to use to deploy this API. Choose between ServerlessApiGatewayRestApi (default) or ServerlessApiGatewayHttpApi. |
auth | string | IAM | The method used to authenticate with your API. Choose between IAM (default), Cognito or None. |
directory | string | packages | The directory to store the application in. |
iacProvider | string | CDK | The preferred IaC provider |
moduleName | string | - | Python module name |
Output del Generatore
Sezione intitolata “Output del Generatore”Il generatore creerà la seguente struttura del progetto nella directory <directory>/<api-name>
:
- project.json Configurazione del progetto e target di build
- pyproject.toml Configurazione del progetto Python e dipendenze
Directory<module_name>
- __init__.py Inizializzazione del modulo
- init.py Configura l’app FastAPI e il middleware powertools
- main.py Implementazione dell’API
Directoryscripts
- generate_open_api.py Script per generare lo schema OpenAPI dall’app FastAPI
Infrastruttura
Sezione intitolata “Infrastruttura”Poiché questo generatore fornisce infrastruttura come codice basata sul tuo iacProvider
selezionato, creerà un progetto in packages/common
che include i relativi costrutti CDK o moduli Terraform.
Il progetto comune di infrastruttura come codice è strutturato come segue:
Directorypackages/common/constructs
Directorysrc
Directoryapp/ Construct per l’infrastruttura specifica di un progetto/generatore
- …
Directorycore/ Construct generici riutilizzati dai construct in
app
- …
- index.ts Punto di ingresso che esporta i construct da
app
- project.json Target di build e configurazione del progetto
Directorypackages/common/terraform
Directorysrc
Directoryapp/ Moduli Terraform per l’infrastruttura specifica di un progetto/generatore
- …
Directorycore/ Moduli generici riutilizzati dai moduli in
app
- …
- project.json Target di build e configurazione del progetto
Per la distribuzione della tua API, vengono generati i seguenti file:
Directorypackages/common/constructs/src
Directoryapp
Directoryapis
- <project-name>.ts Costrutto CDK per distribuire la tua API
Directorycore
Directoryapi
- http-api.ts Costrutto CDK per distribuire un’API HTTP (se hai scelto di distribuire un’API HTTP)
- rest-api.ts Costrutto CDK per distribuire un’API REST (se hai scelto di distribuire un’API REST)
- utils.ts Utilities per i costrutti API
Directorypackages/common/terraform/src
Directoryapp
Directoryapis
Directory<project-name>
- <project-name>.tf Modulo per distribuire la tua API
Directorycore
Directoryapi
Directoryhttp-api
- http-api.tf Modulo per distribuire un’API HTTP (se hai scelto di distribuire un’API HTTP)
Directoryrest-api
- rest-api.tf Modulo per distribuire un’API REST (se hai scelto di distribuire un’API REST)
Implementazione della tua FastAPI
Sezione intitolata “Implementazione della tua FastAPI”L’implementazione principale dell’API si trova in main.py
. Qui definisci le route API e le relative implementazioni. Ecco un esempio:
from .init import app, tracerfrom pydantic import BaseModel
class Item(BaseModel): name: str
@app.get("/items/{item_id}")def get_item(item_id: int) -> Item: return Item(name=...)
@app.post("/items")def create_item(item: Item): return ...
Il generatore configura automaticamente diverse funzionalità:
- Integrazione con AWS Lambda Powertools per l’osservabilità
- Middleware per la gestione degli errori
- Correlazione tra richieste e risposte
- Raccolta delle metriche
- Handler AWS Lambda utilizzando Mangum
Osservabilità con AWS Lambda Powertools
Sezione intitolata “Osservabilità con AWS Lambda Powertools”Logging
Sezione intitolata “Logging”Il generatore configura il logging strutturato usando AWS Lambda Powertools. Puoi accedere al logger nei tuoi route handler:
from .init import app, logger
@app.get("/items/{item_id}")def read_item(item_id: int): logger.info("Fetching item", extra={"item_id": item_id}) return {"item_id": item_id}
Il logger include automaticamente:
- ID di correlazione per il tracciamento delle richieste
- Percorso e metodo della richiesta
- Informazioni sul contesto Lambda
- Indicatori di cold start
Tracciamento
Sezione intitolata “Tracciamento”Il tracciamento con AWS X-Ray è configurato automaticamente. Puoi aggiungere subsegment personalizzati ai tuoi trace:
from .init import app, tracer
@app.get("/items/{item_id}")@tracer.capture_methoddef read_item(item_id: int): # Crea un nuovo subsegment with tracer.provider.in_subsegment("fetch-item-details"): # Logica qui return {"item_id": item_id}
Metriche
Sezione intitolata “Metriche”Le metriche CloudWatch vengono raccolte automaticamente per ogni richiesta. Puoi aggiungere metriche personalizzate:
from .init import app, metricsfrom aws_lambda_powertools.metrics import MetricUnit
@app.get("/items/{item_id}")def read_item(item_id: int): metrics.add_metric(name="ItemViewed", unit=MetricUnit.Count, value=1) return {"item_id": item_id}
Le metriche predefinite includono:
- Conteggio richieste
- Conteggio successi/fallimenti
- Metriche di cold start
- Metriche per route specifiche
Gestione degli Errori
Sezione intitolata “Gestione degli Errori”Il generatore include una gestione completa degli errori:
from fastapi import HTTPException
@app.get("/items/{item_id}")def read_item(item_id: int): if item_id < 0: raise HTTPException(status_code=400, detail="Item ID must be positive") return {"item_id": item_id}
Le eccezioni non gestite vengono catturate dal middleware e:
- Registrano l’eccezione completa con stack trace
- Registrano una metrica di fallimento
- Restituiscono una risposta sicura 500 al client
- Mantengono l’ID di correlazione
Streaming
Sezione intitolata “Streaming”Con FastAPI, puoi inviare una risposta in streaming al chiamante usando il tipo di risposta StreamingResponse
.
Modifiche all’Infrastruttura
Sezione intitolata “Modifiche all’Infrastruttura”Poiché AWS API Gateway non supporta risposte in streaming, dovrai distribuire la tua FastAPI su una piattaforma che supporti questa funzionalità. L’opzione più semplice è utilizzare un AWS Lambda Function URL.
Per ottenere questo, puoi sostituire il costrutto generato common/constructs/src/app/apis/<name>-api.ts
con uno che distribuisce una Function URL.
Esempio di Costrutto FunctionURL per Streaming
import { Duration, Stack, CfnOutput } from 'aws-cdk-lib';import { IGrantable, Grant } from 'aws-cdk-lib/aws-iam';import { Runtime, Code, Tracing, LayerVersion, FunctionUrlAuthType, InvokeMode, Function,} from 'aws-cdk-lib/aws-lambda';import { Construct } from 'constructs';import url from 'url';import { RuntimeConfig } from '../../core/runtime-config.js';
export class MyApi extends Construct { public readonly handler: Function;
constructor(scope: Construct, id: string) { super(scope, id);
this.handler = new Function(this, 'Handler', { runtime: Runtime.PYTHON_3_12, handler: 'run.sh', code: Code.fromAsset( url.fileURLToPath( new URL( '../../../../../../dist/packages/my_api/bundle', import.meta.url, ), ), ), timeout: Duration.seconds(30), tracing: Tracing.ACTIVE, environment: { AWS_CONNECTION_REUSE_ENABLED: '1', }, });
const stack = Stack.of(this); this.handler.addLayers( LayerVersion.fromLayerVersionArn( this, 'LWALayer', `arn:aws:lambda:${stack.region}:753240598075:layer:LambdaAdapterLayerX86:24`, ), ); this.handler.addEnvironment('PORT', '8000'); this.handler.addEnvironment('AWS_LWA_INVOKE_MODE', 'response_stream'); this.handler.addEnvironment('AWS_LAMBDA_EXEC_WRAPPER', '/opt/bootstrap'); const functionUrl = this.handler.addFunctionUrl({ authType: FunctionUrlAuthType.AWS_IAM, invokeMode: InvokeMode.RESPONSE_STREAM, cors: { allowedOrigins: ['*'], allowedHeaders: [ 'authorization', 'content-type', 'x-amz-content-sha256', 'x-amz-date', 'x-amz-security-token', ], }, });
new CfnOutput(this, 'MyApiUrl', { value: functionUrl.url });
// Registra l'URL API nella configurazione runtime per il client discovery RuntimeConfig.ensure(this).config.apis = { ...RuntimeConfig.ensure(this).config.apis!, MyApi: functionUrl.url, }; }
public grantInvokeAccess(grantee: IGrantable) { Grant.addToPrincipal({ grantee, actions: ['lambda:InvokeFunctionUrl'], resourceArns: [this.handler.functionArn], conditions: { StringEquals: { 'lambda:FunctionUrlAuthType': 'AWS_IAM', }, }, }); }}
Per ottenere questo con Terraform, puoi sostituire l’infrastruttura API Gateway generata con una Lambda Function URL che supporti lo streaming delle risposte.
Esempio di Configurazione Lambda Function URL per Streaming
# Data sources per il contesto AWS correntedata "aws_caller_identity" "current" {}data "aws_region" "current" {}
# Funzione Lambda per FastAPI in streamingresource "aws_lambda_function" "my_api_handler" { filename = "../../../../../../dist/packages/my_api/bundle.zip" function_name = "my-api-handler" role = aws_iam_role.lambda_execution_role.arn handler = "run.sh" runtime = "python3.12" timeout = 30 source_code_hash = filebase64sha256("../../../../../../dist/packages/my_api/bundle.zip")
# Abilita il tracciamento X-Ray tracing_config { mode = "Active" }
# Variabili d'ambiente per Lambda Web Adapter environment { variables = { AWS_CONNECTION_REUSE_ENABLED = "1" PORT = "8000" AWS_LWA_INVOKE_MODE = "response_stream" AWS_LAMBDA_EXEC_WRAPPER = "/opt/bootstrap" } }
# Aggiunge il layer Lambda Web Adapter layers = [ "arn:aws:lambda:${data.aws_region.current.name}:753240598075:layer:LambdaAdapterLayerX86:24" ]
depends_on = [ aws_iam_role_policy_attachment.lambda_logs, aws_cloudwatch_log_group.lambda_logs, ]}
# CloudWatch Log Group per la funzione Lambdaresource "aws_cloudwatch_log_group" "lambda_logs" { name = "/aws/lambda/my-api-handler" retention_in_days = 14}
# IAM role per l'esecuzione Lambdaresource "aws_iam_role" "lambda_execution_role" { name = "my-api-lambda-execution-role"
assume_role_policy = jsonencode({ Version = "2012-10-17" Statement = [ { Action = "sts:AssumeRole" Effect = "Allow" Principal = { Service = "lambda.amazonaws.com" } } ] })}
# Allega la policy di esecuzione baseresource "aws_iam_role_policy_attachment" "lambda_logs" { role = aws_iam_role.lambda_execution_role.name policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"}
# Allega la policy per X-Rayresource "aws_iam_role_policy_attachment" "lambda_xray" { role = aws_iam_role.lambda_execution_role.name policy_arn = "arn:aws:iam::aws:policy/AWSXRayDaemonWriteAccess"}
# Lambda Function URL con supporto streamingresource "aws_lambda_function_url" "my_api_url" { function_name = aws_lambda_function.my_api_handler.function_name authorization_type = "AWS_IAM" invoke_mode = "RESPONSE_STREAM"
cors { allow_credentials = false allow_origins = ["*"] allow_methods = ["*"] allow_headers = [ "authorization", "content-type", "x-amz-content-sha256", "x-amz-date", "x-amz-security-token" ] expose_headers = ["date", "keep-alive"] max_age = 86400 }}
# Output dell'URL della Functionoutput "my_api_url" { description = "URL per la FastAPI in streaming su Lambda" value = aws_lambda_function_url.my_api_url.function_url}
# Opzionale: Crea parametro SSM per la configurazione runtimeresource "aws_ssm_parameter" "my_api_url" { name = "/runtime-config/apis/MyApi" type = "String" value = aws_lambda_function_url.my_api_url.function_url
tags = { Environment = "production" Service = "my-api" }}
# IAM policy per concedere l'accesso di invocazione alla Function URLresource "aws_iam_policy" "my_api_invoke_policy" { name = "my-api-invoke-policy" description = "Policy per consentire l'invocazione della Lambda Function URL in streaming"
policy = jsonencode({ Version = "2012-10-17" Statement = [ { Effect = "Allow" Action = "lambda:InvokeFunctionUrl" Resource = aws_lambda_function.my_api_handler.arn Condition = { StringEquals = { "lambda:FunctionUrlAuthType" = "AWS_IAM" } } } ] })}
# Esempio: Allega la policy a un ruolo (scommenta e modifica se necessario)# resource "aws_iam_role_policy_attachment" "my_api_invoke_access" {# role = var.authenticated_role_name# policy_arn = aws_iam_policy.my_api_invoke_policy.arn# }
Implementazione
Sezione intitolata “Implementazione”Dopo aver aggiornato l’infrastruttura per supportare lo streaming, puoi implementare un’API in streaming con FastAPI. L’API dovrebbe:
- Restituire un
StreamingResponse
- Dichiarare il tipo di ritorno per ogni chunk della risposta
- Aggiungere l’estensione vendor OpenAPI
x-streaming: true
se intendi utilizzare il API Connection.
Ad esempio, se vuoi inviare in streaming una serie di oggetti JSON dalla tua API, puoi implementarlo così:
from pydantic import BaseModelfrom fastapi.responses import StreamingResponse
class Chunk(BaseModel): message: str timestamp: datetime
async def stream_chunks(): for i in range(0, 100): yield Chunk(message=f"This is chunk {i}", timestamp=datetime.now())
@app.get("/stream", openapi_extra={'x-streaming': True})def my_stream() -> Chunk: return StreamingResponse(stream_chunks(), media_type="application/json")
Consumo
Sezione intitolata “Consumo”Per consumare uno stream di risposte, puoi utilizzare il Generatore API Connection che fornirà un metodo type-safe per iterare sui chunk in streaming.
Distribuzione della tua FastAPI
Sezione intitolata “Distribuzione della tua FastAPI”Il generatore FastAPI crea codice infrastrutturale CDK o Terraform in base al iacProvider
selezionato. Puoi usarlo per distribuire la tua FastAPI.
Il costrutto CDK per distribuire l’API si trova nella cartella common/constructs
. Puoi usarlo in un’applicazione CDK:
import { MyApi } from ':my-scope/common-constructs';
export class ExampleStack extends Stack { constructor(scope: Construct, id: string) { // Aggiungi l'API allo stack const api = new MyApi(this, 'MyApi', { integrations: MyApi.defaultIntegrations(this).build(), }); }}
Questo configura:
- Una funzione AWS Lambda per ogni operazione nell’applicazione FastAPI
- API Gateway HTTP/REST API come trigger della funzione
- Ruoli e permessi IAM
- CloudWatch log group
- Configurazione del tracciamento X-Ray
- Namespace per le metriche CloudWatch
I moduli Terraform per distribuire l’API si trovano nella cartella common/terraform
. Puoi usarli in una configurazione Terraform:
module "my_api" { source = "../../common/terraform/src/app/apis/my-api"
# Variabili d'ambiente per la funzione Lambda env = { ENVIRONMENT = var.environment LOG_LEVEL = "INFO" }
# Policy IAM aggiuntive se necessarie additional_iam_policy_statements = [ # Aggiungi eventuali permessi aggiuntivi richiesti dall'API ]
tags = local.common_tags}
Questo configura:
- Una funzione AWS Lambda che serve tutte le route FastAPI
- API Gateway HTTP/REST API come trigger della funzione
- Ruoli e permessi IAM
- CloudWatch log group
- Configurazione del tracciamento X-Ray
- Configurazione CORS
Il modulo Terraform fornisce diversi output utilizzabili:
# Accedi all'endpoint APIoutput "api_url" { value = module.my_api.stage_invoke_url}
# Accedi ai dettagli della funzione Lambdaoutput "lambda_function_name" { value = module.my_api.lambda_function_name}
# Accedi al ruolo IAM per concedere permessi aggiuntivioutput "lambda_execution_role_arn" { value = module.my_api.lambda_execution_role_arn}
Puoi personalizzare le impostazioni CORS passando variabili al modulo:
module "my_api" { source = "../../common/terraform/src/app/apis/my-api"
# Configurazione CORS personalizzata cors_allow_origins = ["https://myapp.com", "https://staging.myapp.com"] cors_allow_methods = ["GET", "POST", "PUT", "DELETE"] cors_allow_headers = [ "authorization", "content-type", "x-custom-header" ]
tags = local.common_tags}
Integrazioni
Sezione intitolata “Integrazioni”I costrutti CDK per le API REST/HTTP sono configurati per fornire un’interfaccia type-safe per definire le integrazioni per ciascuna delle tue operazioni.
I costrutti CDK forniscono supporto completo per l’integrazione type-safe come descritto di seguito.
Integrazioni Predefinite
Sezione intitolata “Integrazioni Predefinite”Puoi utilizzare il metodo statico defaultIntegrations
per sfruttare il pattern predefinito, che definisce una singola funzione AWS Lambda per ogni operazione:
new MyApi(this, 'MyApi', { integrations: MyApi.defaultIntegrations(this).build(),});
I moduli Terraform utilizzano automaticamente il router pattern con una singola funzione Lambda. Nessuna configurazione aggiuntiva è necessaria:
module "my_api" { source = "../../common/terraform/src/app/apis/my-api"
# Il modulo crea automaticamente una singola funzione Lambda # che gestisce tutte le operazioni API tags = local.common_tags}
Accesso alle Integrazioni
Sezione intitolata “Accesso alle Integrazioni”Puoi accedere alle funzioni AWS Lambda sottostanti tramite la proprietà integrations
del costrutto API in modo type-safe. Ad esempio, se la tua API definisce un’operazione chiamata sayHello
e devi aggiungere dei permessi a questa funzione, puoi farlo come segue:
const api = new MyApi(this, 'MyApi', { integrations: MyApi.defaultIntegrations(this).build(),});
// sayHello è tipizzato in base alle operazioni definite nella tua APIapi.integrations.sayHello.handler.addToRolePolicy(new PolicyStatement({ effect: Effect.ALLOW, actions: [...], resources: [...],}));
Con il router pattern di Terraform, esiste solo una funzione Lambda. Puoi accedervi tramite gli output del modulo:
# Concedi permessi aggiuntivi alla singola funzione Lambdaresource "aws_iam_role_policy" "additional_permissions" { name = "additional-api-permissions" role = module.my_api.lambda_execution_role_name
policy = jsonencode({ Version = "2012-10-17" Statement = [ { Effect = "Allow" Action = [ "s3:GetObject", "s3:PutObject" ] Resource = "arn:aws:s3:::my-bucket/*" } ] })}
Personalizzazione delle Opzioni Predefinite
Sezione intitolata “Personalizzazione delle Opzioni Predefinite”Se desideri personalizzare le opzioni utilizzate durante la creazione delle funzioni Lambda per ogni integrazione predefinita, puoi usare il metodo withDefaultOptions
. Ad esempio, per far risiedere tutte le funzioni Lambda in una VPC:
const vpc = new Vpc(this, 'Vpc', ...);
new MyApi(this, 'MyApi', { integrations: MyApi.defaultIntegrations(this) .withDefaultOptions({ vpc, }) .build(),});
Per personalizzare opzioni come la configurazione VPC, devi modificare il modulo Terraform generato. Esempio per aggiungere il supporto VPC:
# Aggiungi variabili VPCvariable "vpc_subnet_ids" { description = "Lista di ID subnet VPC per la funzione Lambda" type = list(string) default = []}
variable "vpc_security_group_ids" { description = "Lista di ID security group VPC per la funzione Lambda" type = list(string) default = []}
# Aggiorna la risorsa Lambda functionresource "aws_lambda_function" "api_lambda" { # ... configurazione esistente ...
# Aggiungi configurazione VPC vpc_config { subnet_ids = var.vpc_subnet_ids security_group_ids = var.vpc_security_group_ids }}
Utilizza il modulo con la configurazione VPC:
module "my_api" { source = "../../common/terraform/src/app/apis/my-api"
# Configurazione VPC vpc_subnet_ids = [aws_subnet.private_a.id, aws_subnet.private_b.id] vpc_security_group_ids = [aws_security_group.lambda_sg.id]
tags = local.common_tags}
Override delle Integrazioni
Sezione intitolata “Override delle Integrazioni”Puoi sovrascrivere le integrazioni per operazioni specifiche usando il metodo withOverrides
. Ogni override deve specificare una proprietà integration
tipizzata correttamente. Esempio per reindirizzare un’API getDocumentation
:
new MyApi(this, 'MyApi', { integrations: MyApi.defaultIntegrations(this) .withOverrides({ getDocumentation: { integration: new HttpIntegration('https://example.com/documentation'), }, }) .build(),});
Le integrazioni sovrascritte non avranno più la proprietà handler
quando accedute tramite api.integrations.getDocumentation
.
Puoi aggiungere proprietà personalizzate alle integrazioni mantenendo il type-safety. Esempio con integrazione S3:
const storageBucket = new Bucket(this, 'Bucket', { ... });
const apiGatewayRole = new Role(this, 'ApiGatewayS3Role', { assumedBy: new ServicePrincipal('apigateway.amazonaws.com'),});
storageBucket.grantRead(apiGatewayRole);
const api = new MyApi(this, 'MyApi', { integrations: MyApi.defaultIntegrations(this) .withOverrides({ getFile: { bucket: storageBucket, integration: new AwsIntegration({ service: 's3', integrationHttpMethod: 'GET', path: `${storageBucket.bucketName}/{fileName}`, options: { credentialsRole: apiGatewayRole, requestParameters: { 'integration.request.path.fileName': 'method.request.querystring.fileName', }, integrationResponses: [{ statusCode: '200' }], }, }), options: { requestParameters: { 'method.request.querystring.fileName': true, }, methodResponses: [{ statusCode: '200', }], } }, }) .build(),});
// Accesso type-safe alla proprietà bucket definitaapi.integrations.getFile.bucket.grantRead(...);
Override degli Authorizer
Sezione intitolata “Override degli Authorizer”Puoi sovrascrivere gli authorizer specificando options
nelle integrazioni. Esempio con autenticazione Cognito:
new MyApi(this, 'MyApi', { integrations: MyApi.defaultIntegrations(this) .withOverrides({ getDocumentation: { integration: new HttpIntegration('https://example.com/documentation'), options: { authorizer: new CognitoUserPoolsAuthorizer(...) // Per REST API } }, }) .build(),});
Integrazioni Esplicite
Sezione intitolata “Integrazioni Esplicite”Puoi definire manualmente ogni integrazione. Utile per usare tipi diversi per ogni operazione:
new MyApi(this, 'MyApi', { integrations: { sayHello: { integration: new LambdaIntegration(...), }, getDocumentation: { integration: new HttpIntegration(...), }, },});
Per integrazioni esplicite con Terraform, modifica il modulo generato:
- Rimuovi le route proxy predefinite
- Sostituisci la singola Lambda con funzioni individuali
- Crea integrazioni specifiche per ogni operazione:
# Aggiungi funzioni Lambda individuali resource "aws_lambda_function" "say_hello_handler" { handler = "sayHello.handler" # ... configurazione ... }
# Crea integrazioni e route specifiche resource "aws_apigatewayv2_integration" "say_hello_integration" { integration_uri = aws_lambda_function.say_hello_handler.invoke_arn # ... configurazione ... }
# Aggiungi risorse API Gateway specifiche resource "aws_api_gateway_resource" "say_hello_resource" { path_part = "sayHello" }
resource "aws_api_gateway_method" "say_hello_method" { http_method = "POST" }
Router Pattern
Sezione intitolata “Router Pattern”Per usare una singola Lambda per tutte le richieste, modifica defaultIntegrations
:
export class MyApi<...> extends ... {
public static defaultIntegrations = (scope: Construct) => { const router = new Function(scope, 'RouterHandler', { ... }); return IntegrationBuilder.rest({ buildDefaultIntegration: (op) => ({ integration: new LambdaIntegration(router), }), }); };}
Il router pattern è l’approccio predefinito di Terraform:
module "my_api" { source = "../../common/terraform/src/app/apis/my-api" tags = local.common_tags}
Generazione del Codice
Sezione intitolata “Generazione del Codice”Poiché le operazioni in FastAPI sono definite in Python e l’infrastruttura CDK in TypeScript, utilizziamo la generazione di codice per fornire metadati al costrutto CDK e creare un’interfaccia type-safe per le integrazioni.
Un target generate:<ApiName>-metadata
viene aggiunto al project.json
dei costrutti comuni per facilitare questa generazione, producendo un file come packages/common/constructs/src/generated/my-api/metadata.gen.ts
. Essendo generato al momento della build, viene ignorato dal version control.
Concessione dell’Accesso (Solo IAM)
Sezione intitolata “Concessione dell’Accesso (Solo IAM)”Se hai selezionato l’autenticazione IAM
, puoi usare il metodo grantInvokeAccess
per concedere l’accesso all’API:
api.grantInvokeAccess(myIdentityPool.authenticatedRole);
# Crea una policy IAM per consentire l'invocazione dell'APIresource "aws_iam_policy" "api_invoke_policy" { name = "MyApiInvokePolicy" description = "Policy per consentire l'invocazione della FastAPI"
policy = jsonencode({ Version = "2012-10-17" Statement = [ { Effect = "Allow" Action = "execute-api:Invoke" Resource = "${module.my_api.api_execution_arn}/*/*" } ] })}
# Allega la policy a un ruolo IAM (es. per utenti autenticati)resource "aws_iam_role_policy_attachment" "api_invoke_access" { role = aws_iam_role.authenticated_user_role.name policy_arn = aws_iam_policy.api_invoke_policy.arn}
# O allega a un ruolo esistente per nomeresource "aws_iam_role_policy_attachment" "api_invoke_access_existing" { role = "MyExistingRole" policy_arn = aws_iam_policy.api_invoke_policy.arn}
Gli output principali dal modulo API utilizzabili per le policy IAM sono:
module.my_api.api_execution_arn
- Per concedere permessi execute-api:Invokemodule.my_api.api_arn
- L’ARN di API Gatewaymodule.my_api.lambda_function_arn
- L’ARN della funzione Lambda
Sviluppo Locale
Sezione intitolata “Sviluppo Locale”Il generatore configura un server di sviluppo locale che puoi eseguire con:
pnpm nx run my-api:serve
yarn nx run my-api:serve
npx nx run my-api:serve
bunx nx run my-api:serve
Questo avvia un server di sviluppo FastAPI locale con:
- Ricarica automatica alle modifiche del codice
- Documentazione API interattiva su
/docs
o/redoc
- Schema OpenAPI su
/openapi.json
Invocazione della tua FastAPI
Sezione intitolata “Invocazione della tua FastAPI”Per invocare la tua API da un sito React, puoi usare il generatore api-connection
.