FastAPI
FastAPI è un framework per la creazione di API in Python.
Il generatore FastAPI crea una nuova applicazione FastAPI con configurazione infrastrutturale AWS CDK. Il backend generato utilizza AWS Lambda per il deployment serverless, esposto tramite un API Gateway HTTP API di AWS. Configura AWS Lambda Powertools per l’osservabilità, inclusi logging, tracciamento AWS X-Ray e metriche Cloudwatch.
Utilizzo
Genera 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
Parametro | Tipo | Predefinito | Descrizione |
---|---|---|---|
name Obbligatorio | string | - | project name. |
directory | string | packages | The directory to store the application in. |
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 progetto Python e dipendenze
Directory<module_name>
- __init__.py Inizializzazione modulo
- init.py Configura l’app FastAPI e il middleware powertools
- main.py Implementazione API
Il generatore crea anche costrutti CDK per il deployment dell’API, residenti nella directory packages/common/constructs
.
Implementare la tua FastAPI
L’implementazione principale dell’API si trova in main.py
. Qui si definiscono le route API e le relative implementazioni. 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:
- Integrazione AWS Lambda Powertools per l’osservabilità
- Middleware per la gestione degli errori
- Correlazione richieste/risposte
- Raccolta metriche
- Handler AWS Lambda usando Mangum
Osservabilità con AWS Lambda Powertools
Logging
Configurazione del logging strutturato tramite AWS Lambda Powertools. Accesso al logger negli 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
- Percorso e metodo della richiesta
- Informazioni sul contesto Lambda
- Indicatori di cold start
Tracing
Tracciamento AWS X-Ray configurato automaticamente. Aggiunta di subsegmenti personalizzati:
from .init import app, tracer
@app.get("/items/{item_id}")@tracer.capture_methoddef read_item(item_id: int): # Crea un nuovo subsegmento with tracer.provider.in_subsegment("fetch-item-details"): # Logica qui return {"item_id": item_id}
Metriche
Metriche CloudWatch raccolte automaticamente. Aggiunta 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}
Metriche predefinite includono:
- Conteggio richieste
- Successi/fallimenti
- Metriche cold start
- Metriche per route specifiche
Gestione Errori
Gestione errori completa:
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}
Eccezioni non gestite vengono:
- Registrate con stack trace
- Tracciate come metriche di fallimento
- Restituiscono risposta 500 sicura
- Mantengono l’ID di correlazione
Streaming
Con FastAPI puoi restituire risposte in streaming usando StreamingResponse
.
Modifiche Infrastrutturali
Dato che API Gateway AWS non supporta lo streaming, dovrai deployare su piattaforme compatibili come AWS Lambda Function URL. Modificare il costrutto HttpApi
generato:
Modifiche di Esempio
import { Construct } from 'constructs';import { CfnOutput, Duration } from 'aws-cdk-lib';import { CfnOutput, Duration, Stack } from 'aws-cdk-lib'; import { CorsHttpMethod, HttpApi as _HttpApi,@@ -7,7 +7,16 @@ import { IHttpRouteAuthorizer, } from 'aws-cdk-lib/aws-apigatewayv2';
}, });
this.api = new _HttpApi(this, id, { corsPreflight: { allowOrigins: props.allowedOrigins ?? ['*'], allowMethods: [CorsHttpMethod.ANY], allowHeaders: [ 'authorization', 'content-type', 'x-amz-content-sha256', 'x-amz-date', 'x-amz-security-token', ], }, defaultAuthorizer: props.defaultAuthorizer, }); let apiUrl; if (props.apiType === 'api-gateway') { this.api = new _HttpApi(this, id, { corsPreflight: { allowOrigins: props.allowedOrigins ?? ['*'], allowMethods: [CorsHttpMethod.ANY], allowHeaders: [ 'authorization', 'content-type', 'x-amz-content-sha256', 'x-amz-date', 'x-amz-security-token', ], }, defaultAuthorizer: props.defaultAuthorizer, });
this.api.addRoutes({ path: '/{proxy+}', methods: [ HttpMethod.GET, HttpMethod.DELETE, HttpMethod.POST, HttpMethod.PUT, HttpMethod.PATCH, HttpMethod.HEAD, ], integration: new HttpLambdaIntegration( 'RouterIntegration', this.routerFunction, ), }); this.api.addRoutes({ path: '/{proxy+}', methods: [ HttpMethod.GET, HttpMethod.DELETE, HttpMethod.POST, HttpMethod.PUT, HttpMethod.PATCH, HttpMethod.HEAD, ], integration: new HttpLambdaIntegration( 'RouterIntegration', this.routerFunction, ), }); apiUrl = this.api.url; } else { const stack = Stack.of(this); this.routerFunction.addLayers( LayerVersion.fromLayerVersionArn( this, 'LWALayer', `arn:aws:lambda:${stack.region}:753240598075:layer:LambdaAdapterLayerX86:24`, ), ); this.routerFunction.addEnvironment('PORT', '8000'); this.routerFunction.addEnvironment( 'AWS_LWA_INVOKE_MODE', 'response_stream', ); this.routerFunction.addEnvironment( 'AWS_LAMBDA_EXEC_WRAPPER', '/opt/bootstrap', ); this.routerFunctionUrl = this.routerFunction.addFunctionUrl({ authType: FunctionUrlAuthType.AWS_IAM, invokeMode: InvokeMode.RESPONSE_STREAM, cors: { allowedOrigins: props.allowedOrigins ?? ['*'], allowedHeaders: [ 'authorization', 'content-type', 'x-amz-content-sha256', 'x-amz-date', 'x-amz-security-token', ], }, }); apiUrl = this.routerFunctionUrl.url; }
new CfnOutput(this, `${props.apiName}Url`, { value: this.api.url! }); new CfnOutput(this, `${props.apiName}Url`, { value: apiUrl! });
RuntimeConfig.ensure(this).config.httpApis = { ...RuntimeConfig.ensure(this).config.httpApis!, [props.apiName]: this.api.url!, [props.apiName]: apiUrl, }; }
public grantInvokeAccess(role: IRole) { role.addToPrincipalPolicy( new PolicyStatement({ effect: Effect.ALLOW, actions: ['execute-api:Invoke'], resources: [this.api.arnForExecuteApi('*', '/*', '*')], }), ); if (this.api) { role.addToPrincipalPolicy( new PolicyStatement({ effect: Effect.ALLOW, actions: ['execute-api:Invoke'], resources: [this.api.arnForExecuteApi('*', '/*', '*')], }), ); } else if (this.routerFunction) { role.addToPrincipalPolicy( new PolicyStatement({ effect: Effect.ALLOW, actions: ['lambda:InvokeFunctionUrl'], resources: [this.routerFunction.functionArn], conditions: { StringEquals: { 'lambda:FunctionUrlAuthType': 'AWS_IAM', }, }, }), ); } }}
Dopo le modifiche, aggiornare packages/common/constructs/src/app/http-apis/<my-api>.ts
per usare la nuova opzione function url.
Implementazione
Dopo l’aggiornamento infrastrutturale, implementa un API streaming in FastAPI:
- Restituisci
StreamingResponse
- Dichiarare il tipo di ritorno per ogni chunk
- Aggiungere l’estensione OpenAPI
x-streaming: true
per API Connection.
Esempio per lo streaming di oggetti JSON:
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
Per consumare stream di risposte, utilizza il Generatore API Connection per iterare in modo type-safe.
Deploy della tua FastAPI
Il generatore crea un costrutto CDK per il deployment in common/constructs
. Utilizzo in un’applicazione CDK:
import { MyApi } from ':my-scope/common-constructs';
export class ExampleStack extends Stack { constructor(scope: Construct, id: string) { const api = new MyApi(this, 'MyApi'); }}
Configura:
- Funzione Lambda con l’applicazione FastAPI
- API Gateway HTTP API come trigger
- Ruoli e permessi IAM
- Log group CloudWatch
- Configurazione tracciamento X-Ray
- Namespace metriche CloudWatch
Concessione Accessi
Metodo grantInvokeAccess
per concedere accessi:
api.grantInvokeAccess(myIdentityPool.authenticatedRole);
Sviluppo Locale
Server di sviluppo avviabile 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
Include:
- Auto-reload su modifiche
- Documentazione interattiva in
/docs
o/redoc
- Schema OpenAPI in
/openapi.json
Invocazione della tua FastAPI
Per invocare l’API da un sito React, utilizza il generatore api-connection
.