Smithy API를 관계형 데이터베이스에 연결
connection 생성기는 Smithy API를 관계형 데이터베이스 프로젝트에 연결하여, 모든 작업 구현이 데이터베이스에 액세스할 수 있도록 서비스 컨텍스트에 Prisma 클라이언트를 주입합니다.
사전 요구 사항
섹션 제목: “사전 요구 사항”이 생성기를 사용하기 전에 다음이 필요합니다:
ts#smithy-api프로젝트 (TypeScript 백엔드)ts#rdb프로젝트
사용법
섹션 제목: “사용법”생성기 실행
섹션 제목: “생성기 실행”- 설치 Nx Console VSCode Plugin 아직 설치하지 않았다면
- VSCode에서 Nx 콘솔 열기
- 클릭
Generate (UI)"Common Nx Commands" 섹션에서 - 검색
@aws/nx-plugin - connection - 필수 매개변수 입력
- 클릭
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:connectionSmithy API 백엔드 프로젝트를 소스로 선택하고 관계형 데이터베이스 프로젝트를 대상으로 선택합니다.
| 매개변수 | 타입 | 기본값 | 설명 |
|---|---|---|---|
| sourceProject 필수 | string | - | 소스 프로젝트 |
| targetProject 필수 | string | - | 연결할 대상 프로젝트 |
| sourceComponent | string | - | 연결을 시작할 소스 컴포넌트 (컴포넌트 이름, 소스 프로젝트 루트 기준 상대 경로, 또는 generator id). 프로젝트를 소스로 명시적으로 선택하려면 '.'을 사용하세요. |
| targetComponent | string | - | 연결할 대상 컴포넌트 (컴포넌트 이름, 대상 프로젝트 루트 기준 상대 경로, 또는 generator id). 프로젝트를 대상으로 명시적으로 선택하려면 '.'을 사용하세요. |
생성기 출력
섹션 제목: “생성기 출력”생성기는 Smithy API 백엔드의 기존 파일 세 개를 수정합니다:
디렉터리packages/api/src
- context.ts
ServiceContext에db속성 추가 - handler.ts
lambdaHandler내부에서 Prisma 클라이언트 생성,serviceHandler.handle로 전달 - local-server.ts 요청 핸들러 내부에서 Prisma 클라이언트 생성,
serviceHandler.handle로 전달
- context.ts
또한 API의 serve-local 타겟을 업데이트하여 데이터베이스를 자동으로 시작합니다.
작동 방식
섹션 제목: “작동 방식”ServiceContext
섹션 제목: “ServiceContext”생성기는 context.ts의 ServiceContext에 타입이 지정된 db 속성을 추가합니다:
import { getPrisma as getMyDb } from ':my-scope/my-db';
export interface ServiceContext { tracer: Tracer; logger: Logger; metrics: Metrics; myDb: Awaited<ReturnType<typeof getMyDb>>;}Lambda Handler
섹션 제목: “Lambda Handler”Prisma 클라이언트는 lambdaHandler 내부에서 인스턴스화되고 서비스 컨텍스트를 통해 전달됩니다:
import { getPrisma as getMyDb } from ':my-scope/my-db';
export const lambdaHandler = async (event: APIGatewayProxyEvent) => { const httpRequest = convertEvent(event); const myDb = await getMyDb(); const httpResponse = await serviceHandler.handle(httpRequest, { tracer, logger, metrics, myDb, }); return convertVersion1Response(httpResponse);};작업에서 데이터베이스 사용
섹션 제목: “작업에서 데이터베이스 사용”작업 구현에서 컨텍스트로부터 db에 액세스합니다:
import { ListUsersOperationInput, ListUsersOperationOutput } from '../generated/ssdk/index.js';import { ServiceContext } from '../context.js';
export const listUsers = async ( input: ListUsersOperationInput, ctx: ServiceContext,): Promise<ListUsersOperationOutput> => { const users = await ctx.myDb.user.findMany(); return { users };};인프라
섹션 제목: “인프라”런타임에 API가 데이터베이스에 연결할 수 있도록 하려면, API Lambda 함수를 데이터베이스와 동일한 VPC에 배포하고 네트워크 및 IAM 액세스 권한을 부여해야 합니다.
애플리케이션 스택에서 API를 데이터베이스와 동일한 VPC에 배포한 다음, allowDefaultPortFrom 및 grantConnect를 호출하여 네트워크 경로를 열고 각 Lambda 핸들러에 IAM rds-db:connect 권한을 부여합니다:
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);});API Lambda 함수를 프라이빗 격리 서브넷이 아닌 외부 연결이 가능한 프라이빗 서브넷에 배포하세요. 런타임에 getPrisma()는 AWS AppConfig에서 데이터베이스 연결 세부 정보를 가져오는데, 이는 아웃바운드 인터넷 액세스가 필요한 퍼블릭 AWS 서비스 엔드포인트입니다.
데이터베이스 모듈 출력을 API 모듈에 전달하여 데이터베이스에 도달하고 런타임 구성을 읽을 수 있도록 합니다:
module "my_database" { source = "../../common/terraform/src/app/dbs/my-database" vpc_id = module.vpc.vpc_id database_subnet_ids = module.vpc.private_isolated_subnet_ids lambda_subnet_ids = module.vpc.private_subnet_ids}
module "api" { source = "..." vpc_id = module.vpc.vpc_id private_subnet_ids = module.vpc.private_subnet_ids
appconfig_application_id = module.my_database.appconfig_application_id database_cluster_resource_id = module.my_database.cluster_resource_id database_runtime_user = module.my_database.database_runtime_user database_security_group_id = module.my_database.security_group_id database_port = module.my_database.cluster_port
environment_variables = { RUNTIME_CONFIG_APP_ID = module.my_database.appconfig_application_id }}API Lambda 함수를 프라이빗 격리 서브넷이 아닌 외부 연결이 가능한 프라이빗 서브넷에 배포하세요. API Lambda 역할에 rds-db:connect 권한이 있고 해당 보안 그룹이 데이터베이스 포트에서 데이터베이스 보안 그룹에 도달할 수 있는지 확인하세요.
로컬 개발
섹션 제목: “로컬 개발”생성기는 local-server.ts의 요청 핸들러 내부에 동일한 Prisma 클라이언트 주입을 적용합니다:
import { getPrisma as getMyDb } from ':my-scope/my-db';
const server = createServer(async function (req, res) { const httpRequest = convertRequest(req); const myDb = await getMyDb(); const httpResponse = await serviceHandler.handle(httpRequest, { tracer, logger, metrics, myDb, }); return writeResponse(httpResponse, res);});pnpm nx serve-local <api-project-name>yarn nx serve-local <api-project-name>npx nx serve-local <api-project-name>bunx nx serve-local <api-project-name>이렇게 하면 API와 로컬 데이터베이스가 모두 시작됩니다. SERVE_LOCAL=true 환경 변수가 자동으로 설정되므로 Prisma 클라이언트는 Aurora 대신 로컬 Docker 데이터베이스에 연결됩니다.