Bỏ qua để đến nội dung

Blog

Di chuyển từ AWS PDK

Hướng dẫn này sẽ đưa bạn qua một ví dụ di chuyển dự án AWS PDK sang Nx Plugin for AWS, cũng như cung cấp hướng dẫn chung về chủ đề này.

Di chuyển sang Nx Plugin for AWS mang lại các lợi ích sau so với PDK:

  • Build nhanh hơn
  • Dễ sử dụng hơn (UI và CLI)
  • Thân thiện với vibe-coding (thử MCP server của chúng tôi!)
  • Công nghệ hiện đại hơn
  • Phát triển API và website cục bộ
  • Kiểm soát nhiều hơn (sửa đổi các file được cung cấp để phù hợp với trường hợp sử dụng của bạn)
  • Và nhiều hơn nữa!

Ví dụ Di chuyển: Ứng dụng Danh sách Mua sắm

Phần tiêu đề “Ví dụ Di chuyển: Ứng dụng Danh sách Mua sắm”

Trong hướng dẫn này, chúng ta sẽ sử dụng Ứng dụng Danh sách Mua sắm từ PDK Tutorial làm dự án mục tiêu để di chuyển. Làm theo các bước trong hướng dẫn đó để tạo dự án mục tiêu nếu bạn muốn tự làm theo.

Ứng dụng danh sách mua sắm bao gồm các loại dự án PDK sau:

  • MonorepoTsProject
  • TypeSafeApiProject
  • CloudscapeReactTsWebsiteProject
  • InfrastructureTsProject

Để bắt đầu, chúng ta sẽ tạo một workspace mới cho dự án mới của chúng ta. Mặc dù cực đoan hơn so với di chuyển tại chỗ, cách tiếp cận này mang lại cho chúng ta kết quả cuối cùng sạch sẽ nhất. Tạo một Nx workspace tương đương với việc sử dụng MonorepoTsProject của PDK:

Terminal window
pnpm create @aws/nx-workspace@1.0.0-rc.47 shopping-list --iac=cdk

Mở thư mục shopping-list mà lệnh này tạo ra trong IDE yêu thích của bạn.

TypeSafeApiProject được sử dụng trong ứng dụng danh sách mua sắm đã sử dụng:

  • Smithy làm ngôn ngữ mô hình hóa
  • TypeScript để triển khai các thao tác
  • Tạo hook TypeScript để tích hợp với trang web react

Do đó, chúng ta có thể sử dụng generator ts#smithy-api để cung cấp chức năng tương đương.

Chạy generator ts#api với framework được đặt thành smithy để thiết lập dự án api của bạn trong packages/api:

Terminal window
pnpm nx g @aws/nx-plugin:ts#api --name=api --framework=smithy --namespace=com.aws --auth=iam --no-interactive
Bạn cũng có thể thực hiện chạy thử để xem những tệp nào sẽ bị thay đổi
Terminal window
pnpm nx g @aws/nx-plugin:ts#api --name=api --framework=smithy --namespace=com.aws --auth=iam --no-interactive --dry-run

Bạn sẽ nhận thấy điều này tạo ra một dự án model, cũng như một dự án backend. Dự án model chứa mô hình Smithy của bạn, và backend chứa triển khai máy chủ của bạn.

Backend sử dụng Smithy Server Generator for TypeScript. Chúng ta sẽ khám phá điều này chi tiết hơn bên dưới.

Bây giờ chúng ta đã có cấu trúc cơ bản cho dự án Smithy API, chúng ta có thể di chuyển mô hình:

  1. Xóa các tệp Smithy ví dụ được tạo trong packages/api/model/src

  2. Sao chép mô hình của bạn từ thư mục packages/api/model/src/main/smithy của dự án PDK vào thư mục packages/api/model/src của dự án mới.

  3. Cập nhật tên dịch vụ và namespace trong smithy-build.json để khớp với ứng dụng PDK:

    smithy-build.json
    "plugins": {
    "openapi": {
    "service": "com.aws#MyApi",
    ...
  4. Cập nhật dịch vụ trong main.smithy để thêm lỗi ValidationException, điều này là bắt buộc khi sử dụng Smithy TypeScript Server SDK.

    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. Thêm tệp extensions.smithy vào packages/api/model/src nơi chúng ta sẽ định nghĩa một trait cung cấp thông tin phân trang cho client được tạo:

    extensions.smithy
    $version: "2"
    namespace com.aws
    use smithy.openapi#specificationExtension
    @trait
    @specificationExtension(as: "x-cursor")
    structure cursor {
    inputToken: String
    enabled: Boolean
    }
  6. Thêm trait @cursor mới vào thao tác GetShoppingLists trong get-shopping-lists.smithy:

    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
    }

    Bất kỳ thao tác @paginated nào cũng nên sử dụng @cursor nếu bạn đang sử dụng generator client được cung cấp bởi Nx Plugin for AWS (thông qua generator api-connection).

  7. Cuối cùng, xóa trait @handler khỏi tất cả các thao tác vì điều này không được hỗ trợ bởi Nx Plugin for AWS. Sử dụng ts#smithy-api, chúng ta không cần các cấu trúc CDK hàm lambda được tạo tự động và các mục tiêu đóng gói được tạo bởi trait này, vì chúng ta sử dụng một bundle duy nhất cho tất cả các hàm lambda.

Tại thời điểm này, hãy chạy một bản build để kiểm tra các thay đổi mô hình của chúng ta và đảm bảo chúng ta có một số mã máy chủ được tạo để làm việc. Sẽ có một số lỗi trong dự án backend (@shopping-list/api) nhưng chúng ta sẽ giải quyết chúng tiếp theo.

Terminal window
pnpm nx run-many --target build

Bạn có thể coi dự án api/backend tương đương với dự án api/handlers/typescript của Type Safe API.

Một trong những khác biệt chính giữa Type Safe API và generator ts#smithy-api là các handler được triển khai bằng Smithy Server Generator for TypeScript, thay vì các wrapper handler được tạo riêng của Type Safe API (được tìm thấy trong dự án api/generated/typescript/runtime).

Các lambda handler của ứng dụng danh sách mua sắm phụ thuộc vào gói @aws-sdk/client-dynamodb, vì vậy hãy cài đặt nó vào dự án @shopping-list/api:

Terminal window
pnpm add @aws-sdk/client-dynamodb --filter api

Sau đó, hãy sao chép tệp handlers/src/dynamo-client.ts từ dự án PDK sang backend/src/operations để nó có sẵn cho các handler của chúng ta.

Generator ts#smithy-api tạo ra một thao tác Echo ví dụ. Vì chúng ta đã xóa điều này khỏi mô hình của mình, hãy xóa handler tương ứng trong backend/src/operations/echo.ts. Chúng ta sẽ đăng ký các thao tác đã di chuyển của mình trong service.ts bên dưới.

Để di chuyển các handler, bạn có thể làm theo các bước chung sau:

  1. Sao chép handler từ thư mục packages/api/handlers/typescript/src của dự án PDK sang thư mục packages/api/backend/src/operations của dự án mới.

  2. Xóa các import my-api-typescript-runtime và thay vào đó import loại thao tác từ TypeScript Server SDK được tạo, cũng như ServiceContext ví dụ:

    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. Xóa export wrapper handler

    export const handler = deleteShoppingListHandler(
    ...INTERCEPTORS,
    deleteShoppingList,
    );
  4. Cập nhật chữ ký cho handler thao tác của bạn để sử dụng SSDK:

    export const deleteShoppingList: DeleteShoppingListChainedHandlerFunction = async (request) => {
    export const DeleteShoppingList: DeleteShoppingListOperation<ServiceContext> = async (input, ctx) => {
  5. Thay thế việc sử dụng LoggingInterceptor bằng ctx.logger. (Cũng áp dụng cho các interceptor metrics và tracing):

    LoggingInterceptor.getLogger(request).info('...');
    ctx.logger.info('...');
  6. Cập nhật các tham chiếu đến tham số đầu vào. Vì SSDK cung cấp các loại khớp chính xác với mô hình Smithy của bạn (thay vì nhóm các tham số path/query/header riêng biệt với tham số body), hãy cập nhật bất kỳ tham chiếu đầu vào nào cho phù hợp:

    const shoppingListId = request.input.requestParameters.shoppingListId;
    const shoppingListId = input.shoppingListId;
  7. Xóa việc sử dụng Response. Thay vào đó, chúng ta chỉ trả về các đối tượng thuần túy trong SSDK.

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

    Chúng ta cũng không còn throw hoặc return Response, thay vào đó chúng ta throw các lỗi được tạo của 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. Cập nhật bất kỳ import nào để sử dụng cú pháp ESM, cụ thể là thêm phần mở rộng .js vào các import tương đối.

  9. Thêm thao tác vào 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';
    // Register operations to the service here
    export const Service: MyApiService<ServiceContext> = {
    PutShoppingList,
    GetShoppingLists,
    DeleteShoppingList,
    };
Nhấp vào đây để xem các ví dụ trước/sau đầy đủ cho ba thao tác danh sách mua sắm từ hướng dẫn

Chúng ta đã tạo dự án Smithy API với tên api ban đầu vì chúng ta muốn nó được thêm vào packages/api để nhất quán với dự án PDK. Vì Smithy API của chúng ta bây giờ định nghĩa service MyApi thay vì service Api, chúng ta cần cập nhật bất kỳ trường hợp nào của getApiServiceHandler bằng getMyApiServiceHandler.

Thực hiện thay đổi này trong 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);

Và trong 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);

Ngoài ra, cập nhật packages/api/backend/project.json và cập nhật metadata.apiName thành my-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]
},

