콘텐츠로 이동

FastAPI

FastAPI는 Python으로 API를 구축하기 위한 프레임워크입니다.

FastAPI 생성기는 AWS CDK 또는 Terraform 인프라 설정이 포함된 새로운 FastAPI를 생성합니다. 생성된 백엔드는 서버리스 배포를 위해 AWS Lambda를 사용하며 AWS API Gateway API를 통해 노출됩니다. AWS Lambda Powertools를 설정하여 로깅, AWS X-Ray 추적, Cloudwatch 메트릭을 포함한 관측 가능성을 제공합니다.

다음 두 가지 방법으로 새로운 FastAPI를 생성할 수 있습니다:

  1. 설치 Nx Console VSCode Plugin 아직 설치하지 않았다면
  2. VSCode에서 Nx 콘솔 열기
  3. 클릭 Generate (UI) "Common Nx Commands" 섹션에서
  4. 검색 @aws/nx-plugin - py#fast-api
  5. 필수 매개변수 입력
    • 클릭 Generate
    매개변수 타입 기본값 설명
    name 필수 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.
    integrationPattern string isolated How API Gateway integrations are generated for the API. Choose between isolated (default) and shared.
    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 Inherit The preferred IaC provider. By default this is inherited from your initial selection.
    moduleName string - Python module name

    생성기는 <directory>/<api-name> 디렉토리에 다음 프로젝트 구조를 생성합니다:

    • project.json 프로젝트 구성 및 빌드 대상
    • pyproject.toml Python 프로젝트 구성 및 의존성
    • run.sh uvicorn을 통해 FastAPI 앱을 시작하는 Lambda Web Adapter 부트스트랩 스크립트
    • 디렉터리<module_name>
      • __init__.py 모듈 초기화
      • init.py FastAPI 앱 설정 및 powertools 미들웨어 구성
      • main.py API 구현
    • 디렉터리scripts
      • generate_open_api.py FastAPI 앱에서 OpenAPI 스키마 생성 스크립트

    이 생성기는 선택한 iacProvider 기반으로 인프라를 코드 형태로 제공하므로, packages/common 디렉터리에 관련 CDK 구축 요소 또는 Terraform 모듈을 포함하는 프로젝트를 생성합니다.

    공통 인프라스트럭처 코드 프로젝트의 구조는 다음과 같습니다:

    • 디렉터리packages/common/constructs
      • 디렉터리src
        • 디렉터리app/ 특정 프로젝트/생성기에 종속적인 인프라를 위한 구축 요소
        • 디렉터리core/ app 내 구축 요소에서 재사용되는 일반적 구축 요소
        • index.ts app의 구축 요소를 익스포트하는 진입점
      • project.json 프로젝트 빌드 대상 및 구성

    API 배포를 위해 다음 파일들이 생성됩니다:

    • 디렉터리packages/common/constructs/src
      • 디렉터리app
        • 디렉터리apis
          • <project-name>.ts API를 배포하기 위한 CDK construct
      • 디렉터리core
        • 디렉터리api
          • http-api.ts HTTP API 배포를 위한 CDK construct (HTTP API 배포를 선택한 경우)
          • rest-api.ts REST API 배포를 위한 CDK construct (REST API 배포를 선택한 경우)
          • utils.ts API constructs를 위한 유틸리티

    주요 API 구현은 main.py에 있습니다. 여기서 API 경로와 구현을 정의합니다. 예시:

    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 ...

    생성기는 자동으로 여러 기능을 설정합니다:

    1. 관측 가능성을 위한 AWS Lambda Powertools 통합
    2. 오류 처리 미들웨어
    3. 요청/응답 상관 관계
    4. 메트릭 수집
    5. uvicorn과 함께 Lambda Web Adapter를 통한 AWS Lambda 배포
    6. 타입 세이프 스트리밍 (REST API 전용)

    AWS Lambda Powertools를 이용한 관측 가능성

    섹션 제목: “AWS Lambda Powertools를 이용한 관측 가능성”

    생성기는 AWS Lambda Powertools를 사용해 구조화된 로깅을 구성합니다. 라우트 핸들러에서 로거에 접근할 수 있습니다:

    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}

    로거는 자동으로 다음을 포함합니다:

    • 요청 추적을 위한 상관 ID
    • 요청 경로 및 메서드
    • Lambda 컨텍스트 정보
    • 콜드 스타트 표시기

    AWS X-Ray 추적이 자동으로 구성됩니다. 추적에 커스텀 하위 세그먼트를 추가할 수 있습니다:

    from .init import app, tracer
    @app.get("/items/{item_id}")
    @tracer.capture_method
    def read_item(item_id: int):
    # 새로운 하위 세그먼트 생성
    with tracer.provider.in_subsegment("fetch-item-details"):
    # 로직 구현
    return {"item_id": item_id}

    각 요청에 대한 CloudWatch 메트릭이 자동으로 수집됩니다. 커스텀 메트릭을 추가할 수 있습니다:

    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}

    기본 메트릭 포함 사항:

    • 요청 수
    • 성공/실패 수
    • 콜드 스타트 메트릭
    • 경로별 메트릭

    생성기는 포괄적인 오류 처리를 포함합니다:

    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}

    처리되지 않은 예외는 미들웨어에 의해 포착되어:

    1. 스택 트레이스와 함께 전체 예외 기록
    2. 실패 메트릭 기록
    3. 클라이언트에 안전한 500 응답 반환
    4. 상관 ID 유지

    생성된 FastAPI는 REST API를 사용할 때 기본적으로 스트리밍 응답을 지원합니다. 인프라는 AWS Lambda Web Adapter를 사용하여 Lambda 내에서 uvicorn을 통해 FastAPI를 실행하도록 구성되어 있으며, 모든 REST API 작업에 대해 API Gateway에서 ResponseTransferMode.STREAM을 사용하여 스트리밍이 비스트리밍 작업과 함께 작동할 수 있도록 합니다.

    생성된 init.py는 적절한 OpenAPI 스키마 생성과 함께 타입 세이프 스트리밍을 제공하는 JsonStreamingResponse 클래스를 내보냅니다. 이를 통해 connection 생성기가 올바르게 타입이 지정된 스트리밍 클라이언트 메서드를 생성할 수 있습니다.

    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())

    JsonStreamingResponse 클래스는:

    1. Pydantic 모델을 JSON Lines 형식(application/jsonl)으로 직렬화
    2. itemSchema가 포함된 올바른 OpenAPI 스키마를 생성하는 openapi_response 헬퍼를 제공하여, connection 생성기가 타입 세이프 스트리밍 클라이언트 메서드를 생성할 수 있도록 함

    스트리밍 응답을 소비하려면 connection 생성기를 사용하여 스트리밍 청크를 반복하는 타입 세이프 메서드를 제공할 수 있습니다.

    FastAPI 생성기는 선택한 iacProvider에 따라 CDK 또는 Terraform 인프라 코드를 생성합니다. 이를 사용해 FastAPI를 배포할 수 있습니다.

    common/constructs 폴더에 API 배포를 위한 CDK 구성이 있습니다. CDK 애플리케이션에서 사용할 수 있습니다:

    import { MyApi } from ':my-scope/common-constructs';
    export class ExampleStack extends Stack {
    constructor(scope: Construct, id: string) {
    // 스택에 API 추가
    const api = new MyApi(this, 'MyApi', {
    integrations: MyApi.defaultIntegrations(this).build(),
    });
    }
    }

    이 설정은 다음을 구성합니다:

    1. FastAPI 애플리케이션의 각 작업에 대한 AWS Lambda 함수
    2. 함수 트리거로 API Gateway HTTP/REST API
    3. IAM 역할 및 권한
    4. CloudWatch 로그 그룹
    5. X-Ray 추적 구성
    6. CloudWatch 메트릭 네임스페이스

    REST/HTTP API CDK 구문은 각 작업에 대한 통합을 정의하기 위한 타입 안전 인터페이스를 제공하도록 구성됩니다.

    CDK 구문은 아래 설명된 대로 완전한 타입 안전 통합 지원을 제공합니다.

    정적 defaultIntegrations를 사용하여 각 작업에 대해 개별 AWS Lambda 함수를 정의하는 기본 패턴을 활용할 수 있습니다:

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

    API 구문의 integrations 속성을 통해 타입 안전 방식으로 기본 AWS Lambda 함수에 접근할 수 있습니다. 예를 들어 API에 sayHello 작업이 정의된 경우 이 함수에 권한을 추가하려면 다음과 같이 할 수 있습니다:

    const api = new MyApi(this, 'MyApi', {
    integrations: MyApi.defaultIntegrations(this).build(),
    });
    // sayHello는 API에 정의된 작업으로 타입이 지정됩니다
    api.integrations.sayHello.handler.addToRolePolicy(new PolicyStatement({
    effect: Effect.ALLOW,
    actions: [...],
    resources: [...],
    }));

    API가 shared 패턴을 사용하는 경우 공유 라우터 Lambda는 api.integrations.$router로 노출됩니다:

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

    withDefaultOptions 메서드를 사용하여 기본 통합 생성 시 사용되는 옵션을 사용자 정의할 수 있습니다. 예를 들어 모든 Lambda 함수를 VPC에 배치하려면:

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

    withOverrides 메서드를 사용하여 특정 작업에 대한 통합을 재정의할 수 있습니다. 각 재정의는 HTTP 또는 REST API에 적합한 CDK 통합 구문으로 타입이 지정된 integration 속성을 지정해야 합니다. withOverrides 메서드도 타입 안전합니다. 예를 들어 getDocumentation API를 외부 웹사이트 호스팅 문서로 재정의하려면:

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

    api.integrations.getDocumentation을 통해 접근 시 재정의된 통합에는 더 이상 handler 속성이 없습니다.

    추가 속성을 통합에 추가하면 다른 유형의 통합을 추상화하면서도 타입 안전성을 유지할 수 있습니다. 예를 들어 REST API용 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(),
    });
    // 이후 다른 파일에서 정의한 bucket 속성에 타입 안전 방식으로 접근 가능
    api.integrations.getFile.bucket.grantRead(...);

    통합에 options를 제공하여 Cognito 인증과 같은 특정 메서드 옵션을 재정의할 수 있습니다. 예를 들어 getDocumentation 작업에 Cognito 인증을 사용하려면:

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

    기본 통합 대신 각 작업에 직접 통합을 제공할 수 있습니다. 이는 각 작업이 다른 유형의 통합을 사용해야 하거나 새 작업 추가 시 타입 오류를 수신하려는 경우 유용합니다:

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

    생성된 CDK API 구문은 두 가지 통합 패턴을 지원합니다:

    • isolated는 작업당 하나의 Lambda 함수를 생성합니다. 이는 생성된 API의 기본값입니다.
    • shared는 단일 기본 라우터 Lambda를 생성하고 특정 통합을 재정의하지 않는 한 모든 작업에 재사용합니다.

    isolated는 작업별로 더 세밀한 권한과 구성을 제공합니다. shared는 선택적 재정의를 여전히 허용하면서 Lambda 및 API Gateway 통합 확산을 줄입니다.

    예를 들어 pattern'shared'로 설정하면 통합당 하나씩이 아닌 단일 함수를 생성합니다:

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

    FastAPI 작업은 Python으로 정의되고 CDK 인프라는 TypeScript로 작성되므로, 통합을 위한 타입 세이프 인터페이스를 제공하기 위해 메타데이터를 CDK 구성에 제공하는 코드 생성을 도입합니다.

    타입 세이프 코드 생성을 위해 common/constructsproject.jsongenerate:<ApiName>-metadata 대상이 추가됩니다. 이는 packages/common/constructs/src/generated/my-api/metadata.gen.ts와 같은 파일을 생성하며, 빌드 시 생성되므로 버전 관리에서 제외됩니다.

    IAM 인증을 선택한 경우 grantInvokeAccess 메서드를 사용해 API 접근 권한을 부여할 수 있습니다:

    api.grantInvokeAccess(myIdentityPool.authenticatedRole);

    생성기는 다음 명령으로 실행할 수 있는 로컬 개발 서버를 구성합니다:

    Terminal window
    pnpm nx run my-api:serve

    이 명령은 다음 기능이 포함된 로컬 FastAPI 개발 서버를 시작합니다:

    • 코드 변경 시 자동 리로드
    • /docs 또는 /redoc에서 대화형 API 문서
    • /openapi.json에서 OpenAPI 스키마

    React 웹사이트에서 API를 호출하려면 connection 생성기를 사용할 수 있습니다.