Pular para o conteúdo

FastAPI

FastAPI é um framework para construção de APIs em Python.

O gerador FastAPI cria uma nova aplicação FastAPI com configuração de infraestrutura AWS CDK ou Terraform. O backend gerado utiliza AWS Lambda para implantação serverless, exposto via AWS API Gateway. Configura AWS Lambda Powertools para observabilidade, incluindo registro de logs, rastreamento com AWS X-Ray e métricas no CloudWatch.

Você pode gerar uma nova API FastAPI de duas formas:

  1. Instale o Nx Console VSCode Plugin se ainda não o fez
  2. Abra o console Nx no VSCode
  3. Clique em Generate (UI) na seção "Common Nx Commands"
  4. Procure por @aws/nx-plugin - py#fast-api
  5. Preencha os parâmetros obrigatórios
    • Clique em Generate
    Parâmetro Tipo Padrão Descrição
    name Obrigatório string - Nome do projeto de API a ser gerado
    computeType string ServerlessApiGatewayRestApi O tipo de computação a ser usado para implantar esta API. Escolha entre ServerlessApiGatewayRestApi (padrão) ou ServerlessApiGatewayHttpApi.
    integrationPattern string isolated Como as integrações do API Gateway são geradas para a API. Escolha entre isolated (padrão) e shared.
    auth string IAM O método usado para autenticar com sua API. Escolha entre IAM (padrão), Cognito ou None.
    directory string packages O diretório para armazenar a aplicação.
    subDirectory string - O subdiretório onde o projeto é colocado. Por padrão, este é o nome do projeto.
    iacProvider string Inherit O provedor de IaC preferido. Por padrão, isso é herdado da sua seleção inicial.
    moduleName string - Nome do módulo Python

    O gerador criará a seguinte estrutura de projeto no diretório <directory>/<api-name>:

    • project.json Configuração do projeto e alvos de build
    • pyproject.toml Configuração do projeto Python e dependências
    • run.sh Script de bootstrap do Lambda Web Adapter para iniciar o app FastAPI via uvicorn
    • Directory<module_name>
      • __init__.py Inicialização do módulo
      • init.py Configura o app FastAPI e middleware do powertools
      • main.py Implementação da API
    • Directoryscripts
      • generate_open_api.py Script para gerar schema OpenAPI a partir do app FastAPI

    Como este gerador fornece infraestrutura como código com base no iacProvider escolhido, ele criará um projeto em packages/common que inclui os constructs CDK ou módulos Terraform relevantes.

    O projeto comum de infraestrutura como código está estruturado da seguinte forma:

    • Directorypackages/common/constructs
      • Directorysrc
        • Directoryapp/ Constructs para infraestrutura específica de um projeto/gerador
        • Directorycore/ Constructs genéricos reutilizados pelos constructs em app
        • index.ts Ponto de entrada exportando os constructs de app
      • project.json Metas de build e configuração do projeto

    Para implantar sua API, os seguintes arquivos são gerados:

    • Directorypackages/common/constructs/src
      • Directoryapp
        • Directoryapis
          • <project-name>.ts Construto CDK para implantar sua API
      • Directorycore
        • Directoryapi
          • http-api.ts Construto CDK para implantar uma API HTTP (se você escolheu implantar uma API HTTP)
          • rest-api.ts Construto CDK para implantar uma API REST (se você escolheu implantar uma API REST)
          • utils.ts Utilitários para os construtos da API

    A implementação principal da API está em main.py. É aqui que você define suas rotas e suas implementações. Exemplo:

    from pydantic import BaseModel
    from .init import app, tracer
    class Item(BaseModel):
    name: str
    @app.get("/items/{item_id}")
    @tracer.capture_method
    def get_item(item_id: int) -> Item:
    return Item(name=...)
    @app.post("/items")
    @tracer.capture_method
    def create_item(item: Item):
    return ...

    O gerador configura automaticamente vários recursos:

    1. Integração com AWS Lambda Powertools para observabilidade
    2. Middleware de tratamento de erros
    3. Correlação de requisições/respostas
    4. Coleta de métricas
    5. Implantação AWS Lambda via Lambda Web Adapter com uvicorn
    6. Streaming type-safe (somente REST API)

    O gerador configura logging estruturado usando AWS Lambda Powertools. Você pode acessar o logger nos handlers de rota:

    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}

    O logger inclui automaticamente:

    • IDs de correlação para rastreamento de requisições
    • Caminho e método da requisição
    • Informações de contexto do Lambda
    • Indicadores de cold start

    O rastreamento com AWS X-Ray é configurado automaticamente. Você pode adicionar subsegmentos personalizados aos seus traces:

    from .init import app, tracer
    @app.get("/items/{item_id}")
    @tracer.capture_method
    def read_item(item_id: int):
    # Cria um novo subsegmento
    with tracer.provider.in_subsegment("fetch-item-details"):
    # Sua lógica aqui
    return {"item_id": item_id}

    Métricas no CloudWatch são coletadas automaticamente para cada requisição. Você pode adicionar métricas personalizadas:

    from .init import app, metrics
    from 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}

    Métricas padrão incluem:

    • Contagem de requisições
    • Contagem de sucessos/falhas
    • Métricas de cold start
    • Métricas por rota

    O gerador inclui tratamento abrangente de erros:

    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}

    Exceções não tratadas são capturadas pelo middleware e:

    1. Registram a exceção completa com stack trace
    2. Gravam métrica de falha
    3. Retornam resposta 500 segura ao cliente
    4. Preservam o ID de correlação

    A FastAPI gerada suporta respostas em streaming nativamente ao usar REST API. A infraestrutura é configurada para usar o AWS Lambda Web Adapter para executar sua FastAPI via uvicorn dentro do Lambda, com ResponseTransferMode.STREAM no API Gateway para todas as operações REST API, o que permite que streaming funcione junto com operações não-streaming.

    O arquivo init.py gerado exporta uma classe JsonStreamingResponse que fornece streaming type-safe com geração adequada de schema OpenAPI. Isso garante que o gerador connection possa produzir métodos cliente de streaming corretamente tipados.

    from pydantic import BaseModel
    from .init import app, JsonStreamingResponse
    class Chunk(BaseModel):
    message: str
    async def generate_chunks():
    for i in range(100):
    yield Chunk(message=f"This is chunk {i}")
    @app.post(
    "/stream",
    response_class=JsonStreamingResponse,
    responses={200: JsonStreamingResponse.openapi_response(Chunk, "Stream of chunks")},
    )
    async def my_stream() -> JsonStreamingResponse:
    return JsonStreamingResponse(generate_chunks())

    A classe JsonStreamingResponse:

    1. Serializa modelos Pydantic para o formato JSON Lines (application/jsonl)
    2. Fornece um helper openapi_response que gera o schema OpenAPI correto com itemSchema, permitindo que o gerador connection produza métodos cliente de streaming type-safe

    Para consumir streams de respostas, utilize o gerador connection, que fornece um método type-safe para iterar sobre os chunks transmitidos.

    O gerador FastAPI cria código de infraestrutura CDK ou Terraform baseado no iacProvider selecionado. Use para implantar sua FastAPI.

    O construct CDK para implantação da API está na pasta common/constructs. Use em uma aplicação CDK:

    import { MyApi } from ':my-scope/common-constructs';
    export class ExampleStack extends Stack {
    constructor(scope: Construct, id: string) {
    // Adicione a API ao seu stack
    const api = new MyApi(this, 'MyApi', {
    integrations: MyApi.defaultIntegrations(this).build(),
    });
    }
    }

    Isso configura:

    1. Uma função AWS Lambda para cada operação na aplicação FastAPI
    2. API Gateway HTTP/REST como trigger da função
    3. Roles e permissões IAM
    4. Log group no CloudWatch
    5. Configuração de rastreamento X-Ray
    6. Namespace de métricas no CloudWatch

    Os construtos CDK da API REST/HTTP são configurados para fornecer uma interface type-safe para definir integrações para cada uma de suas operações.

    Os construtos CDK fornecem suporte completo a integrações type-safe conforme descrito abaixo.

    Você pode usar o método estático defaultIntegrations para utilizar o padrão padrão, que define uma função AWS Lambda individual para cada operação:

    new MyApi(this, 'MyApi', {
    integrations: MyApi.defaultIntegrations(this).build(),
    });

    Você pode acessar as funções AWS Lambda subjacentes através da propriedade integrations do construto da API, de forma type-safe. Por exemplo, se sua API define uma operação chamada sayHello e você precisa adicionar permissões a esta função, você pode fazer isso da seguinte forma:

    const api = new MyApi(this, 'MyApi', {
    integrations: MyApi.defaultIntegrations(this).build(),
    });
    // sayHello é tipado conforme as operações definidas em sua API
    api.integrations.sayHello.handler.addToRolePolicy(new PolicyStatement({
    effect: Effect.ALLOW,
    actions: [...],
    resources: [...],
    }));

    Se sua API usa o padrão shared, o roteador Lambda compartilhado é exposto como api.integrations.$router:

    const api = new MyApi(this, 'MyApi', {
    integrations: MyApi.defaultIntegrations(this).build(),
    });
    api.integrations.$router.handler.addEnvironment('LOG_LEVEL', 'DEBUG');

    Se você deseja personalizar as opções usadas ao criar a função Lambda para cada integração padrão, pode usar o método withDefaultOptions. Por exemplo, se deseja que todas suas funções Lambda residam em uma VPC:

    const vpc = new Vpc(this, 'Vpc', ...);
    new MyApi(this, 'MyApi', {
    integrations: MyApi.defaultIntegrations(this)
    .withDefaultOptions({
    vpc,
    })
    .build(),
    });

    Você também pode sobrescrever integrações para operações específicas usando o método withOverrides. Cada sobrescrita deve especificar uma propriedade integration que é tipada ao construto de integração CDK apropriado para a API HTTP ou REST. O método withOverrides também é type-safe. Por exemplo, se você deseja sobrescrever uma API getDocumentation para apontar para documentação hospedada em um site externo:

    new MyApi(this, 'MyApi', {
    integrations: MyApi.defaultIntegrations(this)
    .withOverrides({
    getDocumentation: {
    integration: new HttpIntegration('https://example.com/documentation'),
    },
    })
    .build(),
    });

    Você notará que a integração sobrescrita não terá mais uma propriedade handler quando acessada via api.integrations.getDocumentation.

    Você pode adicionar propriedades adicionais a uma integração que também serão tipadas adequadamente, permitindo que outros tipos de integração sejam abstraídos mas permaneçam type-safe. Por exemplo, se você criou uma integração S3 para uma API REST e depois deseja referenciar o bucket para uma operação específica:

    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(),
    });
    // Posteriormente, talvez em outro arquivo, você pode acessar a propriedade bucket que definimos
    // de forma type-safe
    api.integrations.getFile.bucket.grantRead(...);

    Você também pode fornecer options em sua integração para sobrescrever opções específicas de método como autorizadores. Por exemplo, se desejar usar autenticação Cognito para sua operação getDocumentation:

    new MyApi(this, 'MyApi', {
    integrations: MyApi.defaultIntegrations(this)
    .withOverrides({
    getDocumentation: {
    integration: new HttpIntegration('https://example.com/documentation'),
    options: {
    authorizer: new CognitoUserPoolsAuthorizer(...) // para REST, ou HttpUserPoolAuthorizer para HTTP API
    }
    },
    })
    .build(),
    });

    Se preferir, você pode optar por não usar as integrações padrão e fornecer diretamente uma para cada operação. Isso é útil se, por exemplo, cada operação precisar usar um tipo diferente de integração ou se você quiser receber um erro de tipo ao adicionar novas operações:

    new MyApi(this, 'MyApi', {
    integrations: {
    sayHello: {
    integration: new LambdaIntegration(...),
    },
    getDocumentation: {
    integration: new HttpIntegration(...),
    },
    },
    });

    Os construtos CDK de API gerados suportam dois padrões de integração:

    • isolated cria uma função Lambda por operação. Este é o padrão para APIs geradas.
    • shared cria um único roteador Lambda padrão e o reutiliza para cada operação, a menos que você sobrescreva integrações específicas.

    isolated oferece permissões e configuração mais granulares por operação. shared reduz a proliferação de funções Lambda e integrações do API Gateway, ainda permitindo sobrescritas seletivas.

    Por exemplo, definir pattern como 'shared' cria uma única função em vez de uma por integração:

    packages/common/constructs/src/app/apis/my-api.ts
    export class MyApi<...> extends ... {
    public static defaultIntegrations = (scope: Construct) => {
    ...
    return IntegrationBuilder.rest({
    pattern: 'shared',
    ...
    });
    };
    }

    Como as operações em FastAPI são definidas em Python e a infraestrutura CDK em TypeScript, instrumentamos geração de código para fornecer metadados ao construct CDK e prover uma interface type-safe para integrações.

    Um alvo generate:<ApiName>-metadata é adicionado ao project.json dos constructs comuns para facilitar essa geração de código, que emite um arquivo como packages/common/constructs/src/generated/my-api/metadata.gen.ts. Como isso é gerado em tempo de build, é ignorado no controle de versão.

    Se você selecionou autenticação IAM, pode usar o método grantInvokeAccess para conceder acesso à sua API:

    api.grantInvokeAccess(myIdentityPool.authenticatedRole);

    O gerador configura um servidor de desenvolvimento local que você pode executar com:

    Terminal window
    pnpm nx serve my-api

    Isso inicia um servidor de desenvolvimento FastAPI local com:

    • Recarregamento automático em alterações de código
    • Documentação interativa da API em /docs ou /redoc
    • Schema OpenAPI em /openapi.json

    Para invocar sua API de um site React, você pode usar o gerador connection.