Bây giờ chúng ta có thể build dự án để kiểm tra xem quá trình di chuyển đã hoạt động cho đến nay chưa:

Terminal window
pnpm nx run-many --target build

CloudscapeReactTsWebsiteProject được sử dụng trong ứng dụng danh sách mua sắm đã cấu hình một website React với CloudScape và xác thực Cognito được tích hợp sẵn.

Loại dự án này tận dụng create-react-app, hiện đã không còn được hỗ trợ. Để di chuyển website trong hướng dẫn này, chúng ta sẽ sử dụng generator ts#website, sử dụng các công nghệ hiện đại và được hỗ trợ hơn, cụ thể là Vite.

Là một phần của quá trình di chuyển, chúng ta cũng sẽ chuyển từ React Router được cấu hình sẵn của PDK sang TanStack Router, cung cấp thêm tính an toàn kiểu cho định tuyến website.

Chạy generator ts#website với framework được đặt thành react để thiết lập dự án website của bạn trong packages/website. Vì ứng dụng danh sách mua sắm được xây dựng với các component CloudScape, chúng ta cũng đặt ux thành cloudscape (mặc định là shadcn):

Terminal window
pnpm nx g @aws/nx-plugin:ts#website --name=website --framework=react --ux=cloudscape --no-interactive
Bạn cũng có thể thực hiện chạy thử để xem những tệp nào sẽ bị thay đổi
Terminal window
pnpm nx g @aws/nx-plugin:ts#website --name=website --framework=react --ux=cloudscape --no-interactive --dry-run

Generator React website ở trên không tích hợp sẵn xác thực cognito như CloudscapeReactTsWebsiteProject, thay vào đó nó được thêm một cách rõ ràng thông qua generator ts#website#auth.

Terminal window
pnpm nx g @aws/nx-plugin:ts#website#auth --project=website --cognitoDomain=shopping-list --no-interactive
Bạn cũng có thể thực hiện chạy thử để xem những tệp nào sẽ bị thay đổi
Terminal window
pnpm nx g @aws/nx-plugin:ts#website#auth --project=website --cognitoDomain=shopping-list --no-interactive --dry-run

Điều này thêm các component React quản lý các chuyển hướng thích hợp để đảm bảo người dùng đăng nhập bằng giao diện Cognito hosted UI. Điều này cũng thêm một construct CDK để triển khai các tài nguyên Cognito trong packages/common/constructs, được gọi là UserIdentity.

Trong PDK, bạn có thể truyền các dự án Projen được cung cấp cho nhau để kích hoạt mã tích hợp được tạo ra. Điều này đã được sử dụng trong ứng dụng danh sách mua sắm để cấu hình website có thể tích hợp với API.

Với Nx Plugin for AWS, tích hợp API được hỗ trợ thông qua generator connection. Tiếp theo, chúng ta sử dụng generator này để website của chúng ta có thể gọi Smithy API của chúng ta:

Terminal window
pnpm nx g @aws/nx-plugin:connection --sourceProject=website --targetProject=api --no-interactive
Bạn cũng có thể thực hiện chạy thử để xem những tệp nào sẽ bị thay đổi
Terminal window
pnpm nx g @aws/nx-plugin:connection --sourceProject=website --targetProject=api --no-interactive --dry-run

Điều này tạo ra các provider client cần thiết và các target build để website của bạn có thể gọi API của bạn thông qua một client TypeScript được tạo ra.

CloudscapeReactTsWebsiteProject tự động bao gồm một dependency trên @aws-northstar/ui được sử dụng trong ứng dụng danh sách mua sắm của chúng ta, vì vậy chúng ta thêm nó vào dự án @shopping-list/website:

Terminal window
pnpm add @aws-northstar/ui --filter website

@aws-northstar/ui tích hợp một component code editor phụ thuộc vào ace-builds, sử dụng một import đặc thù của webpack mà Vite không thể phân giải. Vì ứng dụng danh sách mua sắm của chúng ta không sử dụng component này, chúng ta loại trừ nó khỏi bundle bằng cách thêm nó vào cấu hình external trong các tùy chọn build hiện có trong packages/website/vite.config.mts:

packages/website/vite.config.mts
build: {
outDir: '../../dist/packages/website/bundle',
emptyOutDir: true,
reportCompressedSize: true,
commonjsOptions: {
transformMixedEsModules: true,
},
rollupOptions: {
external: ['ace-builds/webpack-resolver'],
},
},

