Smithy TypeScript API
Smithy là một ngôn ngữ định nghĩa giao diện độc lập với giao thức để tạo API theo cách hướng mô hình.
Trình tạo Smithy TypeScript API tạo một API mới sử dụng Smithy để định nghĩa dịch vụ, và Smithy TypeScript Server SDK để triển khai. Trình tạo cung cấp mã cơ sở hạ tầng CDK hoặc Terraform để triển khai dịch vụ của bạn lên AWS Lambda, được hiển thị qua AWS API Gateway REST API. Nó cung cấp phát triển API an toàn kiểu với tự động tạo mã từ các mô hình Smithy. Handler được tạo sử dụng AWS Lambda Powertools for TypeScript để quan sát, bao gồm ghi log, theo dõi AWS X-Ray và CloudWatch Metrics
Cách sử dụng
Phần tiêu đề “Cách sử dụng”Tạo một Smithy TypeScript API
Phần tiêu đề “Tạo một Smithy TypeScript API”Bạn có thể tạo một Smithy TypeScript API mới theo hai cách:
pnpm nx g @aws/nx-plugin:ts#api --framework=smithyyarn nx g @aws/nx-plugin:ts#api --framework=smithynpx nx g @aws/nx-plugin:ts#api --framework=smithybunx nx g @aws/nx-plugin:ts#api --framework=smithyBạn cũng có thể thực hiện chạy thử để xem những tệp nào sẽ bị thay đổi
pnpm nx g @aws/nx-plugin:ts#api --framework=smithy --dry-runyarn nx g @aws/nx-plugin:ts#api --framework=smithy --dry-runnpx nx g @aws/nx-plugin:ts#api --framework=smithy --dry-runbunx nx g @aws/nx-plugin:ts#api --framework=smithy --dry-run- Cài đặt Nx Console VSCode Plugin nếu bạn chưa cài đặt
- Mở Nx Console trong VSCode
- Nhấp
Generate (UI)trong phần "Common Nx Commands" - Tìm kiếm
@aws/nx-plugin - ts#api - Điền các tham số bắt buộc
- framework: smithy
- Nhấp
Generate
Tùy chọn
Phần tiêu đề “Tùy chọn”| Tham số | Kiểu | Mặc định | Mô tả |
|---|---|---|---|
| name Bắt buộc | string | - | Tên của API (bắt buộc). Được sử dụng để tạo tên class và đường dẫn file. |
| framework | trpc | smithy | trpc | Framework API để sử dụng. |
| namespace | string | - | Namespace cho Smithy API (chỉ áp dụng cho framework smithy). Mặc định là scope của monorepo |
| integrationPattern | isolated | shared | isolated | Cách thức tạo API Gateway integrations cho API. Chọn giữa isolated (mặc định) và shared. |
| auth | iam | cognito | custom | iam | Phương thức được sử dụng để xác thực với API của bạn. Chọn giữa iam (mặc định), cognito hoặc custom. |
| directory | string | packages | Thư mục để lưu trữ ứng dụng. |
| subDirectory | string | - | Thư mục con mà dự án được đặt trong đó. Mặc định đây là tên dự án. |
| iac | inherit | cdk | terraform | inherit | Nhà cung cấp IaC ưa thích. Mặc định được kế thừa từ lựa chọn ban đầu của bạn. |
| infra | rest-lambda | http-lambda | none | rest-lambda | Loại hạ tầng được sử dụng để triển khai API này. |
| preferInstallDependencies | boolean | true | Có nên cài đặt dependencies sau khi generator chạy hay không. Đặt thành false để trì hoãn việc cài đặt khi chạy nhiều generator liên tiếp (việc cài đặt vẫn sẽ chạy nếu cần thiết để các generator tiếp theo có thể tính toán Nx project graph); cài đặt một lần vào cuối. |
Đầu ra của trình tạo
Phần tiêu đề “Đầu ra của trình tạo”Trình tạo tạo hai dự án liên quan trong thư mục <directory>/<api-name>:
Thư mụcmodel/ Dự án mô hình Smithy
- package.json Tệp kê khai dự án định nghĩa tên gói và các phụ thuộc của dự án
- project.json Cấu hình dự án và các target build
- smithy-build.json Cấu hình build Smithy
- ssdk.rolldown.config.mjs Đóng gói TypeScript Server SDK được tạo
Thư mụcsrc/
- main.smithy Định nghĩa dịch vụ chính
Thư mụcoperations/
- echo.smithy Định nghĩa thao tác ví dụ
Thư mụcbackend/ Triển khai backend TypeScript
- project.json Cấu hình dự án và các target build
- rolldown.config.ts Cấu hình bundle
Thư mụcsrc/
- handler.ts AWS Lambda handler
- local-server.ts Server phát triển cục bộ
- service.ts Triển khai dịch vụ
- context.ts Định nghĩa ngữ cảnh dịch vụ
Thư mụcoperations/
- echo.ts Triển khai thao tác ví dụ
Thư mụcgenerated/ TypeScript SDK được tạo (được tạo trong quá trình build)
- …
Cơ sở hạ tầng
Phần tiêu đề “Cơ sở hạ tầng”Vì trình tạo này tạo mã cơ sở hạ tầng dựa trên iac bạn chọn, nó sẽ tạo một dự án trong packages/common bao gồm các CDK construct hoặc Terraform module liên quan.
Dự án mã cơ sở hạ tầng chung được cấu trúc như sau:
Thư mụcpackages/common/constructs
Thư mụcsrc
Thư mụcapp/ Các construct cho cơ sở hạ tầng cụ thể cho một dự án/trình tạo
Thư mụcapis/
- <project-name>.ts CDK construct để triển khai API của bạn
Thư mụccore/ Các construct chung được tái sử dụng bởi các construct trong
appThư mụcapi/
- rest-api.ts CDK construct để triển khai REST API
- utils.ts Các tiện ích cho các construct API
- index.ts Entry point xuất các construct từ
app
- project.json Các target build và cấu hình dự án
Thư mụcpackages/common/terraform
Thư mụcsrc
Thư mụcapp/ Các module Terraform cho cơ sở hạ tầng cụ thể cho một dự án/trình tạo
Thư mụcapis/
Thư mục<project-name>/
- <project-name>.tf Module để triển khai API của bạn
Thư mụccore/ Các module chung được tái sử dụng bởi các module trong
appThư mụcapi/
Thư mụcrest-api/
- rest-api.tf Module để triển khai REST API
- project.json Các target build và cấu hình dự án
Kiến trúc
Phần tiêu đề “Kiến trúc”Smithy API được triển khai có kiến trúc sau, với AWS WAFv2 Web ACL ở phía trước API Gateway stage:
Triển khai Smithy API của bạn
Phần tiêu đề “Triển khai Smithy API của bạn”Định nghĩa các thao tác trong Smithy
Phần tiêu đề “Định nghĩa các thao tác trong Smithy”Các thao tác được định nghĩa trong các tệp Smithy trong dự án model. Định nghĩa dịch vụ chính nằm trong main.smithy:
$version: "2.0"
namespace your.namespace
use aws.protocols#restJson1use smithy.framework#ValidationException
@title("YourService")@restJson1service YourService { version: "1.0.0" operations: [ Echo, // Add your operations here ] errors: [ ValidationException ]}Các operations riêng lẻ được định nghĩa trong các file riêng biệt trong thư mục operations/:
$version: "2.0"
namespace your.namespace
@http(method: "POST", uri: "/echo")operation Echo { input: EchoInput output: EchoOutput}
structure EchoInput { @required message: String
foo: Integer bar: String}
structure EchoOutput { @required message: String}Thêm một thư viện Shape
Phần tiêu đề “Thêm một thư viện Shape”Nếu bạn có nhiều Smithy API chia sẻ cùng các kiểu dữ liệu, bạn có thể định nghĩa các kiểu đó một lần trong một thư viện shape thay vì sao chép chúng trong mỗi model. Một thư viện shape là một dự án Smithy không có dịch vụ — chỉ có các shape có thể tái sử dụng — mà bất kỳ số lượng dự án Smithy nào cũng có thể phụ thuộc vào.
Tạo một thư viện với trình tạo smithy#project:
pnpm nx g @aws/nx-plugin:smithy#project --name=my-shapes --type=shapesyarn nx g @aws/nx-plugin:smithy#project --name=my-shapes --type=shapesnpx nx g @aws/nx-plugin:smithy#project --name=my-shapes --type=shapesbunx nx g @aws/nx-plugin:smithy#project --name=my-shapes --type=shapesBạn cũng có thể thực hiện chạy thử để xem những tệp nào sẽ bị thay đổi
pnpm nx g @aws/nx-plugin:smithy#project --name=my-shapes --type=shapes --dry-runyarn nx g @aws/nx-plugin:smithy#project --name=my-shapes --type=shapes --dry-runnpx nx g @aws/nx-plugin:smithy#project --name=my-shapes --type=shapes --dry-runbunx nx g @aws/nx-plugin:smithy#project --name=my-shapes --type=shapes --dry-run- Cài đặt Nx Console VSCode Plugin nếu bạn chưa cài đặt
- Mở Nx Console trong VSCode
- Nhấp
Generate (UI)trong phần "Common Nx Commands" - Tìm kiếm
@aws/nx-plugin - smithy#project - Điền các tham số bắt buộc
- name: my-shapes
- type: shapes
- Nhấp
Generate
Mô hình API của bạn sau đó có thể tham chiếu các shape của nó bằng use:
$version: "2.0"
namespace com.example.api
use com.example.shared#Customer
structure GetCustomerOutput { @required customer: Customer}Xem hướng dẫn dự án Smithy để biết cách tạo một thư viện shape và kết nối nó như một phụ thuộc của model API của bạn.
Triển khai các thao tác trong TypeScript
Phần tiêu đề “Triển khai các thao tác trong TypeScript”Các triển khai thao tác nằm trong thư mục src/operations/ của dự án backend. Mỗi thao tác được triển khai bằng các kiểu được tạo từ TypeScript Server SDK (được tạo tại thời điểm build từ mô hình Smithy của bạn).
import { ServiceContext } from '../context.js';import { Echo as EchoOperation } from '../generated/ssdk/index.js';
export const Echo: EchoOperation<ServiceContext> = async (input) => { // Your business logic here return { message: `Echo: ${input.message}` // type-safe based on your Smithy model };};Operations phải được đăng ký vào định nghĩa dịch vụ trong src/service.ts:
import { ServiceContext } from './context.js';import { YourServiceService } from './generated/ssdk/index.js';import { Echo } from './operations/echo.js';// Import other operations here
// Register operations to the service hereexport const Service: YourServiceService<ServiceContext> = { Echo, // Add other operations here};Ngữ cảnh dịch vụ
Phần tiêu đề “Ngữ cảnh dịch vụ”Bạn có thể định nghĩa ngữ cảnh được chia sẻ cho các thao tác của mình trong context.ts:
export interface ServiceContext { // Powertools tracer, logger and metrics are provided by default tracer: Tracer; logger: Logger; metrics: Metrics; // Add shared dependencies, database connections, etc. dbClient: any; userIdentity: string;}Context này được truyền cho tất cả các triển khai operation và có thể được sử dụng để chia sẻ tài nguyên như kết nối database, cấu hình, hoặc tiện ích logging.
Khả năng quan sát với AWS Lambda Powertools
Phần tiêu đề “Khả năng quan sát với AWS Lambda Powertools”Ghi log
Phần tiêu đề “Ghi log”Trình tạo cấu hình ghi log có cấu trúc bằng AWS Lambda Powertools với tự động chèn ngữ cảnh qua middleware Middy.
export const handler = middy<APIGatewayProxyEvent, APIGatewayProxyResult>() .use(captureLambdaHandler(tracer)) .use(injectLambdaContext(logger)) .use(logMetrics(metrics)) .handler(lambdaHandler);Bạn có thể tham chiếu logger từ các triển khai operation của bạn thông qua context:
import { ServiceContext } from '../context.js';import { Echo as EchoOperation } from '../generated/ssdk/index.js';
export const Echo: EchoOperation<ServiceContext> = async (input, ctx) => { ctx.logger.info('Your log message'); // ...};Theo dõi
Phần tiêu đề “Theo dõi”Theo dõi AWS X-Ray được cấu hình tự động qua middleware captureLambdaHandler.
export const handler = middy<APIGatewayProxyEvent, APIGatewayProxyResult>() .use(captureLambdaHandler(tracer)) .use(injectLambdaContext(logger)) .use(logMetrics(metrics)) .handler(lambdaHandler);Bạn có thể thêm subsegments tùy chỉnh vào traces của bạn trong các operations:
import { ServiceContext } from '../context.js';import { Echo as EchoOperation } from '../generated/ssdk/index.js';
export const Echo: EchoOperation<ServiceContext> = async (input, ctx) => { // Creates a new subsegment const subsegment = ctx.tracer.getSegment()?.addNewSubsegment('custom-operation'); try { // Your logic here } catch (error) { subsegment?.addError(error as Error); throw error; } finally { subsegment?.close(); }};Số liệu
Phần tiêu đề “Số liệu”Các số liệu CloudWatch được thu thập tự động cho mỗi yêu cầu qua middleware logMetrics.
export const handler = middy<APIGatewayProxyEvent, APIGatewayProxyResult>() .use(captureLambdaHandler(tracer)) .use(injectLambdaContext(logger)) .use(logMetrics(metrics)) .handler(lambdaHandler);Bạn có thể thêm custom metrics trong các operations của bạn:
import { MetricUnit } from '@aws-lambda-powertools/metrics';import { ServiceContext } from '../context.js';import { Echo as EchoOperation } from '../generated/ssdk/index.js';
export const Echo: EchoOperation<ServiceContext> = async (input, ctx) => { ctx.metrics.addMetric("CustomMetric", MetricUnit.Count, 1); // ...};Xử lý lỗi
Phần tiêu đề “Xử lý lỗi”Smithy cung cấp xử lý lỗi tích hợp. Bạn có thể định nghĩa các lỗi tùy chỉnh trong mô hình Smithy của mình:
@error("client")@httpError(400)structure InvalidRequestError { @required message: String}Và đăng ký chúng vào operation/service của bạn:
operation MyOperation { ... errors: [InvalidRequestError]}Sau đó ném chúng trong triển khai TypeScript của bạn:
import { InvalidRequestError } from '../generated/ssdk/index.js';
export const MyOperation: MyOperationHandler<ServiceContext> = async (input) => { if (!input.requiredField) { throw new InvalidRequestError({ message: "Required field is missing" }); }
return { /* success response */ };};Truy cập người dùng đang gọi
Phần tiêu đề “Truy cập người dùng đang gọi”Khi API của bạn được bảo vệ bằng xác thực, các thao tác của bạn thường cần biết ai đang gọi. Cách tiếp cận được khuyến nghị là giải quyết danh tính của người gọi một lần trong handler và truyền nó qua ngữ cảnh dịch vụ để các thao tác cụ thể sử dụng.
Chúng ta sẽ mô hình hóa trường hợp không được ủy quyền như một lỗi Smithy để nó được tuần tự hóa thành phản hồi 403 phù hợp. Thêm nó vào mô hình của bạn, ví dụ trong model/src/operations/errors.smithy, và tham chiếu nó trên bất kỳ operation nào yêu cầu danh tính:
$version: "2.0"
namespace your.namespace
/// Thrown when the calling user cannot be determined@error("client")@httpError(403)structure UnauthorizedError { @required message: String}Đầu tiên, hiển thị danh tính đã giải quyết trên service context trong src/context.ts. Chúng ta cung cấp nó dưới dạng một hàm để UnauthorizedError được ném ra từ bên trong một operation (nơi Server SDK tuần tự hóa nó thành 403), thay vì từ handler:
import { Logger } from '@aws-lambda-powertools/logger';import { Metrics } from '@aws-lambda-powertools/metrics';import { Tracer } from '@aws-lambda-powertools/tracer';
export interface Identity { sub: string; username: string;}
/** * Context provided to all operations. */export interface ServiceContext { tracer: Tracer; logger: Logger; metrics: Metrics; getIdentity: () => Promise<Identity>;}Tiếp theo, viết resolver trong src/identity.ts. Nó ném UnauthorizedError khi không thể xác định người gọi. Việc triển khai phụ thuộc vào phương thức auth bạn đã chọn:
Đối với xác thực IAM, chúng ta tra cứu người gọi trong Cognito bằng sub được trích xuất từ sự kiện API Gateway:
import { CognitoIdentityProvider } from '@aws-sdk/client-cognito-identity-provider';import type { APIGatewayProxyEvent } from 'aws-lambda';import { Identity } from './context.js';import { UnauthorizedError } from './generated/ssdk/index.js';
const cognito = new CognitoIdentityProvider();
export const getIdentity = async ( event: APIGatewayProxyEvent,): Promise<Identity> => { const cognitoAuthenticationProvider = event.requestContext?.identity?.cognitoAuthenticationProvider;
let sub: string | undefined = undefined; if (cognitoAuthenticationProvider) { const providerParts = cognitoAuthenticationProvider.split(':'); sub = providerParts[providerParts.length - 1]; }
if (!sub) { throw new UnauthorizedError({ message: 'Unable to determine calling user' }); }
const { Users } = await cognito.listUsers({ // Assumes user pool id is configured in lambda environment UserPoolId: process.env.USER_POOL_ID!, Limit: 1, Filter: `sub="${sub}"`, });
if (!Users || Users.length !== 1) { throw new UnauthorizedError({ message: `No user found with subjectId ${sub}` }); }
return { sub, username: Users[0].Username! };};Với auth: 'cognito', API Gateway Cognito User Pools authorizer xác minh JWT mà người gọi cung cấp trong header Authorization và đặt các claim đã xác minh trên sự kiện tại event.requestContext.authorizer.claims:
import type { APIGatewayProxyEvent } from 'aws-lambda';import { Identity } from './context.js';import { UnauthorizedError } from './generated/ssdk/index.js';
export const getIdentity = async ( event: APIGatewayProxyEvent,): Promise<Identity> => { const claims = event.requestContext?.authorizer?.claims as | Record<string, string> | undefined;
const sub = claims?.sub; const username = claims?.username;
if (!sub || !username) { throw new UnauthorizedError({ message: 'Unable to determine calling user' }); }
return { sub, username };};Sau đó kết nối resolver vào ngữ cảnh trong src/handler.ts:
import { Service } from './service.js';import { getIdentity } from './identity.js';// ...const httpResponse = await serviceHandler.handle(httpRequest, { tracer, logger, metrics, getIdentity: () => getIdentity(event),});Bây giờ chúng ta có thể sử dụng danh tính đã giải quyết trong một operation, ví dụ trong src/operations/echo.ts:
import { ServiceContext } from '../context.js';import { Echo as EchoOperation } from '../generated/ssdk/index.js';
export const Echo: EchoOperation<ServiceContext> = async (input, ctx) => { const identity = await ctx.getIdentity(); return { message: `${identity.username} says ${input.message}` };};Build và tạo mã
Phần tiêu đề “Build và tạo mã”Dự án mô hình Smithy sử dụng Smithy CLI để build các artifact Smithy và tạo TypeScript Server SDK:
pnpm nx build <model-project>yarn nx build <model-project>npx nx build <model-project>bunx nx build <model-project>Trên macOS và Linux, CLI được giải quyết bởi mise, mà quá trình build tải về theo yêu cầu, vì vậy không có gì cần cài đặt — nó tải xuống và lưu vào bộ nhớ cache phiên bản đã được ghim lần đầu tiên bạn build.
Quá trình này:
- Biên dịch mô hình Smithy và xác thực nó
- Tạo đặc tả OpenAPI từ mô hình Smithy
- Tạo TypeScript Server SDK với các giao diện operation an toàn kiểu
- Xuất các build artifacts ra
dist/<model-project>/build/
Dự án backend tự động sao chép SDK được tạo trong quá trình biên dịch:
pnpm nx copy-ssdk <backend-project>yarn nx copy-ssdk <backend-project>npx nx copy-ssdk <backend-project>bunx nx copy-ssdk <backend-project>Build trên Windows
Phần tiêu đề “Build trên Windows”mise không xuất bản gói Windows lên npm, vì vậy trên Windows, Smithy CLI là một điều kiện tiên quyết bạn tự cài đặt. Cài đặt nó một lần theo hướng dẫn cài đặt Smithy CLI (ví dụ winget install smithy hoặc scoop install smithy), và đảm bảo smithy nằm trên PATH của bạn. Một dự án Smithy được tạo trên Windows chạy smithy trực tiếp thay vì thông qua mise.
Ngoài ra, phát triển bên trong WSL, nơi quá trình build chạy đường dẫn Linux và mise giải quyết CLI cho bạn — không có gì cần cài đặt.
Một dự án được tạo trên Windows commit một target compile gọi smithy trực tiếp, vì vậy bất kỳ ai khác làm việc trên nó — bao gồm trên macOS hoặc Linux — cũng cần Smithy CLI trên PATH của họ. Để các máy đó giải quyết CLI thông qua mise thay thế, hãy chuyển target sang lệnh mise như mô tả bên dưới.
Chọn cách CLI được giải quyết
Phần tiêu đề “Chọn cách CLI được giải quyết”macOS và Linux giải quyết CLI thông qua mise và Windows sử dụng CLI được cài đặt toàn cục, nhưng bạn có thể chọn một trong hai trên bất kỳ nền tảng nào bằng cách chỉnh sửa lệnh của target compile trong project.json của dự án mô hình.
Để sử dụng Smithy CLI được cài đặt toàn cục thay vì mise, thay thế tiền tố mise bằng smithy đơn giản:
{ "targets": { "compile": { "options": { "commands": ["... npx -y mise@<version> exec smithy@<version> -- smithy build ..."] "commands": ["... smithy build ..."] } } }}Để quay lại việc mise giải quyết CLI, khôi phục tiền tố npx -y mise@<version> exec smithy@<version> --.
Target Bundle
Phần tiêu đề “Target Bundle”Generator tự động cấu hình một target bundle sử dụng Rolldown để tạo gói triển khai:
pnpm nx bundle <project-name>yarn nx bundle <project-name>npx nx bundle <project-name>bunx nx bundle <project-name>Cấu hình Rolldown có thể được tìm thấy trong rolldown.config.ts, với một entry cho mỗi bundle cần tạo. Rolldown quản lý việc tạo nhiều bundle song song nếu được định nghĩa.
Phát triển cục bộ
Phần tiêu đề “Phát triển cục bộ”Trình tạo cấu hình một server phát triển cục bộ với hot reloading:
pnpm nx serve <backend-project>yarn nx serve <backend-project>npx nx serve <backend-project>bunx nx serve <backend-project>Triển khai Smithy API của bạn
Phần tiêu đề “Triển khai Smithy API của bạn”Trình tạo tạo cơ sở hạ tầng CDK hoặc Terraform dựa trên iac bạn đã chọn.
CDK construct để triển khai API của bạn nằm trong thư mục common/constructs:
import { MyApi } from '@my-scope/common-constructs';
export class ExampleStack extends Stack { constructor(scope: Construct, id: string) { // Add the API to your stack const api = new MyApi(this, 'MyApi', { integrations: MyApi.defaultIntegrations(this).build(), }); }}Điều này thiết lập:
- Một hàm AWS Lambda cho dịch vụ Smithy
- API Gateway REST API làm trigger cho hàm
- Các vai trò IAM và quyền
- Nhóm log CloudWatch
- Cấu hình theo dõi X-Ray
Các module Terraform để triển khai API của bạn nằm trong thư mục common/terraform.
Module API đặt zip triển khai Lambda của nó trong một S3 asset bucket được chia sẻ — xem hướng dẫn cơ sở hạ tầng Terraform để biết chi tiết. Khởi tạo module core/asset-bucket một lần cho mỗi triển khai và truyền đầu ra bucket_name của nó vào mọi module API / Lambda qua đầu vào asset_bucket_name:
module "asset_bucket" { source = "../../common/terraform/src/core/asset-bucket"}
module "my_api" { source = "../../common/terraform/src/app/apis/my-api"
asset_bucket_name = module.asset_bucket.bucket_name
# Environment variables for the Lambda function env = { ENVIRONMENT = var.environment LOG_LEVEL = "INFO" }
# Additional IAM policies if needed additional_iam_policy_statements = [ # Add any additional permissions your API needs ]
tags = local.common_tags}Điều này thiết lập:
- Một hàm AWS Lambda phục vụ Smithy API
- API Gateway REST API làm trigger cho hàm
- Các vai trò IAM và quyền
- Nhóm log CloudWatch
- Cấu hình theo dõi X-Ray
- Cấu hình CORS
Module Terraform cung cấp một số đầu ra:
# Access the API endpointoutput "api_url" { value = module.my_api.stage_invoke_url}
# Access Lambda function detailsoutput "lambda_function_name" { value = module.my_api.lambda_function_name}Đối với REST API, construct được tạo ra sẽ liên kết một AWS WAFv2 Web ACL với API Gateway stage theo mặc định. Web ACL sử dụng bộ quy tắc mặc định được quản lý bởi AWS (AWSManagedRulesCommonRuleSet và AWSManagedRulesKnownBadInputsRuleSet), cung cấp bảo vệ chống lại các lỗ hổng web phổ biến bao gồm OWASP Top 10. Nhật ký yêu cầu WAF được ghi vào một nhóm CloudWatch Logs.
Bạn có thể chỉnh sửa rest-api construct được tạo ra để thêm, xóa hoặc điều chỉnh các quy tắc (ví dụ: để thêm quy tắc dựa trên tốc độ hoặc các nhóm quy tắc được quản lý bổ sung).
Để chọn không sử dụng (ví dụ: để đính kèm Web ACL của riêng bạn), đặt enableWaf thành false:
const api = new MyApi(this, 'MyApi', { integrations: MyApi.defaultIntegrations(this).build(), enableWaf: false,});Để chọn không sử dụng (ví dụ: để đính kèm Web ACL của riêng bạn), đặt enable_waf thành false:
module "my_api" { source = "../../common/terraform/src/app/apis/my-api"
asset_bucket_name = module.asset_bucket.bucket_name enable_waf = false}Ghi log truy cập
Phần tiêu đề “Ghi log truy cập”Đối với REST API, cơ sở hạ tầng được tạo ra sẽ kích hoạt ghi log truy cập theo mặc định, ghi một dòng JSON có cấu trúc cho mỗi yêu cầu vào một nhóm CloudWatch Logs chuyên dụng. Nhóm log được mã hóa bằng khóa KMS do khách hàng quản lý và được giữ lại trong một năm.
API Gateway ghi log truy cập bằng cách sử dụng vai trò CloudWatch Logs cấp tài khoản. Vai trò này được cấu hình trên cài đặt AWS::ApiGateway::Account, là một singleton cho mỗi vùng mỗi tài khoản — chỉ có một vai trò cho mọi REST API trong vùng. Để quản lý điều này một cách an toàn trên nhiều stack được triển khai độc lập, cơ sở hạ tầng được tạo ra:
- Tạo một vai trò CloudWatch Logs được chia sẻ và cấu hình nó trên tài khoản chỉ khi chưa có vai trò hoạt động nào được thiết lập, do đó các triển khai không bao giờ ghi đè vai trò mà stack khác sở hữu.
- Để nguyên cài đặt tài khoản khi dỡ bỏ, do đó việc hủy một stack không bao giờ vô hiệu hóa ghi log cho các REST API khác trong vùng.
Vai trò tài khoản được quản lý bởi construct ApiGatewayAccount, một singleton có phạm vi stack được giải quyết thông qua ApiGatewayAccount.ensure(scope). Mỗi stage của REST API phụ thuộc vào nó, và vai trò được cấu hình bởi một tài nguyên tùy chỉnh được hỗ trợ bởi Lambda.
Định dạng log truy cập được thiết lập bởi construct RestApi mà API của bạn mở rộng. Để tùy chỉnh nó, hãy truyền deployOptions qua super trong file packages/common/constructs/src/app/apis/my-api.ts được tạo ra, giữ nguyên tracingEnabled mà construct đã thiết lập:
super(scope, id, { apiName: 'MyApi', // ... deployOptions: { tracingEnabled: true, accessLogFormat: AccessLogFormat.clf(), }, ...props,});AccessLogFormat được import từ aws-cdk-lib/aws-apigateway. Bất kỳ thứ gì bạn để trống sẽ giữ nguyên giá trị mặc định của construct — một định dạng JSON với các trường tiêu chuẩn.
Vai trò tài khoản được quản lý bởi module core/api/api-gateway-account, được khởi tạo bởi module API được tạo ra. Nó cấu hình tài khoản một cách idempotent và không bao giờ được đặt lại khi chạy terraform destroy.
Bạn có thể tùy chỉnh định dạng log truy cập bằng cách chỉnh sửa khối access_log_settings trên tài nguyên aws_api_gateway_stage trong module API được tạo ra.
Tích hợp
Phần tiêu đề “Tích hợp”Các cấu trúc CDK REST/HTTP API được cấu hình để cung cấp giao diện an toàn kiểu cho việc định nghĩa tích hợp cho từng hoạt động của bạn.
Tích hợp Mặc định
Phần tiêu đề “Tích hợp Mặc định”Bạn có thể sử dụng defaultIntegrations tĩnh để sử dụng mẫu mặc định, định nghĩa một hàm AWS Lambda riêng cho mỗi hoạt động:
new MyApi(this, 'MyApi', { integrations: MyApi.defaultIntegrations(this).build(),});Các module Terraform tự động sử dụng mẫu router với một hàm Lambda duy nhất. Không cần cấu hình thêm:
module "my_api" { source = "../../common/terraform/src/app/apis/my-api"
asset_bucket_name = module.asset_bucket.bucket_name
# The module automatically creates a single Lambda function # that handles all API operations tags = local.common_tags}Truy cập Tích hợp
Phần tiêu đề “Truy cập Tích hợp”Bạn có thể truy cập các hàm AWS Lambda cơ bản thông qua thuộc tính integrations của cấu trúc API, theo cách an toàn kiểu. Ví dụ, nếu API của bạn định nghĩa một hoạt động có tên sayHello và bạn cần thêm một số quyền cho hàm này, bạn có thể làm như sau:
const api = new MyApi(this, 'MyApi', { integrations: MyApi.defaultIntegrations(this).build(),});
// sayHello is typed to the operations defined in your APIapi.integrations.sayHello.handler.addToRolePolicy(new PolicyStatement({ effect: Effect.ALLOW, actions: [...], resources: [...],}));Nếu API của bạn sử dụng mẫu shared, Lambda router được chia sẻ được hiển thị dưới dạng api.integrations.$router:
const api = new MyApi(this, 'MyApi', { integrations: MyApi.defaultIntegrations(this).build(),});
api.integrations.$router.handler.addEnvironment('LOG_LEVEL', 'DEBUG');Với mẫu router của Terraform, chỉ có một hàm Lambda. Bạn có thể truy cập nó thông qua các đầu ra của module:
# Grant additional permissions to the single Lambda functionresource "aws_iam_role_policy" "additional_permissions" { name = "additional-api-permissions" role = module.my_api.lambda_execution_role_name
policy = jsonencode({ Version = "2012-10-17" Statement = [ { Effect = "Allow" Action = [ "s3:GetObject", "s3:PutObject" ] Resource = "arn:aws:s3:::my-bucket/*" } ] })}Tùy chỉnh Tùy chọn Mặc định
Phần tiêu đề “Tùy chỉnh Tùy chọn Mặc định”Nếu bạn muốn tùy chỉnh các tùy chọn được sử dụng khi tạo hàm Lambda cho mỗi tích hợp mặc định, bạn có thể sử dụng phương thức withDefaultOptions. Ví dụ, nếu bạn muốn tất cả các hàm Lambda của mình nằm trong một Vpc:
const vpc = new Vpc(this, 'Vpc', ...);
new MyApi(this, 'MyApi', { integrations: MyApi.defaultIntegrations(this) .withDefaultOptions({ vpc, }) .build(),});Cấu hình VPC đã được hỗ trợ bởi module được tạo — đặt enable_vpc cùng với vpc_id và subnet_ids, và module sẽ triển khai hàm Lambda vào VPC của bạn đằng sau một security group mà nó tạo cho bạn:
module "my_api" { source = "../../common/terraform/src/app/apis/my-api"
asset_bucket_name = module.asset_bucket.bucket_name
# VPC configuration enable_vpc = true vpc_id = aws_vpc.main.id subnet_ids = [aws_subnet.private_a.id, aws_subnet.private_b.id]
tags = local.common_tags}Đối với các tùy chọn mà module không hiển thị, hãy chỉnh sửa trực tiếp tài nguyên aws_lambda_function trong module Terraform được tạo.
Tùy chỉnh Tùy chọn Theo Hoạt động
Phần tiêu đề “Tùy chỉnh Tùy chọn Theo Hoạt động”Để tùy chỉnh các tùy chọn được sử dụng để tạo tích hợp mặc định cho các hoạt động cụ thể (mà không ảnh hưởng đến các hoạt động khác), bạn có thể sử dụng phương thức withOperationOptions. Ví dụ, nếu bạn muốn tăng thời gian chờ của hàm Lambda chỉ cho một hoạt động:
const api = new MyApi(this, 'MyApi', { integrations: MyApi.defaultIntegrations(this) .withOperationOptions({ sayHello: { timeout: Duration.seconds(60), }, }) .build(),});
// The selected operations remain default integrations, so they're still typed accordingly:api.integrations.sayHello.handler.addToRolePolicy(new PolicyStatement({ ... }));Các tùy chọn bạn chỉ định được hợp nhất với các tùy chọn tích hợp mặc định (và bất kỳ tùy chọn nào được đặt qua withDefaultOptions). Lưu ý rằng bạn không thể chỉ định tùy chọn cho các hoạt động mà bạn đã thay thế qua withOverrides, vì chúng không còn sử dụng tích hợp mặc định nữa.
Bạn sẽ gặp lỗi kiểu nếu cùng một hoạt động được nhắm mục tiêu bởi cả withOperationOptions và withOverrides, bất kể thứ tự bạn gọi chúng.
Để tùy chỉnh tùy chọn cho các hoạt động cụ thể với Terraform, bạn cần chỉnh sửa module Terraform được tạo để cấu hình các hàm Lambda riêng lẻ cho mỗi hoạt động (xem phần Tích hợp Rõ ràng bên dưới).
Ghi đè Tích hợp
Phần tiêu đề “Ghi đè Tích hợp”Bạn cũng có thể ghi đè tích hợp cho các hoạt động cụ thể bằng phương thức withOverrides. Mỗi ghi đè phải chỉ định thuộc tính integration được định kiểu cho cấu trúc tích hợp CDK phù hợp cho HTTP hoặc REST API. Phương thức withOverrides cũng an toàn kiểu. Ví dụ, nếu bạn muốn ghi đè API getDocumentation để trỏ đến tài liệu được lưu trữ bởi một trang web bên ngoài, bạn có thể đạt được điều này như sau:
new MyApi(this, 'MyApi', { integrations: MyApi.defaultIntegrations(this) .withOverrides({ getDocumentation: { integration: new HttpIntegration('https://example.com/documentation'), }, }) .build(),});Bạn cũng sẽ nhận thấy rằng tích hợp được ghi đè không còn có thuộc tính handler khi truy cập nó qua api.integrations.getDocumentation.
Bạn có thể thêm các thuộc tính bổ sung vào một tích hợp cũng sẽ được định kiểu tương ứng, cho phép các loại tích hợp khác được trừu tượng hóa nhưng vẫn an toàn kiểu, ví dụ nếu bạn đã tạo tích hợp S3 cho REST API và sau này muốn tham chiếu bucket cho một hoạt động cụ thể, bạn có thể làm như sau:
const storageBucket = new Bucket(this, 'Bucket', { ... });
const apiGatewayRole = new Role(this, 'ApiGatewayS3Role', { assumedBy: new ServicePrincipal('apigateway.amazonaws.com'),});
storageBucket.grantRead(apiGatewayRole);
const api = new MyApi(this, 'MyApi', { integrations: MyApi.defaultIntegrations(this) .withOverrides({ getFile: { bucket: storageBucket, integration: new AwsIntegration({ service: 's3', integrationHttpMethod: 'GET', path: `${storageBucket.bucketName}/{fileName}`, options: { credentialsRole: apiGatewayRole, requestParameters: { 'integration.request.path.fileName': 'method.request.querystring.fileName', }, integrationResponses: [{ statusCode: '200' }], }, }), options: { requestParameters: { 'method.request.querystring.fileName': true, }, methodResponses: [{ statusCode: '200', }], } }, }) .build(),});
// Later, perhaps in another file, you can access the bucket property we defined// in a type-safe mannerapi.integrations.getFile.bucket.grantRead(...);Ghi đè Authorizers
Phần tiêu đề “Ghi đè Authorizers”Bạn cũng có thể cung cấp options trong tích hợp của mình để ghi đè các tùy chọn phương thức cụ thể như authorizers, ví dụ nếu bạn muốn sử dụng xác thực Cognito cho hoạt động getDocumentation của mình:
new MyApi(this, 'MyApi', { integrations: MyApi.defaultIntegrations(this) .withOverrides({ getDocumentation: { integration: new HttpIntegration('https://example.com/documentation'), options: { authorizer: new CognitoUserPoolsAuthorizer(...) // for REST, or HttpUserPoolAuthorizer for an HTTP API } }, }) .build(),});Tích hợp Rõ ràng
Phần tiêu đề “Tích hợp Rõ ràng”Nếu bạn muốn, bạn có thể chọn không sử dụng tích hợp mặc định và thay vào đó cung cấp trực tiếp một tích hợp cho mỗi hoạt động. Điều này hữu ích nếu, ví dụ, mỗi hoạt động cần sử dụng một loại tích hợp khác nhau hoặc bạn muốn nhận lỗi kiểu khi thêm hoạt động mới:
new MyApi(this, 'MyApi', { integrations: { sayHello: { integration: new LambdaIntegration(...), }, getDocumentation: { integration: new HttpIntegration(...), }, },});Để có tích hợp rõ ràng theo hoạt động với Terraform, bạn nên sửa đổi module cụ thể cho ứng dụng được tạo để thay thế tích hợp proxy mặc định bằng các tích hợp cụ thể cho từng hoạt động.
Chỉnh sửa packages/common/terraform/src/app/apis/my-api/my-api.tf:
- Xóa các route proxy mặc định (ví dụ:
resource "aws_apigatewayv2_route" "proxy_routes") - Thay thế hàm Lambda duy nhất bằng các hàm riêng lẻ cho mỗi hoạt động
- Tạo các tích hợp và route cụ thể cho mỗi hoạt động, tái sử dụng cùng một gói ZIP:
# Remove the default single Lambda function resource "aws_lambda_function" "api_lambda" { s3_bucket = aws_s3_object.lambda_zip.bucket s3_key = aws_s3_object.lambda_zip.key s3_object_version = aws_s3_object.lambda_zip.version_id function_name = "MyApiHandler" role = aws_iam_role.lambda_execution_role.arn handler = "index.handler" runtime = "nodejs22.x" timeout = 30 # ... rest of configuration }
# Remove the default proxy integration resource "aws_apigatewayv2_integration" "lambda_integration" { api_id = module.http_api.api_id integration_type = "AWS_PROXY" integration_uri = aws_lambda_function.api_lambda.invoke_arn # ... rest of configuration }
# Remove the default proxy routes resource "aws_apigatewayv2_route" "proxy_routes" { for_each = toset(["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD"]) api_id = module.http_api.api_id route_key = "${each.key} /{proxy+}" target = "integrations/${aws_apigatewayv2_integration.lambda_integration.id}" # ... rest of configuration }
# Add individual Lambda functions for each operation using the same bundle resource "aws_lambda_function" "say_hello_handler" { s3_bucket = aws_s3_object.lambda_zip.bucket s3_key = aws_s3_object.lambda_zip.key s3_object_version = aws_s3_object.lambda_zip.version_id function_name = "MyApi-SayHello" role = aws_iam_role.lambda_execution_role.arn handler = "sayHello.handler" # Specific handler for this operation runtime = "nodejs22.x" timeout = 30 source_code_hash = data.archive_file.lambda_zip.output_base64sha256
tracing_config { mode = "Active" }
environment { variables = var.env }
tags = var.tags }
resource "aws_lambda_function" "get_documentation_handler" { s3_bucket = aws_s3_object.lambda_zip.bucket s3_key = aws_s3_object.lambda_zip.key s3_object_version = aws_s3_object.lambda_zip.version_id function_name = "MyApi-GetDocumentation" role = aws_iam_role.lambda_execution_role.arn handler = "getDocumentation.handler" # Specific handler for this operation runtime = "nodejs22.x" timeout = 30 source_code_hash = data.archive_file.lambda_zip.output_base64sha256
tracing_config { mode = "Active" }
environment { variables = var.env }
tags = var.tags }
# Add specific integrations for each operation resource "aws_apigatewayv2_integration" "say_hello_integration" { api_id = module.http_api.api_id integration_type = "AWS_PROXY" integration_uri = aws_lambda_function.say_hello_handler.invoke_arn payload_format_version = "2.0" timeout_milliseconds = 30000 }
resource "aws_apigatewayv2_integration" "get_documentation_integration" { api_id = module.http_api.api_id integration_type = "HTTP_PROXY" integration_uri = "https://example.com/documentation" integration_method = "GET" }
# Add specific routes for each operation resource "aws_apigatewayv2_route" "say_hello_route" { api_id = module.http_api.api_id route_key = "POST /sayHello" target = "integrations/${aws_apigatewayv2_integration.say_hello_integration.id}" authorization_type = "AWS_IAM" }
resource "aws_apigatewayv2_route" "get_documentation_route" { api_id = module.http_api.api_id route_key = "GET /documentation" target = "integrations/${aws_apigatewayv2_integration.get_documentation_integration.id}" authorization_type = "NONE" }
# Add Lambda permissions for each function resource "aws_lambda_permission" "say_hello_permission" { statement_id = "AllowExecutionFromAPIGateway-SayHello" action = "lambda:InvokeFunction" function_name = aws_lambda_function.say_hello_handler.function_name principal = "apigateway.amazonaws.com" source_arn = "${module.http_api.api_execution_arn}/*/*" }
resource "aws_lambda_permission" "get_documentation_permission" { statement_id = "AllowExecutionFromAPIGateway-GetDocumentation" action = "lambda:InvokeFunction" function_name = aws_lambda_function.get_documentation_handler.function_name principal = "apigateway.amazonaws.com" source_arn = "${module.http_api.api_execution_arn}/*/*" }# Remove the default single Lambda function resource "aws_lambda_function" "api_lambda" { s3_bucket = aws_s3_object.lambda_zip.bucket s3_key = aws_s3_object.lambda_zip.key s3_object_version = aws_s3_object.lambda_zip.version_id function_name = "MyApiHandler-${random_string.suffix.result}" role = aws_iam_role.lambda_execution_role.arn handler = "index.handler" runtime = "nodejs22.x" timeout = 30 # ... rest of configuration }
# Remove the default proxy integration resource "aws_api_gateway_integration" "lambda_integration" { rest_api_id = module.rest_api.api_id resource_id = aws_api_gateway_resource.proxy_resource.id http_method = aws_api_gateway_method.proxy_method.http_method integration_http_method = "POST" type = "AWS_PROXY" uri = aws_lambda_function.api_lambda.invoke_arn # ... rest of configuration }
# Remove the default catch-all proxy method resource "aws_api_gateway_method" "proxy_method" { rest_api_id = module.rest_api.api_id resource_id = aws_api_gateway_resource.proxy_resource.id http_method = "ANY" # ... rest of configuration }
# Add individual Lambda functions for each operation using the same bundle resource "aws_lambda_function" "say_hello_handler" { s3_bucket = aws_s3_object.lambda_zip.bucket s3_key = aws_s3_object.lambda_zip.key s3_object_version = aws_s3_object.lambda_zip.version_id function_name = "MyApi-SayHello" role = aws_iam_role.lambda_execution_role.arn handler = "sayHello.handler" # Specific handler for this operation runtime = "nodejs22.x" timeout = 30 source_code_hash = data.archive_file.lambda_zip.output_base64sha256
tracing_config { mode = "Active" }
environment { variables = var.env }
tags = var.tags }
resource "aws_lambda_function" "get_documentation_handler" { s3_bucket = aws_s3_object.lambda_zip.bucket s3_key = aws_s3_object.lambda_zip.key s3_object_version = aws_s3_object.lambda_zip.version_id function_name = "MyApi-GetDocumentation" role = aws_iam_role.lambda_execution_role.arn handler = "getDocumentation.handler" # Specific handler for this operation runtime = "nodejs22.x" timeout = 30 source_code_hash = data.archive_file.lambda_zip.output_base64sha256
tracing_config { mode = "Active" }
environment { variables = var.env }
tags = var.tags }
# Add specific resources and methods for each operation resource "aws_api_gateway_resource" "say_hello_resource" { rest_api_id = module.rest_api.api_id parent_id = module.rest_api.api_root_resource_id path_part = "sayHello" }
resource "aws_api_gateway_method" "say_hello_method" { rest_api_id = module.rest_api.api_id resource_id = aws_api_gateway_resource.say_hello_resource.id http_method = "POST" authorization = "AWS_IAM" }
resource "aws_api_gateway_integration" "say_hello_integration" { rest_api_id = module.rest_api.api_id resource_id = aws_api_gateway_resource.say_hello_resource.id http_method = aws_api_gateway_method.say_hello_method.http_method
integration_http_method = "POST" type = "AWS_PROXY" uri = aws_lambda_function.say_hello_handler.invoke_arn }
resource "aws_api_gateway_resource" "get_documentation_resource" { rest_api_id = module.rest_api.api_id parent_id = module.rest_api.api_root_resource_id path_part = "documentation" }
resource "aws_api_gateway_method" "get_documentation_method" { rest_api_id = module.rest_api.api_id resource_id = aws_api_gateway_resource.get_documentation_resource.id http_method = "GET" authorization = "NONE" }
resource "aws_api_gateway_integration" "get_documentation_integration" { rest_api_id = module.rest_api.api_id resource_id = aws_api_gateway_resource.get_documentation_resource.id http_method = aws_api_gateway_method.get_documentation_method.http_method
integration_http_method = "GET" type = "HTTP" uri = "https://example.com/documentation" }
# Update deployment to depend on new integrations~ resource "aws_api_gateway_deployment" "api_deployment" { rest_api_id = module.rest_api.api_id
depends_on = [ aws_api_gateway_integration.lambda_integration, aws_api_gateway_integration.say_hello_integration, aws_api_gateway_integration.get_documentation_integration, ]
lifecycle { create_before_destroy = true }
triggers = { redeployment = sha1(jsonencode([ aws_api_gateway_integration.say_hello_integration, aws_api_gateway_integration.get_documentation_integration, ])) } }
# Add Lambda permissions for each function resource "aws_lambda_permission" "say_hello_permission" { statement_id = "AllowExecutionFromAPIGateway-SayHello" action = "lambda:InvokeFunction" function_name = aws_lambda_function.say_hello_handler.function_name principal = "apigateway.amazonaws.com" source_arn = "${module.rest_api.api_execution_arn}/*/*" }
resource "aws_lambda_permission" "get_documentation_permission" { statement_id = "AllowExecutionFromAPIGateway-GetDocumentation" action = "lambda:InvokeFunction" function_name = aws_lambda_function.get_documentation_handler.function_name principal = "apigateway.amazonaws.com" source_arn = "${module.rest_api.api_execution_arn}/*/*" }Mẫu Tích hợp
Phần tiêu đề “Mẫu Tích hợp”Các cấu trúc API CDK được tạo hỗ trợ hai mẫu tích hợp:
isolatedtạo một hàm Lambda cho mỗi hoạt động. Đây là mặc định cho các API được tạo.sharedtạo một Lambda router mặc định duy nhất và tái sử dụng nó cho mọi hoạt động trừ khi bạn ghi đè các tích hợp cụ thể.
isolated cung cấp cho bạn quyền và cấu hình chi tiết hơn cho mỗi hoạt động. shared giảm sự lan tràn của Lambda và tích hợp API Gateway trong khi vẫn cho phép ghi đè có chọn lọc.
Ví dụ, đặt pattern thành 'shared' tạo một hàm duy nhất thay vì một hàm cho mỗi tích hợp:
export class MyApi<...> extends ... {
public static defaultIntegrations = (scope: Construct) => { ... return IntegrationBuilder.rest({ pattern: 'shared', ... }); };}Các module Terraform tự động sử dụng mẫu router - đây là cách tiếp cận mặc định và duy nhất được hỗ trợ. Module được tạo tạo một hàm Lambda duy nhất xử lý tất cả các hoạt động API.
Bạn chỉ cần khởi tạo module mặc định để có mẫu router:
# Default router pattern - single Lambda function for all operationsmodule "my_api" { source = "../../common/terraform/src/app/apis/my-api"
asset_bucket_name = module.asset_bucket.bucket_name
# Single Lambda function handles all operations automatically tags = local.common_tags}Tạo mã
Phần tiêu đề “Tạo mã”Vì các thao tác được định nghĩa trong Smithy, chúng tôi sử dụng tạo mã để cung cấp metadata cho CDK construct cho các tích hợp an toàn kiểu.
Một target generate:<ApiName>-metadata được thêm vào project.json của common constructs để tạo điều kiện cho việc tạo mã này, xuất ra một tệp như packages/common/constructs/src/generated/my-api/metadata.gen.ts. Vì điều này được tạo tại thời điểm build, nó bị bỏ qua trong kiểm soát phiên bản.
Cấp quyền truy cập (chỉ IAM)
Phần tiêu đề “Cấp quyền truy cập (chỉ IAM)”Nếu bạn chọn xác thực IAM, bạn có thể sử dụng phương thức grantInvokeAccess để cấp quyền truy cập vào API của bạn:
api.grantInvokeAccess(myIdentityPool.authenticatedRole);# Create an IAM policy to allow invoking the APIresource "aws_iam_policy" "api_invoke_policy" { name = "MyApiInvokePolicy" description = "Policy to allow invoking the Smithy API"
policy = jsonencode({ Version = "2012-10-17" Statement = [ { Effect = "Allow" Action = "execute-api:Invoke" Resource = "${module.my_api.api_execution_arn}/*/*" } ] })}
# Attach the policy to an IAM roleresource "aws_iam_role_policy_attachment" "api_invoke_access" { role = aws_iam_role.authenticated_user_role.name policy_arn = aws_iam_policy.api_invoke_policy.arn}Gọi Smithy API của bạn
Phần tiêu đề “Gọi Smithy API của bạn”Để gọi API của bạn từ một website React, bạn có thể sử dụng trình tạo connection, cung cấp tạo client an toàn kiểu từ mô hình Smithy của bạn.
Kết nối
Phần tiêu đề “Kết nối”Sử dụng trình tạo connection để tích hợp dự án này với các dự án khác trong workspace của bạn. Các kết nối sau liên quan đến dự án này: