콘텐츠로 이동

Blog

AWS PDK에서 마이그레이션

이 가이드는 AWS PDK 프로젝트를 Nx Plugin for AWS로 마이그레이션하는 예시와 일반적인 지침을 제공합니다.

Nx Plugin for AWS로 마이그레이션하면 PDK 대비 다음과 같은 이점이 있습니다:

  • 더 빠른 빌드
  • 더 쉬운 사용성 (UI 및 CLI)
  • Vibe-coding 지원 (MCP 서버를 사용해 보세요!)
  • 더 현대적인 기술 스택
  • 로컬 API 및 웹사이트 개발
  • 더 많은 제어권 (사용 사례에 맞게 파일 수정 가능)
  • 기타 다양한 개선 사항!

예시 마이그레이션: 쇼핑 리스트 애플리케이션

섹션 제목: “예시 마이그레이션: 쇼핑 리스트 애플리케이션”

이 가이드에서는 PDK 튜토리얼의 쇼핑 리스트 애플리케이션을 마이그레이션 대상으로 사용합니다. 직접 따라 하려면 해당 튜토리얼의 단계를 따라 대상 프로젝트를 생성하세요.

쇼핑 리스트 애플리케이션은 다음 PDK 프로젝트 유형으로 구성됩니다:

  • MonorepoTsProject
  • TypeSafeApiProject
  • CloudscapeReactTsWebsiteProject
  • InfrastructureTsProject

시작으로 새 프로젝트를 위한 워크스페이스를 생성합니다. 기존 프로젝트를 직접 수정하는 방식보다 깔끔한 결과를 얻을 수 있습니다. Nx 워크스페이스 생성은 PDK의 MonorepoTsProject 사용과 동일합니다:

Terminal window
npx create-nx-workspace@21.4.1 shopping-list --pm=pnpm --preset=@aws/nx-plugin@0.50.0 --iacProvider=CDK --ci=skip

생성된 shopping-list 디렉토리를 선호하는 IDE에서 엽니다.

쇼핑 목록 애플리케이션에서 사용된 TypeSafeApiProject는 다음을 활용했습니다:

  • 모델링 언어로 Smithy 사용
  • 연산 구현을 위한 TypeScript
  • React 웹사이트 통합을 위한 TypeScript 훅 생성

따라서 ts#smithy-api 생성기를 사용해 동등한 기능을 제공할 수 있습니다.

ts#smithy-api 생성기를 실행해 packages/api에 API 프로젝트를 설정합니다:

  1. 설치 Nx Console VSCode Plugin 아직 설치하지 않았다면
  2. VSCode에서 Nx 콘솔 열기
  3. 클릭 Generate (UI) "Common Nx Commands" 섹션에서
  4. 검색 @aws/nx-plugin - ts#smithy-api
  5. 필수 매개변수 입력
    • name: api
    • namespace: com.aws
    • auth: IAM
  6. 클릭 Generate

이렇게 하면 model 프로젝트와 backend 프로젝트가 생성됩니다. model은 Smithy 모델을 포함하며, backend는 서버 구현을 포함합니다.

백엔드는 Smithy Server Generator for TypeScript를 사용합니다. 이에 대해서는 아래에서 자세히 살펴보겠습니다.