Ứng dụng danh sách mua sắm có một component gọi là CreateItem, và hai page, ShoppingListShoppingLists. Chúng ta sẽ di chuyển chúng sang website mới, thực hiện một số điều chỉnh vì chúng ta đang sử dụng TanStack Router và trình tạo mã client TypeScript của Nx Plugin for AWS.

  1. Sao chép packages/website/src/components/CreateItem/index.tsx từ dự án PDK vào chính xác cùng vị trí trong dự án mới.

  2. Sao chép packages/website/src/pages/ShoppingLists/index.tsx sang packages/website/src/routes/index.tsx, vì ShoppingLists là trang chủ của chúng ta và chúng ta sử dụng định tuyến dựa trên file với TanStack router.

  3. Sao chép packages/website/src/pages/ShoppingList/index.tsx sang packages/website/src/routes/$shoppingListId.tsx, vì ShoppingList là trang chúng ta muốn hiển thị trên route /:shoppingListId.

Lưu ý rằng bây giờ bạn sẽ có một số lỗi build hiển thị trong IDE của bạn, chúng ta sẽ cần thực hiện thêm một vài thay đổi để phù hợp với framework mới, được nêu dưới đây.

Di chuyển từ React Router sang TanStack Router

Phần tiêu đề “Di chuyển từ React Router sang TanStack Router”

Vì chúng ta đang sử dụng file-based routing, chúng ta có thể sử dụng máy chủ phát triển website cục bộ để quản lý việc tự động tạo cấu hình route.

Hãy khởi động máy chủ website cục bộ:

Terminal window
pnpm nx dev website

Bạn sẽ thấy một số lỗi, nhưng máy chủ website cục bộ sẽ khởi động trên cổng 4200, cũng như máy chủ Smithy API cục bộ trên cổng 3001.

Làm theo các bước dưới đây trong cả routes/index.tsxroutes/$shoppingListId.tsx để di chuyển sang TanStack Router:

  1. Thêm createFileRoute để đăng ký mỗi route:

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

    Sau khi bạn lưu file, bạn sẽ nhận thấy rằng các lỗi kiểu với lời gọi đến createFileRoute đã biến mất.

  2. Thay thế hook useNavigate.

    Cập nhật import:

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

    Cập nhật các lời gọi đến phương thức navigate (được trả về bởi useNavigate) để truyền vào các route an toàn kiểu:

    navigate(`/${cell.shoppingListId}`);
    navigate({
    to: '/$shoppingListId',
    params: { shoppingListId: cell.shoppingListId },
    });
  3. Thay thế hook useParams.

    Xóa import:

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

    Cập nhật các lời gọi đến useParams với hook được cung cấp bởi Route được tạo ở trên. Bây giờ chúng đã an toàn kiểu!

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

Vì các file route của chúng ta không được lồng sâu trong cây file như trong dự án PDK của chúng ta, chúng ta cần sửa import cho CreateItem trong cả routes/index.tsxroutes/$shoppingListId.tsx:

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

AppLayoutContext cũng được cung cấp ở một vị trí hơi khác trong dự án mới của chúng ta:

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

Di chuyển để sử dụng Generated TypeScript Client mới

Phần tiêu đề “Di chuyển để sử dụng Generated TypeScript Client mới”

Chúng ta đang gần hoàn thành rồi! Tiếp theo, chúng ta cần di chuyển để sử dụng client TypeScript được cung cấp bởi Nx Plugin for AWS, có một số cải tiến so với Type Safe API. Để đạt được điều này, hãy làm theo các bước dưới đây

  1. Import client và types được tạo mới thay vì cái cũ, ví dụ:

    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";

    Lưu ý rằng routes/$shoppingListId.tsx import type ShoppingList dưới dạng _ShoppingList - trong file đó chúng ta nên làm tương tự, nhưng lại import từ types.gen.

    Cũng lưu ý rằng chúng ta import các hook liên quan trực tiếp từ @tanstack/react-query, vì client được tạo ra cung cấp các phương thức để tạo options cho các hook TanStack query, thay vì các wrapper hook.

  2. Khởi tạo các hook TanStack Query mới, ví dụ:

    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. Xóa wrapper <operation>RequestContent cho các lời gọi đến các operation chấp nhận tham số trong request body:

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

Còn một vài lỗi cần sửa do sự khác biệt giữa TanStack Query v4 (được sử dụng bởi PDK) và v5 mà generator connection đã thêm:

  1. Thay thế isLoading bằng isPending cho các mutation, ví dụ:

    putShoppingList.isLoading
    putShoppingList.isPending
  2. Ứng dụng danh sách mua sắm đã sử dụng InfiniteQueryTable từ @aws-northstar/ui mong đợi một type từ TanStack Query v4. Điều này thực sự hoạt động với các infinite query từ v5, vì vậy chúng ta chỉ cần bỏ qua lỗi kiểu:

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

Bây giờ bạn có thể truy cập website cục bộ tại http://localhost:4200/

Website sẽ tải lên bây giờ khi mọi thứ đã được di chuyển! Vì cơ sở hạ tầng duy nhất mà ứng dụng danh sách mua sắm dựa vào ngoài API, Website và Identity là bảng DynamoDB - nếu bạn có một bảng DynamoDB có tên shopping_list trong vùng, và thông tin xác thực AWS cục bộ có thể truy cập nó, website sẽ hoạt động đầy đủ!

Nếu không, không sao, chúng ta sẽ di chuyển cơ sở hạ tầng tiếp theo.

Nhấp vào đây để xem ví dụ đầy đủ trước/sau cho hai trang danh sách mua sắm từ hướng dẫn

Dự án cuối cùng chúng ta cần di chuyển cho ứng dụng danh sách mua sắm là InfrastructureTsProject. Đây là một dự án TypeScript CDK, mà tương đương trong Nx Plugin for AWS là trình tạo ts#infra.

Cũng như các dự án Projen, PDK cũng cung cấp các construct CDK mà các dự án này phụ thuộc vào. Chúng ta sẽ di chuyển ứng dụng danh sách mua sắm khỏi các construct CDK này, thay vào đó sử dụng những construct được tạo bởi Nx Plugin for AWS.

Tạo một Dự án Cơ sở hạ tầng TypeScript CDK

Phần tiêu đề “Tạo một Dự án Cơ sở hạ tầng TypeScript CDK”

Chạy trình tạo ts#infra để thiết lập dự án cơ sở hạ tầng của bạn trong packages/infra:

Terminal window
pnpm nx g @aws/nx-plugin:ts#infra --name=infra --no-interactive
Bạn cũng có thể thực hiện chạy thử để xem những tệp nào sẽ bị thay đổi
Terminal window
pnpm nx g @aws/nx-plugin:ts#infra --name=infra --no-interactive --dry-run

Ứng dụng danh sách mua sắm PDK đã khởi tạo các construct sau trong stack ứng dụng CDK:

  • DatabaseConstruct cho bảng DynamoDB lưu trữ danh sách mua sắm
  • UserIdentity cho các tài nguyên Cognito, được import trực tiếp từ PDK
  • MyApi để triển khai Smithy API, sử dụng construct TypeScript CDK được tạo với các tích hợp type-safe, phụ thuộc vào construct CDK TypeSafeRestApi của PDK bên dưới.
  • Website để triển khai Website, bao bọc construct CDK StaticWebsite của PDK.

Tiếp theo, chúng ta sẽ di chuyển từng cái trong số này sang dự án mới.

Sao chép packages/infra/src/stacks/application-stack.ts từ ứng dụng danh sách mua sắm PDK đến chính xác cùng vị trí trong dự án mới của bạn. Bạn sẽ thấy một số lỗi TypeScript mà chúng ta sẽ giải quyết bên dưới.

Ứng dụng danh sách mua sắm PDK có một construct Database trong packages/src/constructs/database.ts. Sao chép nó đến chính xác cùng vị trí trong dự án mới của bạn.

Vì Nx Plugin for AWS sử dụng Checkov cho các bài kiểm tra bảo mật nghiêm ngặt hơn một chút so với PDK Nag, chúng ta cũng cần thêm một số suppression:

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',
);

Trong application-stack.ts, cập nhật import cho DatabaseConstruct để sử dụng cú pháp ESM:

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

Construct UserIdentity thường có thể được thay thế mà không cần thay đổi bằng cách điều chỉnh các import.

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

Lưu ý rằng các construct cơ bản được sử dụng bởi construct UserIdentity mới được cung cấp trực tiếp từ aws-cdk-lib, trong khi PDK sử dụng @aws-cdk/aws-cognito-identitypool-alpha.

Ứng dụng danh sách mua sắm PDK có một construct trong constructs/apis/myapi.ts khởi tạo một construct CDK mà Type Safe API tạo ra từ mô hình Smithy của bạn.

Cũng như construct này, vì dự án PDK sử dụng trait @handler, các construct CDK hàm lambda được tạo cũng được sinh ra.

Giống như Type Safe API, Nx Plugin for AWS cung cấp type-safety cho các tích hợp dựa trên mô hình Smithy của bạn, tuy nhiên nó được thực hiện theo cách đơn giản và linh hoạt hơn nhiều. Thay vì tạo toàn bộ construct CDK tại thời điểm build, chỉ có “metadata” tối thiểu được tạo ra, mà packages/common/constructs/src/app/apis/api.ts sử dụng theo cách chung. Bạn có thể tìm hiểu thêm về cách sử dụng construct trong hướng dẫn trình tạo ts#smithy-api.

Thực hiện các bước sau:

  1. Khởi tạo construct Api trong application-stack.ts

    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(),
    });

    Lưu ý ở đây chúng ta sử dụng Api.defaultIntegrations(this).build() - hành vi mặc định là tạo một hàm lambda cho mỗi operation trong API của chúng ta, đây là hành vi giống như chúng ta có trong myapi.ts.

  2. Cấp quyền cho các hàm lambda truy cập bảng DynamoDB.

    Trong ứng dụng danh sách mua sắm PDK, DatabaseConsruct được truyền vào MyApi, và nó quản lý việc thêm các quyền liên quan vào mỗi construct hàm được tạo. Chúng ta sẽ làm điều này trực tiếp trong file application-stack.ts bằng cách truy cập thuộc tính integrations type-safe của construct Api:

    stacks/application-stack.ts
    // Grant our lambda functions scoped access to call Dynamo
    databaseConstruct.shoppingListTable.grantReadData(
    api.integrations.getShoppingLists.handler,
    );
    [
    api.integrations.putShoppingList.handler,
    api.integrations.deleteShoppingList.handler,
    ].forEach((f) => databaseConstruct.shoppingListTable.grantWriteData(f));
  3. Cấp quyền cho người dùng đã xác thực để gọi API.

    Trong myapi.ts của ứng dụng PDK, người dùng đã xác thực cũng được cấp quyền IAM để gọi API. Chúng ta sẽ làm tương đương trong application-stack.ts:

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

Cuối cùng, chúng ta thêm construct Website từ packages/common/constructs/src/app/static-websites/website.ts vào application-stack.ts, vì đây là tương đương với packages/infra/src/constructs/websites/website.ts của ứng dụng danh sách mua sắm PDK.

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

Lưu ý rằng chúng ta không truyền identity hoặc API cho website - cấu hình runtime được quản lý trong mỗi construct được cung cấp bởi Nx Plugin for AWS, trong đó UserIdentityApi đăng ký các giá trị cần thiết, và Website quản lý việc triển khai nó đến /runtime-config.json trên trang web tĩnh của bạn.

Hãy build dự án bây giờ sau khi chúng ta đã di chuyển tất cả các phần liên quan của codebase sang dự án mới.

Terminal window
pnpm nx run-many --target build

Bây giờ chúng ta đã có codebase đã được di chuyển hoàn toàn, chúng ta có thể xem xét việc triển khai nó. Có hai hướng đi mà chúng ta có thể thực hiện tại thời điểm này.

Cách tiếp cận đơn giản nhất là coi đây là một ứng dụng hoàn toàn mới, có nghĩa là chúng ta sẽ “bắt đầu lại” với một bảng DynamoDB mới và Cognito User Pool mới - mất tất cả người dùng và danh sách mua sắm của họ. Với cách tiếp cận này, chỉ cần:

  1. Xóa bảng DynamoDB có tên shopping_list

  2. Triển khai ứng dụng mới:

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

🎉 Và chúng ta đã hoàn thành! 🎉

Di chuyển Tài nguyên Stateful Hiện có mà không có Downtime (Phức tạp hơn)

Phần tiêu đề “Di chuyển Tài nguyên Stateful Hiện có mà không có Downtime (Phức tạp hơn)”

Trong thực tế, nhiều khả năng bạn sẽ muốn di chuyển các tài nguyên AWS hiện có để chúng được quản lý bởi codebase mới, đồng thời tránh bất kỳ thời gian ngừng hoạt động nào cho khách hàng của bạn.