기본 Smithy API 프로젝트 구조가 준비되었으므로 모델을 마이그레이션합니다:

  1. packages/api/model/src에 생성된 예제 Smithy 파일 삭제

  2. PDK 프로젝트의 packages/api/model/src/main/smithy 디렉토리에서 새 프로젝트의 packages/api/model/src로 모델 복사

  3. PDK 애플리케이션과 일치하도록 smithy-build.json의 서비스 이름 및 네임스페이스 업데이트:

    smithy-build.json
    "plugins": {
    "openapi": {
    "service": "com.aws#MyApi",
    ...
  4. main.smithy의 서비스에 Smithy TypeScript Server SDK 사용 시 필수인 ValidationException 오류 추가:

    main.smithy
    use smithy.framework#ValidationException
    /// My Shopping List API
    @restJson1
    service MyApi {
    version: "1.0"
    operations: [
    GetShoppingLists
    PutShoppingList
    DeleteShoppingList
    ]
    errors: [
    BadRequestError
    NotAuthorizedError
    InternalFailureError
    ValidationException
    ]
    }
  5. 생성된 클라이언트에 페이지네이션 정보를 제공하는 트레이트 정의를 위해 packages/api/model/srcextensions.smithy 파일 추가:

    extensions.smithy
    $version: "2"
    namespace com.aws
    use smithy.openapi#specificationExtension
    @trait
    @specificationExtension(as: "x-cursor")
    structure cursor {
    inputToken: String
    enabled: Boolean
    }
  6. get-shopping-lists.smithyGetShoppingLists 연산에 새 @cursor 트레이트 추가:

    operations/get-shopping-lists.smithy
    @readonly
    @http(method: "GET", uri: "/shopping-list")
    @paginated(inputToken: "nextToken", outputToken: "nextToken", pageSize: "pageSize", items: "shoppingLists")
    @cursor(inputToken: "nextToken")
    @handler(language: "typescript")
    operation GetShoppingLists {
    input := with [PaginatedInputMixin] {
    @httpQuery("shoppingListId")
    shoppingListId: ShoppingListId
    }

    Nx Plugin for AWS(api-connection 생성기 통해)의 클라이언트 생성기를 사용하는 경우 @paginated 연산에도 @cursor를 사용해야 합니다.

  7. 모든 연산에서 @handler 트레이트 제거. 이 트레이트는 Nx Plugin for AWS에서 지원하지 않으며, ts#smithy-api를 사용하면 이 트레이트가 생성하는 람다 함수 CDK 구성체와 번들링 타겟이 필요 없습니다(모든 람다 함수에 단일 번들을 사용하기 때문).

이제 모델 변경 사항을 확인하고 생성된 서버 코드가 작동하는지 빌드를 실행합니다. 백엔드 프로젝트(@shopping-list/api)에 일부 오류가 발생하지만 다음 단계에서 해결할 것입니다.

Terminal window
pnpm nx run-many --target build

api/backend 프로젝트는 Type Safe API의 api/handlers/typescript 프로젝트와 유사하다고 볼 수 있습니다.

Type Safe API와 ts#smithy-api 생성기의 주요 차이점은 핸들러 구현 시 Smithy Server Generator for TypeScript를 사용한다는 점입니다(Type Safe API의 자체 생성 핸들러 래퍼 대신).

쇼핑 목록 애플리케이션의 람다 핸들러는 @aws-sdk/client-dynamodb 패키지를 사용하므로 먼저 설치합니다:

Terminal window
pnpm add -w @aws-sdk/client-dynamodb

그런 다음 PDK 프로젝트의 handlers/src/dynamo-client.ts 파일을 backend/src/operations로 복사해 핸들러에서 사용할 수 있게 합니다.

핸들러 마이그레이션은 다음 일반 단계를 따릅니다:

  1. PDK 프로젝트의 packages/api/handlers/typescript/src 디렉토리에서 새 프로젝트의 packages/api/backend/src/operations로 핸들러 복사

  2. my-api-typescript-runtime 임포트 제거 후 생성된 TypeScript Server SDK에서 연산 타입 및 ServiceContext 임포트:

    import {
    deleteShoppingListHandler,
    DeleteShoppingListChainedHandlerFunction,
    INTERCEPTORS,
    Response,
    LoggingInterceptor,
    } from 'myapi-typescript-runtime';
    import { DeleteShoppingList as DeleteShoppingListOperation } from '../generated/ssdk/index.js';
    import { ServiceContext } from '../context.js';
  3. 핸들러 래퍼 익스포트 삭제

    export const handler = deleteShoppingListHandler(
    ...INTERCEPTORS,
    deleteShoppingList,
    );
  4. SSDK 사용을 위해 연산 핸들러 시그니처 업데이트:

    export const deleteShoppingList: DeleteShoppingListChainedHandlerFunction = async (request) => {
    export const DeleteShoppingList: DeleteShoppingListOperation<ServiceContext> = async (input, ctx) => {
  5. LoggingInterceptor 사용을 ctx.logger로 대체 (메트릭스 및 트레이싱 인터셉터도 동일):

    LoggingInterceptor.getLogger(request).info('...');
    ctx.logger.info('...');
  6. 입력 파라미터 참조 업데이트. SSDK는 Smithy 모델과 정확히 일치하는 타입을 제공하므로(바디 파라미터와 별도로 경로/쿼리/헤더 파라미터를 그룹화하지 않음) 입력 참조를 수정:

    const shoppingListId = request.input.requestParameters.shoppingListId;
    const shoppingListId = input.shoppingListId;
  7. Response 사용 제거. SSDK에서는 일반 객체 반환:

    return Response.success({ shoppingListId });
    return { shoppingListId };

    Response 던지기/반환 대신 SSDK 생성 오류 사용:

    throw Response.badRequest({ message: 'oh no' });
    return Response.badRequest({ message: 'oh no' });
    import { BadRequestError } from '../generated/ssdk/index.js';
    throw new BadRequestError({ message: 'oh no' });
  8. 상대 임포트에 ESM 문법 사용(.js 확장자 추가)

  9. service.ts에 연산 추가

    service.ts
    import { ServiceContext } from './context.js';
    import { MyApiService } from './generated/ssdk/index.js';
    import { DeleteShoppingList } from './operations/delete-shopping-list.js';
    import { GetShoppingLists } from './operations/get-shopping-lists.js';
    import { PutShoppingList } from './operations/put-shopping-list.js';
    // 서비스에 연산 등록
    export const Service: MyApiService<ServiceContext> = {
    PutShoppingList,
    GetShoppingLists,
    DeleteShoppingList,
    };
튜토리얼의 세 가지 쇼핑 목록 연산에 대한 전체 변경 전/후 예시 보기

Smithy API 프로젝트를 packages/api에 일관성 있게 배치하기 위해 초기 이름을 api로 생성했습니다. 이제 Smithy API가 service Api 대신 service MyApi를 정의하므로 getApiServiceHandlergetMyApiServiceHandler로 업데이트해야 합니다.

handler.ts 수정:

packages/api/backend/src/handler.ts
import { getApiServiceHandler } from './generated/ssdk/index.js';
import { getMyApiServiceHandler } from './generated/ssdk/index.js';
process.env.POWERTOOLS_METRICS_NAMESPACE = 'Api';
process.env.POWERTOOLS_SERVICE_NAME = 'Api';
const tracer = new Tracer();
const logger = new Logger();
const metrics = new Metrics();
const serviceHandler = getApiServiceHandler(Service);
const serviceHandler = getMyApiServiceHandler(Service);

local-server.ts 수정:

packages/api/backend/src/local-server.ts
import { getApiServiceHandler } from './generated/ssdk/index.js';
import { getMyApiServiceHandler } from './generated/ssdk/index.js';
const PORT = 3001;
const tracer = new Tracer();
const logger = new Logger();
const metrics = new Metrics();
const serviceHandler = getApiServiceHandler(Service);
const serviceHandler = getMyApiServiceHandler(Service);

추가로 packages/api/backend/project.jsonmetadata.apiNamemy-api로 업데이트:

packages/api/backend/project.json
"metadata": {
"generator": "ts#smithy-api",
"apiName": "api",
"apiName": "my-api",
"auth": "IAM",
"modelProject": "@shopping-list/api-model",
"ports": [3001]
},

현재까지의 마이그레이션 작업을 검증하기 위해 빌드 실행:

Terminal window
pnpm nx run-many --target build

쇼핑 리스트 애플리케이션에서 사용된 CloudscapeReactTsWebsiteProject는 CloudScape와 Cognito 인증이 내장된 React 웹사이트를 구성했습니다.

이 프로젝트 유형은 현재 더 이상 사용되지 않는 create-react-app을 활용했습니다. 이 가이드에서 웹사이트를 마이그레이션하기 위해 ts#react-website 생성기를 사용할 것이며, 이는 Vite와 같은 더 현대적이고 지원되는 기술을 사용합니다.

마이그레이션 과정에서 PDK에서 구성한 React Router에서 TanStack Router로 이동할 것입니다. 이는 웹사이트 라우팅에 추가적인 타입 안전성을 제공합니다.

packages/website에 웹사이트 프로젝트를 설정하려면 ts#react-website 생성기를 실행하세요:

  1. 설치 Nx Console VSCode Plugin 아직 설치하지 않았다면
  2. VSCode에서 Nx 콘솔 열기
  3. 클릭 Generate (UI) "Common Nx Commands" 섹션에서
  4. 검색 @aws/nx-plugin - ts#react-website
  5. 필수 매개변수 입력
    • name: website
  6. 클릭 Generate

위 React 웹사이트 생성기는 CloudscapeReactTsWebsiteProject처럼 기본적으로 Cognito 인증을 번들로 제공하지 않습니다. 대신 ts#react-website#auth 생성기를 통해 명시적으로 추가합니다.

  1. 설치 Nx Console VSCode Plugin 아직 설치하지 않았다면
  2. VSCode에서 Nx 콘솔 열기
  3. 클릭 Generate (UI) "Common Nx Commands" 섹션에서
  4. 검색 @aws/nx-plugin - ts#react-website#auth
  5. 필수 매개변수 입력
    • project: website
    • cognitoDomain: shopping-list
  6. 클릭 Generate

이렇게 하면 Cognito 호스팅 UI를 사용하여 사용자가 로그인하도록 적절한 리디렉션을 관리하는 React 컴포넌트가 추가됩니다. 또한 packages/common/constructsUserIdentity라는 Cognito 리소스를 배포하는 CDK 구문이 추가됩니다.

PDK에서는 Projen 프로젝트를 서로 전달하여 통합 코드를 생성할 수 있었습니다. 이 기능은 쇼핑 리스트 애플리케이션에서 웹사이트가 API와 통합되도록 구성하는 데 사용되었습니다.

Nx Plugin for AWS에서는 api-connection 생성기를 통해 API 통합이 지원됩니다. 다음으로 이 생성기를 사용하여 웹사이트가 Smithy API를 호출할 수 있도록 설정합니다:

  1. 설치 Nx Console VSCode Plugin 아직 설치하지 않았다면
  2. VSCode에서 Nx 콘솔 열기
  3. 클릭 Generate (UI) "Common Nx Commands" 섹션에서
  4. 검색 @aws/nx-plugin - api-connection
  5. 필수 매개변수 입력
    • sourceProject: website
    • targetProject: api
  6. 클릭 Generate

이렇게 하면 생성된 TypeScript 클라이언트를 통해 웹사이트가 API를 호출할 수 있는 필요한 클라이언트 제공자와 빌드 대상이 생성됩니다.

CloudscapeReactTsWebsiteProject는 쇼핑 리스트 애플리케이션에서 사용된 @aws-northstar/ui에 대한 종속성을 자동으로 포함했으므로 여기에 추가합니다:

Terminal window
pnpm add -w @aws-northstar/ui

쇼핑 리스트 애플리케이션에는 CreateItem 컴포넌트와 ShoppingList, ShoppingLists 두 페이지가 있습니다. TanStack Router와 Nx Plugin for AWS TypeScript 클라이언트 코드 생성기를 사용하므로 일부 조정을 통해 이를 새 웹사이트로 마이그레이션합니다.

  1. PDK 프로젝트의 packages/website/src/components/CreateItem/index.tsx를 새 프로젝트의 동일한 위치로 복사합니다.

  2. packages/website/src/pages/ShoppingLists/index.tsxpackages/website/src/routes/index.tsx로 복사합니다. ShoppingLists는 홈 페이지이며 TanStack Router의 파일 기반 라우팅을 사용하기 때문입니다.

  3. packages/website/src/pages/ShoppingList/index.tsxpackages/website/src/routes/$shoppingListId.tsx로 복사합니다. ShoppingList/:shoppingListId 경로에 표시할 페이지입니다.

이제 IDE에 일부 빌드 오류가 표시될 것입니다. 아래에 설명된 몇 가지 추가 변경 사항을 적용하여 새 프레임워크에 맞춰야 합니다.

React Router에서 TanStack Router로 마이그레이션

섹션 제목: “React Router에서 TanStack Router로 마이그레이션”

파일 기반 라우팅을 사용하므로 웹사이트 로컬 개발 서버를 사용하여 라우트 구성을 자동으로 생성할 수 있습니다. 로컬 웹사이트 서버를 시작합니다:

Terminal window
pnpm nx serve-local website

일부 오류가 표시되지만 포트 4200에서 로컬 웹사이트 서버와 포트 3001에서 로컬 Smithy API 서버가 시작됩니다.

TanStack Router로 마이그레이션하려면 routes/index.tsxroutes/$shoppingListId.tsx에서 다음 단계를 따르세요:

  1. 각 라우트를 등록하기 위해 createFileRoute 추가:

    import { createFileRoute } from "@tanstack/react-router";
    ...
    export default ShoppingLists;
    export const Route = createFileRoute('/')({
    component: ShoppingLists,
    });

    파일을 저장하면 createFileRoute 호출과 관련된 타입 오류가 사라집니다.

  2. useNavigate 훅 교체:

    임포트 업데이트:

    import { useNavigate } from 'react-router-dom';
    import { useNavigate } from '@tanstack/react-router';

    useNavigate에서 반환된 navigate 메서드 호출을 타입 안전한 경로로 업데이트:

    navigate(`/${cell.shoppingListId}`);
    navigate({
    to: '/$shoppingListId',
    params: { shoppingListId: cell.shoppingListId },
    });
  3. useParams 훅 교체:

    임포트 제거:

    import { useParams } from 'react-router-dom';

    useParams 호출을 위에서 생성한 Route의 훅으로 교체. 이제 타입 안전합니다!

    const { shoppingListId } = useParams();
    const { shoppingListId } = Route.useParams();

PDK 프로젝트보다 파일 트리에서 라우트 파일의 위치가 덜 중첩되었으므로 routes/index.tsxroutes/$shoppingListId.tsx에서 CreateItem 임포트를 수정합니다:

import CreateItem from "../../components/CreateItem";
import CreateItem from "../components/CreateItem";

AppLayoutContext도 새 프로젝트에서 위치가 약간 다릅니다:

import { AppLayoutContext } from "../../layouts/App";
import { AppLayoutContext } from "../components/AppLayout";

새로 생성된 TypeScript 클라이언트 사용

섹션 제목: “새로 생성된 TypeScript 클라이언트 사용”

이제 Nx Plugin for AWS에서 제공하는 개선된 TypeScript 클라이언트를 사용하도록 마이그레이션합니다. 다음 단계를 따르세요:

  1. 이전 Type Safe API 대신 새로 생성된 클라이언트와 타입 임포트:

    import {
    ShoppingList,
    usePutShoppingList,
    useDeleteShoppingList,
    useGetShoppingLists,
    } from "myapi-typescript-react-query-hooks";
    import { ShoppingList } from "../generated/my-api/types.gen";
    import { useMyApi } from "../hooks/useMyApi";
    import { useInfiniteQuery, useMutation } from "@tanstack/react-query";

    routes/$shoppingListId.tsx에서는 ShoppingList 타입을 _ShoppingList로 임포트하므로 동일하게 types.gen에서 임포트합니다.

  2. 새 TanStack Query 훅 인스턴스화:

    const getShoppingLists = useGetShoppingLists({ pageSize: PAGE_SIZE });
    const putShoppingList = usePutShoppingList();
    const deleteShoppingList = useDeleteShoppingList();
    const api = useMyApi();
    const getShoppingLists = useInfiniteQuery(
    api.getShoppingLists.infiniteQueryOptions(
    { pageSize: PAGE_SIZE },
    { getNextPageParam: (p) => p.nextToken },
    ),
    );
    const putShoppingList = useMutation(api.putShoppingList.mutationOptions());
    const deleteShoppingList = useMutation(
    api.deleteShoppingList.mutationOptions(),
    );
  3. 요청 본문 매개변수를 위한 <operation>RequestContent 래퍼 제거:

    await putShoppingList.mutateAsync({
    putShoppingListRequestContent: {
    name: item,
    },
    });

TanStack Query v4에서 v5로 마이그레이션

섹션 제목: “TanStack Query v4에서 v5로 마이그레이션”

api-connection 생성기에서 추가된 v5와 PDK에서 사용한 TanStack Query v4 간의 차이로 인해 남은 오류를 수정합니다:

  1. 뮤테이션에서 isLoadingisPending으로 교체:

    putShoppingList.isLoading
    putShoppingList.isPending
  2. 쇼핑 리스트 애플리케이션에서 TanStack Query v4의 타입을 기대하는 @aws-northstar/uiInfiniteQueryTable을 사용합니다. 이는 v5의 무한 쿼리와 호환되므로 타입 오류를 억제합니다:

    <InfiniteQueryTable
    query={getShoppingLists}
    query={getShoppingLists as any}

이제 http://localhost:4200/ 에서 로컬 웹사이트에 접속할 수 있습니다!

모든 것이 마이그레이션되었으므로 웹사이트가 로드되어야 합니다! 쇼핑 리스트 애플리케이션이 API, 웹사이트, Identity 외에 DynamoDB 테이블에만 의존하므로 shopping_list DynamoDB 테이블이 해당 리전에 있고 로컬 AWS 자격 증명이 접근 권한이 있다면 웹사이트가 완전히 작동할 것입니다.

그렇지 않더라도 다음에 인프라를 마이그레이션할 예정이므로 괜찮습니다.

튜토리얼의 두 쇼핑 리스트 페이지에 대한 전체 Before/After 예제 보기

쇼핑 목록 애플리케이션을 마이그레이션하기 위해 필요한 마지막 프로젝트는 InfrastructureTsProject입니다. 이는 TypeScript CDK 프로젝트로, Nx Plugin for AWS에서 이에 상응하는 것은 ts#infra 생성기입니다.

Projen 프로젝트뿐만 아니라 PDK는 이러한 프로젝트들이 의존하는 CDK 구문들도 제공했습니다. 우리는 PDK의 CDK 구문 대신 Nx Plugin for AWS가 생성한 구문들을 사용하도록 쇼핑 목록 애플리케이션을 마이그레이션할 것입니다.

TypeScript CDK 인프라 프로젝트 생성

섹션 제목: “TypeScript CDK 인프라 프로젝트 생성”

packages/infra에 인프라 프로젝트를 설정하려면 ts#infra 생성기를 실행하세요:

  1. 설치 Nx Console VSCode Plugin 아직 설치하지 않았다면
  2. VSCode에서 Nx 콘솔 열기
  3. 클릭 Generate (UI) "Common Nx Commands" 섹션에서
  4. 검색 @aws/nx-plugin - ts#infra
  5. 필수 매개변수 입력
    • name: infra
  6. 클릭 Generate

PDK 쇼핑 목록 애플리케이션은 CDK 애플리케이션 스택 내에서 다음 구문들을 인스턴스화했습니다:

  • 쇼핑 목록을 저장하는 DynamoDB 테이블용 DatabaseConstruct
  • PDK에서 직접 가져온 Cognito 리소스용 UserIdentity
  • Smithy API 배포용 MyApi (PDK의 TypeSafeRestApi CDK 구문을 기반으로 타입 안전 통합을 사용하는 생성된 TypeScript CDK 구문)
  • PDK의 StaticWebsite CDK 구문을 래핑한 웹사이트 배포용 Website

이제 각각을 새 프로젝트로 마이그레이션하겠습니다.

PDK 쇼핑 목록 애플리케이션의 packages/infra/src/stacks/application-stack.ts를 새 프로젝트의 동일한 위치에 복사하세요. 아래에서 해결할 TypeScript 오류가 표시될 것입니다.

PDK 쇼핑 목록 애플리케이션은 packages/src/constructs/database.tsDatabase 구문을 가지고 있었습니다. 이를 새 프로젝트의 동일한 위치에 복사하세요.

Nx Plugin for AWS는 PDK Nag보다 조금 더 엄격한 Checkov를 보안 테스트에 사용하므로 다음과 같이 일부 규칙 억제를 추가해야 합니다:

constructs/database.ts
import { suppressRules } from ':shopping-list/common-constructs';
...
suppressRules(
this.shoppingListTable,
['CKV_AWS_28', 'CKV_AWS_119'],
'Backup and KMS key not required for this project',
);

application-stack.ts에서 DatabaseConstruct 임포트를 ESM 구문으로 업데이트하세요:

stacks/application-stack.ts
import { DatabaseConstruct } from '../constructs/database';
import { DatabaseConstruct } from '../constructs/database.js';

UserIdentity 구문은 일반적으로 임포트만 조정하면 변경 없이 교체할 수 있습니다.

import { UserIdentity } from "@aws/pdk/identity";
import { UserIdentity } from ':shopping-list/common-constructs';
...
const userIdentity = new UserIdentity(this, `${id}UserIdentity`);

UserIdentity 구문에서 사용하는 기본 구문들은 PDK가 @aws-cdk/aws-cognito-identitypool-alpha를 사용한 반면, 직접 aws-cdk-lib에서 제공됩니다.

PDK 쇼핑 목록 애플리케이션은 Smithy 모델에서 생성된 타입 안전 CDK 구문을 인스턴스화하는 constructs/apis/myapi.ts에 구문을 가지고 있었습니다.

이 구문 외에도 PDK 프로젝트는 @handler 트레이트를 사용해 생성된 람다 함수 CDK 구문들도 생성했습니다.

Type Safe API와 마찬가지로 Nx Plugin for AWS는 Smithy 모델 기반의 타입 안전 통합을 제공하지만 훨씬 간단하고 유연한 방식으로 구현됩니다. 빌드 시 전체 CDK 구문을 생성하는 대신 최소한의 “메타데이터”만 생성되며, packages/common/constructs/src/app/apis/api.ts에서 일반적인 방식으로 사용합니다. ts#smithy-api 생성기 가이드에서 구문 사용법을 더 알아볼 수 있습니다.

다음 단계를 따르세요:

  1. application-stack.ts에서 Api 구문 인스턴스화

    stacks/application-stack.ts
    import { MyApi } from "../constructs/apis/myapi";
    import { Api } from ':shopping-list/common-constructs';
    ...
    const myapi = new MyApi(this, "MyApi", {
    databaseConstruct,
    userIdentity,
    });
    const api = new Api(this, 'MyApi', {
    integrations: Api.defaultIntegrations(this).build(),
    });

    여기서 Api.defaultIntegrations(this).build()를 사용합니다 - 기본 동작은 API의 각 작업에 대해 람다 함수를 생성하는 것으로, myapi.ts의 동작과 동일합니다.

  2. 람다 함수에 DynamoDB 테이블 접근 권한 부여

    PDK 쇼핑 목록 애플리케이션에서는 DatabaseConsructMyApi에 전달되어 각 생성된 함수 구문에 관련 권한을 추가했습니다. application-stack.ts 파일에서 Api 구문의 타입 안전 integrations 속성에 직접 접근하여 이 작업을 수행합니다:

    stacks/application-stack.ts
    // 람다 함수에 Dynamo 호출 권한 부여
    databaseConstruct.shoppingListTable.grantReadData(
    api.integrations.getShoppingLists.handler,
    );
    [
    api.integrations.putShoppingList.handler,
    api.integrations.deleteShoppingList.handler,
    ].forEach((f) => databaseConstruct.shoppingListTable.grantWriteData(f));
  3. 인증된 사용자에게 API 호출 권한 부여

    PDK 애플리케이션의 myapi.ts에서는 인증된 사용자도 API 호출을 위한 IAM 권한을 부여받았습니다. application-stack.ts에서 동등한 작업을 수행합니다:

    stacks/application-stack.ts
    api.grantInvokeAccess(userIdentity.identityPool.authenticatedRole);

마지막으로 PDK 쇼핑 목록 애플리케이션의 packages/infra/src/constructs/websites/website.ts에 상응하는 packages/common/constructs/src/app/static-websites/website.tsWebsite 구문을 application-stack.ts에 추가합니다.

import { Website } from "../constructs/websites/website";
import { Website } from ':shopping-list/common-constructs';
...
new Website(this, "Website", {
userIdentity,
myapi,
});
new Website(this, 'Website');

여기서 identity나 API를 웹사이트에 전달하지 않습니다 - Nx Plugin for AWS가 제공하는 각 구문에서 런타임 구성을 관리하며, UserIdentityApi는 필요한 값을 등록하고 Website는 정적 웹사이트의 /runtime-config.json에 배포합니다.

이제 코드베이스의 모든 관련 부분을 새 프로젝트로 마이그레이션했으므로 프로젝트를 빌드합니다.

Terminal window
pnpm nx run-many --target build

이제 완전히 마이그레이션된 코드베이스를 확보했으므로 배포를 진행할 수 있습니다. 이 시점에서 두 가지 경로를 선택할 수 있습니다.

완전히 새로운 리소스 사용 (간단한 방법)

섹션 제목: “완전히 새로운 리소스 사용 (간단한 방법)”

가장 간단한 접근 방식은 이 애플리케이션을 완전히 새로운 것으로 취급하는 것입니다. 즉, 새로운 DynamoDB 테이블과 Cognito 사용자 풀을 “처음부터 다시 시작”하여 모든 사용자와 그들의 쇼핑 목록을 잃게 됩니다. 이 방법을 사용하려면 다음을 수행하세요:

  1. shopping_list라는 이름의 DynamoDB 테이블 삭제

  2. 새로운 애플리케이션 배포:

    Terminal window
    pnpm nx deploy infra shopping-list-infra-sandbox/*

🎉 완료되었습니다! 🎉

기존 상태 유지 리소스 마이그레이션 (다운타임 없음, 복잡한 방법)

섹션 제목: “기존 상태 유지 리소스 마이그레이션 (다운타임 없음, 복잡한 방법)”

실제로는 기존 AWS 리소스를 새로운 코드베이스에서 관리하도록 마이그레이션하면서 고객에게 다운타임이 발생하지 않도록 하는 것이 더 현실적일 것입니다.

쇼핑 목록 애플리케이션의 경우 중요한 상태 유지 리소스는 사용자의 쇼핑 목록을 포함하는 DynamoDB 테이블과 등록된 모든 사용자 정보를 포함하는 Cognito 사용자 풀입니다. 상위 수준 계획은 이 두 가지 핵심 리소스를 유지하고 새로운 스택에서 관리되도록 이동시킨 다음, DNS를 업데이트하여 새로운 웹사이트(및 고객에게 노출된 경우 API)로 트래픽을 전환하는 것입니다.

  1. 유지하려는 기존 리소스를 참조하도록 새 애플리케이션 업데이트

    쇼핑 목록 애플리케이션의 경우 DynamoDB 테이블에 대해 다음을 수행합니다.

    constructs/database.ts
    this.shoppingListTable = new Table(this, 'ShoppingList', {
    ...
    this.shoppingListTable = Table.fromTableName(
    this,
    'ShoppingList',
    'shopping_list',
    );

    Cognito 사용자 풀의 경우:

    packages/common/constructs/src/core/user-identity.ts
    this.userPool = this.createUserPool();
    this.userPool = UserPool.fromUserPoolId(
    this,
    'UserPool',
    '<your-user-pool-id>',
    );
  2. 새 애플리케이션 빌드 및 배포:

    Terminal window
    pnpm nx run-many --target build
    Terminal window
    pnpm nx deploy infra shopping-list-infra-sandbox/*

    이제 기존 리소스를 참조하는 새 애플리케이션이 구축되었지만 아직 트래픽을 수신하지 않습니다.

  3. 전체 통합 테스트 수행: 새 애플리케이션이 예상대로 작동하는지 확인합니다. 쇼핑 목록 애플리케이션의 경우 웹사이트를 로드하고 로그인, 쇼핑 목록 생성/조회/수정/삭제가 가능한지 확인합니다.

  4. 새 애플리케이션에서 기존 리소스 참조 변경 사항을 되돌리되, 아직 배포하지 마세요.

    constructs/database.ts
    this.shoppingListTable = new Table(this, 'ShoppingList', {
    ...
    this.shoppingListTable = Table.fromTableName(
    this,
    'ShoppingList',
    'shopping_list',
    );

    Cognito 사용자 풀의 경우:

    packages/common/constructs/src/core/user-identity.ts
    this.userPool = this.createUserPool();
    this.userPool = UserPool.fromUserPoolId(
    this,
    'UserPool',
    '<your-user-pool-id>',
    );

    이후 빌드 실행:

    Terminal window
    pnpm nx run-many --target build
  5. 새 애플리케이션의 packages/infra 폴더에서 cdk import를 사용하여 가져올 리소스 확인

    New Application
    cd packages/infra
    pnpm exec cdk import shopping-list-infra-sandbox/Application --force

    엔터를 눌러 프롬프트를 진행합니다. 리소스가 다른 스택에서 관리되므로 가져오기가 실패합니다(예상된 동작). 이 단계는 가져올 리소스를 확인하기 위한 것입니다. 다음과 같은 출력이 표시됩니다:

    Terminal window
    shopping-list-infra-sandbox/Application/ApplicationUserIdentity/UserPool/smsRole/Resource (AWS::IAM::Role): RoleName 입력(건너뛰려면 공백)
    shopping-list-infra-sandbox/Application/ApplicationUserIdentity/UserPool/Resource (AWS::Cognito::UserPool): UserPoolId 입력(건너뛰려면 공백)
    shopping-list-infra-sandbox/Application/Database/ShoppingList/Resource (AWS::DynamoDB::Table): TableName=shopping_list로 가져오기(y/n) y

    이는 실제로 3개의 리소스를 새 스택으로 가져와야 함을 나타냅니다.

  6. 이전 단계에서 발견된 리소스에 대해 RemovalPolicyRETAIN으로 설정하도록 기존 PDK 프로젝트 업데이트. 현재 작성 시점에는 User Pool과 DynamoDB 테이블에 대해 기본값이지만 위에서 발견한 SMS Role에 대해 업데이트가 필요합니다:

    application-stack.ts
    const userIdentity = new UserIdentity(this, `${id}UserIdentity`, {
    userPool,
    });
    const smsRole = userIdentity.userPool.node.findAll().filter(
    c => CfnResource.isCfnResource(c) &&
    c.node.path.includes('/smsRole/'))[0] as CfnResource;
    smsRole.applyRemovalPolicy(RemovalPolicy.RETAIN);
  7. 제거 정책이 적용되도록 PDK 프로젝트 배포

    PDK Application
    cd packages/infra
    npx projen deploy
  8. CloudFormation 콘솔에서 위 cdk import 단계에서 요청된 값 기록

    1. User Pool ID (예: us-west-2_XXXXX)
    2. SMS Role 이름 (예: infra-sandbox-UserIdentityUserPoolsmsRoleXXXXXX)
  9. PDK 프로젝트가 리소스를 생성하는 대신 기존 리소스를 참조하도록 업데이트

    constructs/database.ts
    this.shoppingListTable = new Table(this, 'ShoppingList', {
    ...
    this.shoppingListTable = Table.fromTableName(
    this,
    'ShoppingList',
    'shopping_list',
    );

    Cognito 사용자 풀의 경우:

    application-stack.ts
    const userPool = UserPool.fromUserPoolId(
    this,
    'UserPool',
    '<your-user-pool-id>',
    );
    const userIdentity = new UserIdentity(this, `${id}UserIdentity`, {
    // PDK 구성 요소는 IUserPool이 아닌 UserPool을 요구하지만 여전히 작동합니다!
    userPool: userPool as any,
    });
  10. PDK 프로젝트 재배포: 이제 리소스가 PDK 프로젝트의 CloudFormation 스택에서 관리되지 않습니다.

    PDK Application
    cd packages/infra
    npx projen deploy
  11. 리소스가 관리 해제되었으므로 새 애플리케이션에서 cdk import 실행하여 실제 가져오기 수행:

    New Application
    cd packages/infra
    pnpm exec cdk import shopping-list-infra-sandbox/Application --force

    프롬프트에 값을 입력하면 가져오기가 성공적으로 완료됩니다.

  12. 기존 리소스에 대한 변경 사항(이제 새 스택에서 관리됨)이 적용되도록 새 애플리케이션 재배포:

    Terminal window
    pnpm nx deploy infra shopping-list-infra-sandbox/*
  13. 새 애플리케이션에 대한 전체 테스트 재수행

  14. DNS 레코드를 업데이트하여 새 웹사이트(및 필요한 경우 API)를 가리키도록 설정

    Route53 가중치 기반 라우팅을 사용하여 점진적으로 트래픽을 전환할 것을 권장합니다. 처음에는 일부 요청만 새 애플리케이션으로 전달하고, 지표를 모니터링하면서 점차 비중을 높여 최종적으로 모든 트래픽이 새 애플리케이션으로 전환되도록 합니다.

    DNS가 없고 웹사이트/API에 자동 생성 도메인을 사용한 경우 CloudFront HTTP 오리진이나 API Gateway HTTP 통합을 통해 요청을 프록시할 수 있습니다.

  15. PDK 애플리케이션 지표를 모니터링하여 트래픽이 없는지 확인한 후 최종적으로 기존 CloudFormation 스택 삭제:

    Terminal window
    cd packages/infra
    npx projen destroy

상당히 복잡한 과정이었지만, 사용자를 새 애플리케이션으로 원활하게 마이그레이션하는 데 성공했습니다! 🎉🎉🎉

이제 PDK 대비 Nx Plugin for AWS의 새로운 이점을 누릴 수 있습니다:

  • 더 빠른 빌드
  • 로컬 API 개발 지원
  • 개발자 친화적인 코드베이스 (MCP 서버 사용해 보기!)
  • 더 직관적인 타입 세이프 클라이언트/서버 코드
  • 기타 다양한 개선 사항!

이 섹션은 위 예시 마이그레이션에서 다루지 않은 PDK 기능에 대한 지침을 제공합니다.

일반적으로 PDK에서 전환할 때는 PDK Monorepo와 유사한 Nx 워크스페이스로 프로젝트를 시작하는 것을 권장합니다. 또한 새로운 유형을 구축할 때는 우리의 제너레이터를 기본 요소로 사용하는 것을 추천합니다.

Terminal window
npx create-nx-workspace@21.4.1 my-project --pm=pnpm --preset=@aws/nx-plugin --ci=skip

CDK Graph는 연결된 CDK 리소스의 그래프를 구축하며 두 가지 플러그인을 제공합니다:

CDK Graph Diagram Plugin은 CDK 인프라에서 AWS 아키텍처 다이어그램을 생성합니다.

유사한 결정론적 접근 방식으로 CDK-Dia를 대안으로 고려해 볼 수 있습니다.

생성형 AI의 발전으로 많은 기초 모델들이 CDK 인프라에서 고품질 다이어그램 생성이 가능해졌습니다. AWS Diagram MCP Server 사용을 권장하며, 이 블로그 게시물에서 단계별 안내를 확인할 수 있습니다.

CDK Graph Threat Composer Plugin은 CDK 코드에서 Threat Composer 위협 모델의 초기 버전을 생성합니다.

이 플러그인은 예시 위협들을 포함한 기본 위협 모델을 필터링하여 스택에서 사용하는 리소스 기반으로 필터링하는 방식으로 동작합니다.

특정 예시 위협들을 활용하려면 기본 위협 모델을 복사/필터링하거나, 기초 모델이 유사한 모델을 생성할 때 컨텍스트로 사용할 수 있습니다.

AWS Arch는 CDK Graph용 CloudFormation 리소스와 관련 아키텍처 아이콘 간 매핑을 제공합니다.

아이콘 관련 리소스는 AWS Architecture Icons 페이지를 참조하세요. Diagrams도 코드로 다이어그램을 구축하는 방법을 제공합니다.

직접 사용하시는 경우 프로젝트를 포크(fork)하여 소유권을 가져가는 것을 고려해 보세요!

PDK는 PDKPipelineProject를 제공하여 CDK 인프라 프로젝트를 설정하고 CDK Pipelines 리소스를 래핑한 CDK 구문을 활용했습니다.

이것에서 마이그레이션하려면 CDK Pipelines 구문을 직접 사용할 수 있습니다. 그러나 실제로는 CDK Stages를 정의하고 적절한 스테이지에 대한 deploy 명령을 직접 실행하는 GitHub actions나 GitLab CI/CD와 같은 것을 사용하는 것이 더 간편할 수 있습니다.

PDK NagCDK Nag을 래핑하며 프로토타입 구축에 특화된 규칙 집합을 제공합니다.

PDK Nag에서 마이그레이션하려면 CDK Nag을 직접 사용하세요. 동일한 규칙 집합이 필요한 경우 여기 문서를 참고하여 자체 “팩”을 생성할 수 있습니다.

위의 예시 마이그레이션에서는 Type Safe API에서 가장 일반적으로 사용되는 컴포넌트들을 다루었지만, 아래에 다른 기능들의 마이그레이션 세부 사항을 안내합니다.

Nx Plugin for AWS는 Smithy로 모델링된 API는 지원하지만 OpenAPI로 직접 모델링된 API는 지원하지 않습니다. ts#smithy-api 생성기는 수정 가능한 좋은 시작점입니다. Smithy 대신 OpenAPI 스펙을 model 프로젝트의 src 폴더에 정의하고, 클라이언트/서버용 원하는 코드 생성 도구가 NPM에 없는 경우 build.Dockerfile을 수정하여 사용할 수 있습니다. 원하는 도구가 NPM에 있다면 Nx 워크스페이스에 개발 의존성으로 설치하고 Nx 빌드 대상에서 직접 호출할 수 있습니다.

OpenAPI로 모델링된 타입 세이프 백엔드의 경우 OpenAPI Generator 서버 생성기 중 하나를 고려할 수 있습니다. 이들은 AWS Lambda에 직접 생성되지는 않지만 AWS Lambda Web Adapter를 사용하여 많은 경우에 간극을 메울 수 있습니다.

TypeScript 클라이언트의 경우 ts#react-website 생성기api-connection 생성기ts#smithy-api 예시와 함께 사용하여 클라이언트 생성 및 웹사이트 통합 방식을 확인할 수 있습니다. 이는 open-api#ts-client 또는 open-api#ts-hooks 생성기를 호출하여 클라이언트를 생성하는 빌드 대상을 구성합니다. OpenAPI 스펙을 지정하여 이러한 생성기를 직접 사용할 수 있습니다.

다른 언어의 경우 OpenAPI Generator의 생성기 중 필요한 것이 있는지 확인할 수 있습니다.

ts#nx-generator 생성기를 사용하여 맞춤형 생성기를 구축할 수도 있습니다. OpenAPI에서 코드를 생성하는 방법에 대한 자세한 내용은 해당 생성기의 문서를 참조하세요. Nx Plugin for AWS의 템플릿을 시작점으로 사용할 수 있으며, PDK 코드베이스의 템플릿에서도 영감을 얻을 수 있습니다(Nx Plugin for AWS와 데이터 구조가 약간 다름에 유의).

TypeSpec의 경우 위의 OpenAPI 섹션이 동일하게 적용됩니다. ts#smithy-api를 생성한 후 Nx 워크스페이스에 TypeSpec 컴파일러와 OpenAPI 패키지를 설치하고, 모델 프로젝트의 compile 대상을 tsp compile을 실행하도록 업데이트하여 dist 디렉토리에 OpenAPI 스펙을 출력하도록 할 수 있습니다.

TypeSpec 모델에서 직접 작동하는 TypeSpec HTTP Server generator for JavaScript를 사용하는 것이 권장됩니다.

생성된 서버를 AWS Lambda에서 실행하기 위해 AWS Lambda Web Adapter를 사용할 수 있습니다.

또는 위의 OpenAPI 옵션 중 하나를 사용할 수도 있습니다.

TypeSpec은 Type Safe API가 지원하는 세 언어 모두에 대한 자체 코드 생성기를 보유하고 있습니다:

TypeSpec이 OpenAPI로 컴파일될 수 있으므로 위의 OpenAPI 섹션도 적용됩니다.

위 예시 마이그레이션에서는 ts#smithy-api 생성기 사용으로의 마이그레이션을 설명했습니다. 이 섹션에서는 Python 및 Java 백엔드와 클라이언트에 대한 옵션을 다룹니다.

Smithy Java 코드 생성기는 Java 서버 생성기와 생성된 Java 서버를 AWS Lambda에서 실행하기 위한 어댑터를 포함합니다.

Smithy는 Python용 서버 생성기가 없으므로 OpenAPI를 경유해야 합니다. 잠재적 옵션은 위의 OpenAPI로 모델링된 API 섹션을 참조하세요.

Smithy Java 코드 생성기는 Java 클라이언트 생성기를 포함합니다.

Python 클라이언트는 Smithy Python을 확인할 수 있습니다.

TypeScript의 경우 Smithy TypeScript를 사용하거나, OpenAPI 경유 방식을 선택할 수 있습니다(ts#smithy-api에서는 TanStack Query 훅을 통해 tRPC, FastAPI 및 Smithy API 간 일관성을 위해 이 방식을 선택함).

Type Safe API는 여러 Smithy 기반 API에서 재사용 가능한 Smithy 모델을 포함하는 프로젝트를 구성하는 SmithyShapeLibraryProject Projen 프로젝트 유형을 제공했습니다.

이를 구현하는 가장 직관적인 방법은 다음과 같습니다:

  1. smithy#project 생성기로 shape 라이브러리 생성:

    1. 설치 Nx Console VSCode Plugin 아직 설치하지 않았다면
    2. VSCode에서 Nx 콘솔 열기
    3. 클릭 Generate (UI) "Common Nx Commands" 섹션에서
    4. 검색 @aws/nx-plugin - smithy#project
    5. 필수 매개변수 입력
      • 클릭 Generate

      serviceName 옵션에 임의의 이름 지정(나중에 service shape 제거 예정).

    6. src의 기본 모델을 원하는 shapes로 교체

    7. smithy-build.json에서 plugins 및 사용하지 않는 Maven 의존성 제거

    8. build.Dockerfile을 최소 빌드 단계로 교체:

      build.Dockerfile
      FROM public.ecr.aws/docker/library/node:24 AS builder
      # 출력 디렉토리
      RUN mkdir /out
      # Smithy CLI 설치
      # https://smithy.io/2.0/guides/smithy-cli/cli_installation.html
      WORKDIR /smithy
      ARG TARGETPLATFORM
      RUN if [ "$TARGETPLATFORM" = "linux/arm64" ]; then ARCH="aarch64"; else ARCH="x86_64"; fi && \
      mkdir -p smithy-install/smithy && \
      curl -L https://github.com/smithy-lang/smithy/releases/download/1.61.0/smithy-cli-linux-$ARCH.zip -o smithy-install/smithy-cli-linux-$ARCH.zip && \
      unzip -qo smithy-install/smithy-cli-linux-$ARCH.zip -d smithy-install && \
      mv smithy-install/smithy-cli-linux-$ARCH/* smithy-install/smithy
      RUN smithy-install/smithy/install
      # 프로젝트 파일 복사
      COPY smithy-build.json .
      COPY src src
      # Maven 캐시 마운트로 Smithy 빌드
      RUN --mount=type=cache,target=/root/.m2/repository,id=maven-cache \
      smithy build
      RUN cp -r build/* /out/
      # /out 디렉토리 익스포트
      FROM scratch AS export
      COPY --from=builder /out /

    서비스 모델 프로젝트에서 다음 변경을 수행하여 shape 라이브러리 사용:

    1. project.jsoncompile 대상에 워크스페이스를 빌드 컨텍스트로 추가하고 shape 라이브러리의 build 대상에 의존성 추가

      project.json
      {
      "cache": true,
      "outputs": ["{workspaceRoot}/dist/{projectRoot}/build"],
      "executor": "nx:run-commands",
      "options": {
      "commands": [
      "rimraf dist/packages/api/model/build",
      "make-dir dist/packages/api/model/build",
      "docker build --build-context workspace=. -f packages/api/model/build.Dockerfile --target export --output type=local,dest=dist/packages/api/model/build packages/api/model"
      ],
      "parallel": false,
      "cwd": "{workspaceRoot}"
      },
      "dependsOn": ["@my-project/shapes:build"]
      }
    2. build.Dockerfile을 수정하여 shape 라이브러리의 src 디렉토리 복사(shape 라이브러리가 packages/shapes에 위치한다고 가정):

      build.Dockerfile
      # 프로젝트 파일 복사
      COPY smithy-build.json .
      COPY src src
      COPY --from=workspace packages/shapes/src shapes
    3. smithy-build.json에 shapes 디렉토리를 sources에 추가:

      smithy-build.json
      {
      "version": "1.0",
      "sources": ["src/", "shapes/"],
      "plugins": {
      ...
      }

    Type Safe API는 다음 기본 인터셉터를 제공했습니다:

    • Powertools for AWS Lambda를 사용한 로깅, 추적, 메트릭 인터셉터
    • 처리되지 않은 예외를 다루는 try-catch 인터셉터
    • CORS 헤더 반환을 위한 CORS 인터셉터

    ts#smithy-api 생성기는 Middy를 사용하여 Powertools for AWS Lambda로 로깅, 추적, 메트릭을 계측합니다. try-catch 인터셉터 동작은 Smithy TypeScript SSDK에 내장되어 있으며, CORS 헤더는 handler.ts에 추가됩니다.

    모든 언어에서 로깅, 추적, 메트릭 인터셉터를 위해 Powertools for AWS Lambda를 직접 사용하세요.

    맞춤형 인터셉터 마이그레이션을 위해 다음 라이브러리 사용을 권장합니다:

    Type Safe API는 Redocly CLI를 사용한 문서 생성을 제공했습니다. 위에서 마이그레이션한 프로젝트에 쉽게 추가할 수 있습니다.

    1. Redocly CLI 설치

      Terminal window
      pnpm add -Dw @redocly/cli
    2. redocly build-docs를 사용하여 model 프로젝트에 문서 생성 대상 추가:

      model/project.json
      {
      ...
      "documentation": {
      "cache": true,
      "outputs": ["{workspaceRoot}/dist/{projectRoot}/documentation"],
      "executor": "nx:run-commands",
      "options": {
      "command": "redocly build-docs dist/packages/api/model/build/openapi/openapi.json --output=dist/packages/api/model/documentation/index.html",
      "cwd": "{workspaceRoot}"
      },
      "dependsOn": ["compile"]
      }
      }

    OpenAPI Generator 문서 생성기도 고려할 수 있습니다.

    Type Safe API는 생성된 인프라 패키지 내에 모의 구현을 생성했습니다.

    JSON 스키마 기반 모의 데이터 생성에 JSON Schema Faker로 전환할 수 있습니다. 이는 OpenAPI 스펙에서 직접 작동하며 CLImodel 프로젝트 빌드의 일부로 실행할 수 있습니다.

    생성된 metadata.gen.ts를 기반으로 JSON Schema Faker의 출력 JSON 파일을 읽고 적절한 API Gateway MockIntegration을 반환하도록 CDK 인프라를 업데이트할 수 있습니다(ts#smithy-api 생성기 사용 가정).

    Type Safe API는 백엔드에 다양한 언어를 혼합하여 구현하는 것을 지원했습니다. CDK에서 API 구성을 인스턴스화할 때 통합에 “오버라이드”를 제공하여 동일하게 구현할 수 있습니다:

    application-stack.ts
    const pythonLambdaHandler = new Function(this, 'PythonImplementation', {
    runtime: Runtime.PYTHON_3_12,
    ...
    });
    new MyApi(this, 'MyApi', {
    integrations: Api.defaultIntegrations(this)
    .withOverrides({
    echo: {
    integration: new LambdaIntegration(pythonLambdaHandler),
    handler: pythonLambdaHandler,
    },
    })
    .build(),
    });

    ts#smithy-api 및 TypeScript 서버 SDK를 사용하는 경우 서비스/라우터에 “스텁”을 생성해야 합니다:

    service.ts
    export const Service: ApiService<ServiceContext> = {
    ...
    Echo: () => { throw new Error(`Not Implemented`); },
    };

    Type Safe API는 SpecRestApi를 사용하여 OpenAPI 스펙 기반의 기본 API Gateway 요청 본문 검증을 추가했습니다.

    ts#smithy-api 생성기를 사용하면 검증은 서버 SDK 자체에서 수행됩니다. 대부분의 서버 생성기에서 동일합니다.

    네이티브 API Gateway 검증을 구현하려면 packages/common/constructs/src/core/api/rest-api.ts를 수정하여 OpenAPI 스펙에서 각 작업의 요청 본문에 대한 JSON 스키마를 읽도록 할 수 있습니다.

    Type Safe API의 모델 기반 API 개발을 사용한 API Gateway 및 Lambda 기반 WebSocket API에 대한 직관적인 마이그레이션 경로는 아쉽게도 없습니다. 하지만 이 섹션에서는 몇 가지 아이디어를 제공합니다.

    비동기 API 처리에 특화된 AsyncAPI를 OpenAPI나 TypeSpec 대신 사용해 볼 수 있습니다. AsyncAPI NodeJS 템플릿ECS에서 호스팅할 수 있는 Node WebSocket 백엔드를 생성할 수 있습니다.

    인프라에 AppSync 이벤트Powertools를 고려해 볼 수 있습니다. 이 블로그 포스트가 도움이 될 수 있습니다!

    AppSync의 WebSocket을 통한 GraphQL API 사용도 옵션입니다. 이에 대한 GitHub 이슈에 관심을 표시할 수 있으며, AppSync 개발자 가이드에서 샘플 프로젝트 링크를 확인하세요.

    Type Safe API와 동일한 벤더 확장을 해석하는 맞춤형 코드 생성기를 구축할 수도 있습니다. OpenAPI 기반 코드 생성기 구축에 대한 자세한 내용은 OpenAPI로 모델링된 API 섹션을 참조하세요. API Gateway WebSocket API Lambda 핸들러용 템플릿은 여기에서, 클라이언트는 여기에서 확인할 수 있습니다.

    ts#trpc-api 생성기로 마이그레이션하여 tRPC를 사용할 수도 있습니다. 현재 구독/스트리밍 지원은 없지만 필요 시 GitHub 이슈에 관심을 표시해 주세요.

    Smithy는 프로토콜 독립적이지만 아직 WebSocket 프로토콜을 지원하지 않습니다. 관련 GitHub 이슈를 참조하세요.

    현재 PDK에서 지원하는 Python 및 Java로 작성된 CDK 인프라는 Nx Plugin for AWS에서 아직 지원하지 않습니다.

    권장하는 접근 방식은 CDK 인프라를 TypeScript로 마이그레이션하거나, 저희 제너레이터를 사용하여 공통 구문 패키지를 원하는 언어로 마이그레이션하는 것입니다. 예를 들어 Amazon Q CLI와 같은 Generative AI를 사용하여 이러한 마이그레이션을 가속화할 수 있습니다. AI 에이전트를 통해 CloudFormation 템플릿이 동일하게 생성될 때까지 마이그레이션을 반복 수행할 수 있습니다.

    이 내용은 Python 또는 Java로 생성된 Type Safe API의 인프라에도 동일하게 적용됩니다. 공통 구문 패키지의 일반적인 rest-api.ts 구문을 변환하고 대상 언어에 맞는 간단한 메타데이터 생성기를 직접 구현할 수 있습니다(OpenAPI로 모델링된 API 섹션 참조).

    CDK 코드를 추가할 기본 Python 프로젝트에는 py#project 제너레이터를 사용할 수 있습니다(cdk.json 파일을 이동하고 관련 타겟을 추가). Java 프로젝트의 경우 Nx의 @nx/gradle 플러그인을, Maven 프로젝트에는 @jnxplus/nx-maven을 사용할 수 있습니다.

    PDK는 Projen을 기반으로 구축되었습니다. Projen과 Nx Generators는 근본적인 차이점을 가지고 있어 기술적으로 결합이 가능하지만 이는 일반적으로 안티패턴으로 간주됩니다. Projen은 프로젝트 파일을 코드로 관리하여 직접 수정할 수 없도록 하는 반면, Nx generators는 프로젝트 파일을 한 번 제공한 후 자유롭게 코드를 수정할 수 있도록 합니다.

    Projen을 계속 사용하려는 경우 원하는 Projen 프로젝트 유형을 직접 구현할 수 있습니다. Nx Plugin for AWS의 패턴을 따르려면 저희 제네레이터를 실행하거나 GitHub에서 소스 코드를 확인하여 원하는 프로젝트 유형이 어떻게 구성되는지 파악한 후, Projen의 기본 요소를 사용하여 관련 부분을 구현하면 됩니다.

    AWS MCP 서버용 Nx 플러그인 소개

    소프트웨어 개발 분야가 빠르게 진화하는 가운데, AI 어시스턴트는 코딩 여정에서 귀중한 협력자로 자리잡았습니다. 많은 개발자들이 “바이브 코딩(vibe-coding)“이라 부르는 인간의 창의성과 AI 지원 간의 협업 방식을 받아들였습니다. 모든 신흥 관행이 그렇듯, 이는 흥미로운 장점과 주목할 만한 과제를 동시에 안고 있습니다. 본 게시물에서는 AWS 제품 및 서비스 작업 시 AI 지원 개발 경험을 향상시키는 Nx Plugin for AWS MCP Server를 소개합니다.

    AI 어시스턴트와 협업하여 소프트웨어를 구축하는 관행인 바이브 코딩은 많은 조직의 소프트웨어 개발 접근 방식을 변화시켰습니다. 사용자가 구축하고자 하는 것을 설명하면 AI 어시스턴트가 코드 및 테스트 작성, 빌드 명령 실행, 협업적 반복을 통해 비전을 실현하도록 도와줍니다.

    이 협업적 접근 방식은 개발 주기를 크게 단축시켰습니다. 이전에는 수동으로 작성하는 데 수시간이 걸리던 복잡한 구현을 종종 수분 내에 완료할 수 있게 되었습니다.

    장점에도 불구하고 바이브 코딩은 작업 흐름을 방해하고 좌절감을 유발할 수 있는 함정이 존재합니다. AI 도구는 프로젝트 전반에 걸쳐 일관성 없는 패턴을 생성할 수 있으며, 이는 향후 유지 관리 문제로 이어질 수 있습니다. 구체적인 지침이 없을 경우 AI는 경험 많은 개발자들이 당연히 포함시킬 AWS 특화 모범 사례나 보안 고려 사항을 놓칠 수 있습니다.

    명확한 프로젝트 구조가 없으면 AI가 생성한 코드는 체계를 잃고 유지보수가 어려워질 수 있습니다. AI는 기존에 해결책이 존재하는 문제에 대해 불필요하게 커스텀 구현을 생성할 수도 있습니다.

    이러한 과제는 특히 단일 프레임워크 범위를 벗어나 다양한 AWS 서비스를 연동하여 작업할 때 기술 부채, 보안 취약점, 좌절감으로 이어질 수 있습니다.

    AWS용 Nx 플러그인은 Nx 모노레포 도구를 사용해 AWS 애플리케이션을 구축하기 위한 구조화된 기반을 제공합니다. 백지 상태에서 시작하는 대신, 이 플러그인은 프로젝트 조직을 위한 일관된 프레임워크를 제공합니다.

    본 플러그인은 일반적인 프로젝트 유형에 대한 생성기를 통해 일관된 프로젝트 스캐폴딩을 보장하며 코드베이스 전반의 구조적 통합성을 유지합니다. AWS 모범 사례를 따르는 사전 구성된 템플릿을 포함하여 개발자들이 일반적인 함정과 보안 문제를 피할 수 있도록 돕습니다. 통합 도구는 AWS 애플리케이션의 빌드, 테스트, 배포를 위한 내장 명령어와 로컬 개발 서버를 통해 개발 워크플로우를 간소화합니다. 또한 복잡한 프로젝트 관리를 단순화하기 위해 Nx의 강력한 의존성 관리 시스템을 활용합니다.

    이러한 구조를 제공함으로써 AWS용 Nx 플러그인은 AI 어시스턴트가 작업할 명확한 프레임워크를 마련해 줍니다. AI 어시스턴트가 새로운 패턴을 창조하는 대신 확립된 컨벤션을 따르도록 하여 더 일관적이고 유지보수 가능한 코드베이스를 생성할 수 있습니다.

    모델 컨텍스트 프로토콜(Model Context Protocol, MCP)은 AI 어시스턴트가 외부 도구 및 리소스와 상호작용할 수 있도록 하는 개방형 표준입니다. AWS용 Nx 플러그인 MCP 서버는 AWS 개발에 특화된 전문 지식으로 AI 어시스턴트의 기능을 확장합니다.

    MCP 서버는 AWS 개발 관련 모범 사례, 사용 가능한 프로젝트 구조, 구현 패턴에 대한 컨텍스트 정보를 제공합니다. AI 도구가 작업 공간을 생성하고 일반적인 프로젝트 유형을 스캐폴딩하기 위한 생성기를 실행할 수 있도록 지원합니다. 이러한 컨텍스트 인식을 통해 AI는 확립된 패턴에 부합하고 일반적인 함정을 피하는 더욱 정보화된 제안을 할 수 있습니다.

    모범 사례와 일치하지 않거나 존재하지 않는 기능을 참조할 수 있는 코드를 생성하는 대신, AI 어시스턴트는 MCP 서버를 활용하여 프로젝트의 기반을 마련할 수 있습니다. 결과적으로 핵심 컴포넌트에 대한 견고한 기반에서 시작하여 비즈니스 로직을 채우기 위해 AI를 활용할 수 있는 더욱 결정적이고 신뢰할 수 있는 개발 경험을 얻을 수 있습니다.

    구조화되고 신뢰할 수 있는 AI 지원 AWS 개발을 탐구하고 싶다면 Nx Plugin for AWS MCP Server를 시도해 보세요. 다음 MCP 서버 구성으로 선호하는 AI 어시스턴트(Amazon Q Developer, Cline, Claude Code 등)에 설정할 수 있습니다:

    {
    "mcpServers": {
    "aws-nx-mcp": {
    "command": "npx",
    "args": ["-y", "-p", "@aws/nx-plugin", "aws-nx-mcp"]
    }
    }
    }

    자세한 안내는 AI와 함께 구축하기 가이드를 참조하세요.

    @aws/nx-plugin에 오신 것을 환영합니다

    자, 시작합니다! 🚀

    AWS용 Nx 플러그인은 Nx 기반의 플러그인으로 AWS에서 풀스택 애플리케이션을 구축하고 배포하는 과정을 단순화하는 툴킷을 제공합니다. 개발자에게 애플리케이션 및 IaC 코드를 위한 사전 구성된 템플릿을 제공하여 설정 및 구성에 소요되는 시간을 크게 줄여줍니다. 본 플러그인은 AWS 서비스 통합의 복잡성을 처리하면서도 사용자 정의를 위한 유연성을 유지합니다.

    사용자는 사용 가능한 생성기 목록에서 원하는 컴포넌트를 선택하고 구성 옵션을 제공한 후 @aws/nx-plugin이 필요한 스타터 코드를 생성하도록 할 수 있습니다. 이 툴킷에는 API, 웹사이트, 인프라를 생성하는 생성기부터 프론트엔드와 백엔드를 통합(기존 파일을 AST 변환을 통해 업데이트하는 기능 포함!)하고 타입 안전 클라이언트를 구현하는 고급 기능까지 다양한 생성기가 포함되어 있습니다.

    생성기

    더 알아보려면 플러그인의 모든 주요 컴포넌트를 다루는 던전 어드벤처 튜토리얼을 시작해 보세요. 이를 통해 플러그인 사용 방법을 효과적으로 익힐 수 있습니다.

    여러분의 피드백을 기다립니다. 언제든지 토론 게시이슈 등록을 통해 의견을 공유해 주세요!

    사용해 보세요!