Đối với ứng dụng shopping list của chúng ta, các tài nguyên stateful mà chúng ta quan tâm là bảng DynamoDB chứa danh sách mua sắm của người dùng và User Pool chứa thông tin chi tiết của tất cả người dùng đã đăng ký. Kế hoạch tổng thể của chúng ta sẽ là giữ lại hai tài nguyên chính này và di chuyển chúng sao cho chúng được quản lý bởi stack mới của chúng ta, sau đó cập nhật DNS để trỏ đến website mới của chúng ta (và API nếu được expose cho khách hàng).

  1. Cập nhật ứng dụng mới của bạn để tham chiếu các tài nguyên hiện có mà bạn muốn giữ lại.

    Đối với ứng dụng shopping list, chúng ta làm điều này cho bảng DynamoDB

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

    Và cho Cognito User Pool

    packages/common/constructs/src/core/user-identity.ts
    this.userPool = this.createUserPool();
    this.userPool = UserPool.fromUserPoolId(
    this,
    'UserPool',
    '<your-user-pool-id>',
    );
  2. Build và triển khai ứng dụng mới:

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

    Bây giờ chúng ta có ứng dụng mới đã được thiết lập tham chiếu các tài nguyên hiện có, chưa nhận bất kỳ traffic nào.

  3. Thực hiện kiểm thử tích hợp đầy đủ để đảm bảo ứng dụng mới hoạt động như mong đợi. Đối với ứng dụng shopping list, tải website và kiểm tra bạn có thể đăng nhập và tạo, xem, chỉnh sửa và xóa danh sách mua sắm.

  4. Hoàn nguyên các thay đổi tham chiếu các tài nguyên hiện có trong ứng dụng mới của bạn, nhưng chưa triển khai chúng.

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

    Và cho Cognito User Pool

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

    Và sau đó chạy build

    Terminal window
    pnpm nx run-many --target build
  5. Sử dụng cdk import trong thư mục packages/infra của ứng dụng mới để xem các tài nguyên nào chúng ta sẽ được nhắc import.

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

    Bước qua các prompt bằng cách nhấn enter. Import sẽ thất bại vì các tài nguyên được quản lý bởi một stack khác - điều này là mong đợi, chúng ta chỉ thực hiện bước này để xác nhận các tài nguyên nào chúng ta sẽ cần giữ lại. Bạn sẽ thấy output như thế này:

    Terminal window
    shopping-list-infra-sandbox/Application/ApplicationUserIdentity/UserPool/smsRole/Resource (AWS::IAM::Role): enter RoleName (empty to skip)
    shopping-list-infra-sandbox/Application/ApplicationUserIdentity/UserPool/Resource (AWS::Cognito::UserPool): enter UserPoolId (empty to skip)
    shopping-list-infra-sandbox/Application/Database/ShoppingList/Resource (AWS::DynamoDB::Table): import with TableName=shopping_list (y/n) y

    Điều này cho chúng ta biết rằng thực sự có 3 tài nguyên mà chúng ta sẽ cần import vào stack mới của chúng ta.

  6. Cập nhật dự án PDK cũ của bạn để đặt RemovalPolicy thành RETAIN cho các tài nguyên được phát hiện từ bước trước. Tại thời điểm viết bài này, đây là mặc định cho cả User Pool và bảng DynamoDB, nhưng chúng ta cần cập nhật nó cho SMS Role mà chúng ta đã phát hiện ở trên:

    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. Triển khai dự án PDK của bạn để các removal policy được áp dụng

    PDK Application
    cd packages/infra
    npx projen deploy
  8. Xem console CloudFormation và ghi lại các giá trị mà bạn đã được nhắc trong bước cdk import ở trên

    1. User Pool ID, ví dụ us-west-2_XXXXX
    2. SMS Role Name, ví dụ infra-sandbox-UserIdentityUserPoolsmsRoleXXXXXX
  9. Cập nhật dự án PDK của bạn để tham chiếu các tài nguyên hiện có thay vì tạo chúng

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

    Và cho Cognito User Pool

    application-stack.ts
    const userPool = UserPool.fromUserPoolId(
    this,
    'UserPool',
    '<your-user-pool-id>',
    );
    const userIdentity = new UserIdentity(this, `${id}UserIdentity`, {
    // PDK construct accepts UserPool not IUserPool, but this still works!
    userPool: userPool as any,
    });
  10. Triển khai dự án PDK của bạn một lần nữa, điều này có nghĩa là các tài nguyên không còn được quản lý bởi CloudFormation stack của dự án PDK của chúng ta.

    PDK Application
    cd packages/infra
    npx projen deploy
  11. Bây giờ các tài nguyên không được quản lý, chúng ta có thể chạy cdk import trong ứng dụng mới của chúng ta để thực sự thực hiện import:

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

    Nhập các giá trị khi được nhắc, import sẽ hoàn thành thành công.

  12. Triển khai ứng dụng mới một lần nữa để đảm bảo rằng bất kỳ thay đổi nào đối với các tài nguyên hiện có này (hiện được quản lý bởi stack mới của bạn) được thực hiện:

    Terminal window
    pnpm nx deploy infra shopping-list-infra-sandbox/*
  13. Thực hiện kiểm thử đầy đủ ứng dụng mới của bạn một lần nữa

  14. Cập nhật các bản ghi DNS để trỏ đến Website mới của bạn (và API nếu cần).

    Chúng tôi khuyến nghị cách tiếp cận dần dần sử dụng Route53 Weighted Routing, theo đó một phần nhỏ các request được chuyển đến ứng dụng mới để bắt đầu. Khi bạn theo dõi các metric của mình, bạn có thể tăng trọng số cho ứng dụng mới cho đến khi không có traffic nào được gửi đến ứng dụng PDK cũ của bạn.

    Nếu bạn không có bất kỳ DNS nào và sử dụng các domain tự động tạo cho website và API, bạn luôn có thể xem xét việc proxy các request (ví dụ thông qua CloudFront HTTP origin hoặc API Gateway HTTP integration(s)).

  15. Theo dõi các metric của ứng dụng PDK để đảm bảo không có traffic, và cuối cùng hủy CloudFormation stack cũ:

    Terminal window
    cd packages/infra
    npx projen destroy

Điều đó phức tạp hơn một chút, nhưng chúng ta đã di chuyển thành công người dùng của mình một cách liền mạch sang ứng dụng mới! 🎉🎉🎉

Bây giờ chúng ta có những lợi ích mới của Nx Plugin for AWS so với PDK:

  • Build nhanh hơn
  • Hỗ trợ phát triển API cục bộ
  • Codebase thân thiện với vibe-coding (thử MCP server của chúng tôi!)
  • Code client/server type-safe trực quan hơn
  • Và nhiều hơn nữa!

Phần này cung cấp hướng dẫn cho các tính năng của PDK không được đề cập trong ví dụ di chuyển ở trên.

Như một quy tắc chung khi chuyển từ PDK, chúng tôi khuyến nghị bắt đầu bất kỳ dự án nào với một Nx Workspace, do sự tương đồng của nó với PDK Monorepo. Chúng tôi cũng khuyến nghị sử dụng các generator của chúng tôi làm nền tảng để xây dựng bất kỳ loại mới nào.

Terminal window
pnpm create @aws/nx-workspace my-project

CDK Graph xây dựng đồ thị các tài nguyên CDK được kết nối của bạn, và cung cấp hai plugin:

CDK Graph Diagram Plugin tạo ra các sơ đồ kiến trúc AWS từ cơ sở hạ tầng CDK của bạn.

Để có một cách tiếp cận xác định tương tự, một giải pháp thay thế khả thi là CDK-Dia.

Với những tiến bộ trong Generative AI, nhiều mô hình nền tảng có khả năng tạo ra các sơ đồ chất lượng cao từ cơ sở hạ tầng CDK của bạn. Chúng tôi khuyên bạn nên thử AWS Diagram MCP Server. Xem bài đăng blog này để biết hướng dẫn chi tiết.

CDK Graph Threat Composer Plugin tạo ra một mô hình mối đe dọa Threat Composer khởi đầu từ mã CDK của bạn.

Plugin này hoạt động bằng cách đơn giản lọc một mô hình mối đe dọa cơ sở chứa các mối đe dọa ví dụ, và lọc chúng dựa trên các tài nguyên mà stack của bạn sử dụng.

Nếu bạn quan tâm đến các mối đe dọa ví dụ cụ thể này, bạn có thể sao chép và lọc mô hình mối đe dọa cơ sở, hoặc sử dụng nó làm ngữ cảnh để giúp một mô hình nền tảng tạo ra một mô hình tương tự.

AWS Arch cung cấp ánh xạ giữa các tài nguyên CloudFormation và các biểu tượng kiến trúc liên quan của chúng cho CDK Graph ở trên.

Tham khảo trang AWS Architecture Icons để biết các tài nguyên liên quan đến biểu tượng. Diagrams cũng cung cấp cách để xây dựng sơ đồ dưới dạng mã.

Nếu bạn đang sử dụng trực tiếp điều này, hãy cân nhắc fork dự án và tự quản lý!

PDK cung cấp một PDKPipelineProject để thiết lập một dự án cơ sở hạ tầng CDK và sử dụng một construct CDK bao bọc một số tài nguyên CDK Pipelines.

Để di chuyển từ cách này, bạn có thể sử dụng trực tiếp các construct CDK Pipelines. Tuy nhiên trong thực tế, có thể đơn giản hơn khi sử dụng các công cụ như GitHub actions hoặc GitLab CI/CD, nơi bạn định nghĩa CDK Stages và chạy lệnh deploy cho stage phù hợp một cách trực tiếp.

PDK Nag bao bọc CDK Nag, và cung cấp một tập hợp các quy tắc cụ thể để xây dựng nguyên mẫu.

Để di chuyển từ PDK Nag, hãy sử dụng CDK Nag trực tiếp. Nếu bạn cần cùng một tập hợp quy tắc, bạn có thể tạo một “pack” của riêng mình bằng cách làm theo tài liệu tại đây.

Các thành phần được sử dụng phổ biến nhất từ Type Safe API được đề cập trong ví dụ di chuyển ở trên, tuy nhiên còn có các tính năng khác, với chi tiết di chuyển được nêu dưới đây.

Nx Plugin for AWS hỗ trợ các API được mô hình hóa trong Smithy, nhưng không hỗ trợ những API được mô hình hóa trực tiếp bằng OpenAPI. Generator ts#smithy-api là một điểm khởi đầu tốt mà bạn có thể sửa đổi sau đó. Bạn có thể định nghĩa đặc tả OpenAPI của mình trong thư mục src của dự án model thay vì Smithy, và sửa đổi build.Dockerfile để sử dụng công cụ tạo mã mong muốn cho clients/servers nếu chúng không có sẵn trên NPM. Nếu các công cụ mong muốn của bạn có trên NPM, bạn chỉ cần cài đặt chúng như dev dependencies vào Nx workspace của bạn và gọi chúng trực tiếp như các Nx build targets.

Đối với các backend type-safe được mô hình hóa trong OpenAPI, bạn có thể cân nhắc sử dụng một trong các OpenAPI Generator Server Generators. Những công cụ này sẽ không tạo trực tiếp cho AWS Lambda, nhưng bạn có thể sử dụng AWS Lambda Web Adapter để kết nối cho nhiều trong số chúng.

Đối với TypeScript clients, bạn có thể sử dụng generator ts#websitegenerator connection với một ví dụ ts#api (với framework được đặt thành smithy) để xem cách clients được tạo và tích hợp với một website. Điều này cấu hình các build targets tạo clients bằng cách gọi các generator open-api#ts-client hoặc open-api#ts-hooks của chúng tôi. Bạn có thể tự sử dụng các generator này bằng cách trỏ chúng đến OpenAPI Specification của bạn.

Đối với các ngôn ngữ khác, bạn cũng có thể xem liệu có generator nào từ OpenAPI Generator phù hợp với nhu cầu của bạn không.

Bạn cũng có thể xây dựng một generator tùy chỉnh bằng cách sử dụng generator ts#nx-generator. Tham khảo tài liệu của generator đó để biết chi tiết về cách tạo mã từ OpenAPI. Bạn có thể sử dụng các template từ Nx Plugin for AWS làm điểm khởi đầu. Bạn thậm chí còn có thể tham khảo các template từ codebase PDK để có thêm cảm hứng, lưu ý rằng cấu trúc dữ liệu mà các template hoạt động trên đó hơi khác so với Nx Plugin for AWS.

Đối với TypeSpec, phần trên về OpenAPI cũng áp dụng. Bạn có thể bắt đầu bằng cách tạo một ts#smithy-api, cài đặt TypeSpec compiler và các gói OpenAPI vào Nx workspace của bạn, và cập nhật target compile của dự án model để chạy tsp compile thay thế, đảm bảo nó xuất ra một đặc tả OpenAPI vào thư mục dist.

Cách tiếp cận được khuyến nghị là sử dụng TypeSpec HTTP Server generator for JavaScript để tạo mã server của bạn, vì điều này hoạt động trực tiếp trên mô hình TypeSpec của bạn.

Bạn có thể sử dụng AWS Lambda Web Adapter để chạy server được tạo trên AWS Lambda.

Bạn cũng có thể sử dụng bất kỳ tùy chọn OpenAPI nào ở trên.

TypeSpec có các code generator riêng cho clients trong cả ba ngôn ngữ được Type Safe API hỗ trợ:

Phần OpenAPI ở trên cũng áp dụng vì TypeSpec có thể biên dịch sang OpenAPI.

Ví dụ di chuyển ở trên phác thảo việc di chuyển để sử dụng generator ts#smithy-api. Phần này đề cập đến các tùy chọn cho Python và Java backends và clients.

Smithy code generator for Java. Công cụ này có Java server generator cũng như một adapter để chạy Java server được tạo trên AWS Lambda.

Smithy không có server generator cho Python, vì vậy bạn sẽ cần phải đi qua OpenAPI. Tham khảo phần trên về API được Mô hình hóa bằng OpenAPI để biết các tùy chọn tiềm năng.

Smithy code generator for Java. Công cụ này có Java client generator.

Đối với Python clients, bạn có thể xem Smithy Python.

Đối với TypeScript, hãy xem Smithy TypeScript, hoặc sử dụng cách tiếp cận tương tự mà chúng tôi đã thực hiện trong ts#smithy-api bằng cách đi qua OpenAPI (chúng tôi chọn cách này vì nó mang lại sự nhất quán giữa các API tRPC, FastAPI và Smithy thông qua TanStack Query hooks).

Type Safe API cung cấp một loại dự án Projen có tên SmithyShapeLibraryProject cấu hình một dự án chứa các mô hình Smithy có thể được tái sử dụng bởi nhiều API dựa trên Smithy.

Tương đương là generator smithy#project với type được đặt thành shapes:

Terminal window
pnpm nx g @aws/nx-plugin:smithy#project --name=my-shapes --type=shapes
Bạn cũng có thể thực hiện chạy thử để xem những tệp nào sẽ bị thay đổi
Terminal window
pnpm nx g @aws/nx-plugin:smithy#project --name=my-shapes --type=shapes --dry-run

Di chuyển các shapes từ SmithyShapeLibraryProject của bạn vào thư mục src của dự án được tạo, sau đó tham khảo hướng dẫn dự án Smithy để biết cách kết nối thư viện như một dependency của model API của bạn.

Type Safe API cung cấp các interceptor mặc định sau:

  • Logging, tracing và metrics interceptors sử dụng Powertools for AWS Lambda
  • Try-catch interceptor để xử lý các exception chưa được bắt
  • CORS interceptor để trả về CORS headers

Generator ts#smithy-api tích hợp logging, tracing và metrics với Powertools for AWS Lambda sử dụng Middy. Hành vi của try-catch interceptor được tích hợp sẵn vào Smithy TypeScript SSDK, và CORS headers được thêm vào trong handler.ts.

Đối với logging, tracing và metrics interceptors trong bất kỳ ngôn ngữ nào, hãy sử dụng Powertools for AWS Lambda trực tiếp.

Để di chuyển các interceptor tùy chỉnh, chúng tôi khuyến nghị sử dụng các thư viện sau:

Type Safe API cung cấp tạo tài liệu sử dụng Redocly CLI. Điều này rất dễ thêm vào một dự án hiện có sau khi bạn đã di chuyển nó như trên.

  1. Cài đặt Redocly CLI

    Terminal window
    pnpm add -Dw @redocly/cli
  2. Thêm một target tạo tài liệu vào dự án model của bạn sử dụng redocly build-docs, ví dụ:

    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"]
    }
    }

Bạn cũng có thể cân nhắc các OpenAPI Generator documentation generators.

Type Safe API tạo mocks cho bạn trong gói infrastructure được tạo của nó.

Bạn có thể chuyển sang JSON Schema Faker có thể tạo dữ liệu mock dựa trên JSON Schemas. Điều này có thể hoạt động trực tiếp trên một đặc tả OpenAPI, và có một CLI mà bạn có thể chạy như một phần của quá trình build dự án model của bạn.

Bạn có thể cập nhật cơ sở hạ tầng CDK của mình để đọc tệp JSON được xuất ra bởi JSON Schema Faker, và trả về MockIntegration API Gateway phù hợp cho một integration, dựa trên metadata.gen.ts được tạo (giả sử bạn đã sử dụng generator ts#smithy-api).

Type Safe API hỗ trợ triển khai API với sự kết hợp của các ngôn ngữ khác nhau trong backend. Điều này cũng có thể đạt được bằng cách cung cấp “overrides” cho các integrations khi khởi tạo API construct của bạn trong CDK:

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(),
});

Bạn sẽ cần “stub” service/router của bạn để service của bạn biên dịch nếu sử dụng ts#smithy-api và TypeScript Server SDK, ví dụ:

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

Type Safe API đã thêm xác thực API Gateway gốc cho request bodies dựa trên đặc tả OpenAPI của bạn vì nó sử dụng construct SpecRestApi bên dưới.

Với generator ts#smithy-api, xác thực được thực hiện bởi chính Server SDK. Điều này giống nhau đối với hầu hết các server generators.

Nếu bạn muốn triển khai xác thực API Gateway gốc, bạn có thể làm như vậy bằng cách sửa đổi packages/common/constructs/src/core/api/rest-api.ts để đọc JSON schema liên quan cho request body của mỗi operation từ đặc tả OpenAPI của bạn.

Thật không may, không có đường dẫn di chuyển đơn giản cho websocket API của Type Safe API sử dụng API Gateway và Lambda với phát triển API dựa trên mô hình. Tuy nhiên, phần này của hướng dẫn nhằm mục đích ít nhất cung cấp một vài ý tưởng.

Cân nhắc sử dụng AsyncAPI để mô hình hóa API của bạn thay vì OpenAPI hoặc TypeSpec vì điều này được thiết kế để xử lý các API bất đồng bộ. AsyncAPI NodeJS Template có thể tạo một Node websocket backend mà bạn có thể host trên ECS chẳng hạn.

Bạn cũng có thể cân nhắc AppSync Events cho cơ sở hạ tầng, và sử dụng Powertools. Bài đăng blog này đáng đọc!

Một tùy chọn khác là sử dụng GraphQL APIs với websockets trên AppSync, mà chúng tôi có một GitHub issue bạn có thể +1! Tham khảo hướng dẫn dành cho nhà phát triển AppSync để biết chi tiết và liên kết đến các dự án mẫu.

Bạn cũng có thể cân nhắc tự xây dựng các code generators của riêng bạn để diễn giải các vendor extensions giống như Type Safe API. Tham khảo phần API được Mô hình hóa bằng OpenAPI để biết chi tiết về việc xây dựng các code generator tùy chỉnh dựa trên OpenAPI. Bạn có thể tìm thấy các template mà Type Safe API sử dụng cho API Gateway Websocket API Lambda handlers tại đây, và client tại đây.

Bạn cũng có thể cân nhắc di chuyển để sử dụng generator ts#trpc-api để sử dụng tRPC. Tại thời điểm viết bài này, chúng tôi chưa có hỗ trợ cho subscriptions/streaming nhưng nếu đây là điều bạn cần, hãy thêm +1 vào GitHub issue theo dõi điều này của chúng tôi.

Smithy là protocol agnostic, nhưng chưa có hỗ trợ cho giao thức Websocket, tham khảo GitHub issue theo dõi hỗ trợ này.

PDK hỗ trợ CDK infrastructure được viết bằng Python và Java. Chúng tôi không hỗ trợ điều này trong Nx Plugin for AWS tại thời điểm viết bài này.

Hướng đi được khuyến nghị là di chuyển CDK infrastructure của bạn sang TypeScript, hoặc sử dụng các generator của chúng tôi và di chuyển gói common constructs sang ngôn ngữ mong muốn của bạn. Bạn có thể sử dụng Generative AI để tăng tốc các loại di chuyển này, ví dụ như Kiro CLI. Bạn có thể để một AI agent lặp lại quá trình di chuyển cho đến khi các CloudFormation template được tổng hợp giống hệt nhau.

Điều tương tự áp dụng cho infrastructure được tạo ra bởi Type Safe API trong Python hoặc Java - bạn có thể dịch construct rest-api.ts chung từ gói common constructs, và triển khai metadata generator đơn giản của riêng bạn cho ngôn ngữ đích (tham khảo phần APIs Modelled with OpenAPI).

Bạn có thể sử dụng generator py#project cho một dự án Python cơ bản để thêm mã CDK của bạn vào (và di chuyển tệp cdk.json của bạn, thêm các target liên quan). Bạn có thể sử dụng plugin @nx/gradle của Nx cho các dự án Java, hoặc @jnxplus/nx-maven cho Maven.

PDK được xây dựng trên nền tảng Projen. Projen và Nx Generators có những khác biệt khá cơ bản, nghĩa là mặc dù về mặt kỹ thuật có thể kết hợp chúng nhưng điều đó có thể là một anti-pattern. Projen quản lý các tệp dự án dưới dạng mã sao cho chúng không thể được sửa đổi trực tiếp, trong khi Nx generators tạo ra các tệp dự án một lần và sau đó mã có thể được tự do sửa đổi.

Nếu bạn muốn tiếp tục sử dụng Projen, bạn có thể tự triển khai các loại dự án Projen mong muốn của mình. Để tuân theo các mẫu từ Nx Plugin for AWS, bạn có thể chạy các generators của chúng tôi hoặc kiểm tra mã nguồn của chúng trên GitHub để xem cách các loại dự án mong muốn của bạn được xây dựng, và triển khai các phần liên quan bằng cách sử dụng các nguyên thủy của Projen.

Giới thiệu Nx Plugin for AWS MCP Server

Trong bối cảnh phát triển phần mềm đang phát triển nhanh chóng, các trợ lý AI đã trở thành những cộng tác viên có giá trị trong hành trình lập trình của chúng ta. Nhiều nhà phát triển đã chấp nhận cái mà chúng ta trìu mến gọi là “vibe-coding” - điệu nhảy cộng tác giữa sự sáng tạo của con người và sự hỗ trợ của AI. Giống như bất kỳ thực hành mới nổi nào, nó đi kèm với cả những lợi ích thú vị và những thách thức đáng chú ý. Bài viết này giới thiệu Nx Plugin for AWS MCP Server, giúp nâng cao trải nghiệm phát triển được hỗ trợ bởi AI khi làm việc với các sản phẩm và dịch vụ AWS.

Vibe-coding, thực hành xây dựng phần mềm cộng tác với các trợ lý AI, đã thay đổi cách nhiều tổ chức tiếp cận phát triển phần mềm. Bạn mô tả những gì bạn muốn xây dựng, và trợ lý AI của bạn giúp biến tầm nhìn của bạn thành hiện thực, thông qua việc viết code và tests, chạy các lệnh build, và cộng tác lặp lại để hoàn thành các tác vụ cả lớn và nhỏ.

Cách tiếp cận cộng tác này đã tăng tốc đáng kể chu kỳ phát triển, vì các triển khai phức tạp mà trước đây có thể mất hàng giờ để viết thủ công, giờ đây thường có thể hoàn thành trong vài phút.

Mặc dù có những lợi ích, vibe-coding đi kèm với những cạm bẫy có thể làm gián đoạn luồng công việc của bạn và dẫn đến sự thất vọng. Các công cụ AI có thể tạo ra các mẫu không nhất quán trong một dự án, điều này có thể tạo ra những cơn đau đầu về bảo trì sau này. Nếu không có hướng dẫn cụ thể, AI có thể bỏ lỡ các thực hành tốt nhất hoặc cân nhắc về bảo mật cụ thể của AWS mà các nhà phát triển có kinh nghiệm sẽ tự nhiên kết hợp.

Nếu không có cấu trúc dự án rõ ràng, code được hỗ trợ bởi AI có thể trở nên lộn xộn và khó bảo trì. AI có thể tạo ra các triển khai tùy chỉnh cho các vấn đề đã có giải pháp được thiết lập sẵn, không cần thiết phải phát minh lại bánh xe.

Những thách thức này có thể dẫn đến nợ kỹ thuật, lỗ hổng bảo mật và sự thất vọng, đặc biệt khi làm việc với nhiều dịch vụ AWS kết nối với nhau chứ không chỉ trong phạm vi của một framework duy nhất.

Nx Plugin for AWS cung cấp một nền tảng có cấu trúc để xây dựng các ứng dụng AWS bằng công cụ monorepo Nx. Thay vì bắt đầu với một canvas trống, plugin cung cấp một framework nhất quán cho việc tổ chức dự án.

Plugin đảm bảo việc xây dựng khung sườn dự án nhất quán thông qua các generators cho các loại dự án phổ biến, giúp duy trì tính toàn vẹn cấu trúc trong toàn bộ codebase của bạn. Nó kết hợp các templates được cấu hình sẵn tuân theo các thực hành tốt nhất của AWS, giúp các nhà phát triển tránh các cạm bẫy phổ biến và vấn đề bảo mật. Công cụ tích hợp cung cấp các lệnh tích hợp sẵn để build, test và deploy các ứng dụng AWS, và hợp lý hóa quy trình phát triển thông qua các máy chủ phát triển cục bộ. Ngoài ra, nó tận dụng khả năng quản lý phụ thuộc mạnh mẽ của Nx cho các dự án phức tạp, đơn giản hóa việc quản lý monorepo.

Bằng cách cung cấp cấu trúc này, Nx Plugin for AWS cung cấp cho các trợ lý AI một cấu trúc rõ ràng để làm việc trong đó. Thay vì phát minh các mẫu từ đầu, các trợ lý AI có thể tuân theo các quy ước đã được thiết lập, dẫn đến một codebase nhất quán và dễ bảo trì hơn.

Model Context Protocol (MCP) là một tiêu chuẩn mở cho phép các trợ lý AI tương tác với các công cụ và tài nguyên bên ngoài. Nx Plugin for AWS MCP server mở rộng khả năng của trợ lý AI của bạn với kiến thức chuyên môn về Nx Plugin for AWS.

MCP server cung cấp thông tin theo ngữ cảnh về các thực hành tốt nhất, các cấu trúc dự án có sẵn và các mẫu triển khai cụ thể cho phát triển AWS. Nó cho phép công cụ AI của bạn tạo workspaces và chạy generators để xây dựng khung sườn các loại dự án phổ biến. Nhận thức theo ngữ cảnh này giúp AI đưa ra các đề xuất có thông tin hơn phù hợp với các mẫu đã được thiết lập và tránh các cạm bẫy phổ biến.

Thay vì tạo ra code có thể không phù hợp với các thực hành tốt nhất hoặc có thể tham chiếu đến các tính năng không tồn tại, trợ lý AI của bạn có thể tận dụng MCP server để đặt nền móng cho dự án của bạn. Kết quả là một trải nghiệm phát triển xác định và đáng tin cậy hơn, nơi bạn có thể bắt đầu với một nền tảng vững chắc cho các thành phần cốt lõi của dự án và sử dụng AI để điền vào logic nghiệp vụ.

Nếu bạn quan tâm đến việc khám phá phát triển AWS được hỗ trợ bởi AI với nhiều cấu trúc và độ tin cậy hơn, hãy thử Nx Plugin for AWS MCP Server. Bạn có thể thiết lập nó trong Trợ lý AI yêu thích của mình (Kiro, Kiro CLI, Cline, Claude Code, v.v.) với cấu hình MCP Server sau:

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

Để biết hướng dẫn chi tiết, hãy tham khảo hướng dẫn Xây dựng với AI của chúng tôi.

Chào mừng đến với @aws/nx-plugin

Và chúng tôi đã ra mắt! 🚀

Nx Plugin for AWS là một plugin Nx cung cấp bộ công cụ để đơn giản hóa quy trình xây dựng và triển khai các ứng dụng full-stack trên AWS. Nó cung cấp cho các nhà phát triển các template được cấu hình sẵn cho cả mã ứng dụng và mã IaC, giảm đáng kể thời gian dành cho việc thiết lập và cấu hình. Plugin xử lý sự phức tạp của việc tích hợp dịch vụ AWS trong khi vẫn duy trì tính linh hoạt để tùy chỉnh.

Người dùng chỉ cần chọn các thành phần họ muốn từ danh sách các generator có sẵn, cung cấp bất kỳ tùy chọn cấu hình nào và để @aws/nx-plugin tạo mã khởi đầu cần thiết. Một số generator tồn tại trong bộ công cụ này có thể tạo API, website, cơ sở hạ tầng và thậm chí làm những việc phức tạp hơn như tích hợp frontend với backend (bao gồm cập nhật các file hiện có thông qua AST transforms!) với các client type-safe.

generator

Để tìm hiểu thêm, hãy bắt đầu với hướng dẫn Dungeon Adventure của chúng tôi, bao gồm tất cả các thành phần chính của plugin và sẽ cho bạn cái nhìn tổng quan về cách sử dụng nó.

Chúng tôi rất mong nhận được phản hồi của bạn, đừng ngần ngại đăng thảo luận hoặc báo cáo vấn đề để cho chúng tôi biết bạn nghĩ gì và bạn muốn thấy gì tiếp theo!

Thử ngay!