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

tRPC

Filter this guidePick generator option values to hide sections that don't apply.

tRPC là một framework để xây dựng API trong TypeScript với tính an toàn kiểu từ đầu đến cuối. Sử dụng tRPC, các cập nhật đối với đầu vào và đầu ra của các thao tác API được phản ánh ngay lập tức trong mã client và hiển thị trong IDE của bạn mà không cần rebuild dự án.

Trình tạo API tRPC tạo một API tRPC mới với cấu hình cơ sở hạ tầng AWS CDK hoặc Terraform. Backend được tạo sử dụng AWS Lambda để triển khai serverless, được expose thông qua AWS API Gateway API, và bao gồm xác thực schema bằng Zod. Nó thiết lập AWS Lambda Powertools để quan sát, bao gồm logging, tracing AWS X-Ray và Cloudwatch Metrics.

Bạn có thể tạo một API tRPC mới theo hai cách:

Terminal window
pnpm nx g @aws/nx-plugin:ts#api --framework=trpc
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 --framework=trpc --dry-run
Tham sốKiểuMặc địnhMô tả
name Bắt buộcstring-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 | smithytrpcFramework 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 | sharedisolatedCách thức tạo API Gateway integrations cho API. Chọn giữa isolated (mặc định) và shared.
auth iam | cognito | customiamPhươ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 stringpackagesThư 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 | terraforminheritNhà 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 | nonerest-lambdaLoại hạ tầng được sử dụng để triển khai API này.
preferInstallDependencies booleantrueCó 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.

Generator sẽ tạo cấu trúc dự án sau trong thư mục <directory>/<api-name>:

  • Thư mụcsrc
    • init.ts Backend tRPC initialisation
    • handler.ts Lambda handler entrypoint
    • router.ts tRPC router definition
    • Thư mụcschema Schema definitions using Zod
      • echo.ts Example definitions for the input and output of the “echo” procedure
      • z-async-iterable.ts Zod helper for subscriptions (REST API only)
    • Thư mụcprocedures Procedures (or operations) exposed by your API
      • echo.ts Example procedure
    • Thư mụcmiddleware
      • error.ts Middleware for error handling
      • logger.ts middleware for configuring AWS Powertools for Lambda logging
      • tracer.ts middleware for configuring AWS Powertools for Lambda tracing
      • metrics.ts middleware for configuring AWS Powertools for Lambda metrics
    • local-server.ts tRPC standalone adapter entrypoint for local development server
    • Thư mụcclient
      • index.ts Type-safe client for machine-to-machine API calls
  • tsconfig.json TypeScript configuration
  • package.json Project manifest defining the project’s package name and dependencies
  • project.json Project configuration and build targets

Vì generator này cung cấp infrastructure as code 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 constructs hoặc Terraform modules liên quan.

Dự án infrastructure as code chung được cấu trúc như sau:

  • Thư mụcpackages/common/constructs
    • Thư mụcsrc
      • Thư mụcapp/ Constructs for infrastructure specific to a project/generator
      • Thư mụccore/ Generic constructs which are reused by constructs in app
      • index.ts Entry point exporting constructs from app
    • project.json Project build targets and configuration

Để triển khai API của bạn, các tệp sau được tạo ra:

  • Thư mụcpackages/common/constructs/src
    • Thư mụcapp
      • Thư mụcapis
        • <project-name>.ts CDK construct for deploying your API
    • Thư mụccore
      • Thư mụcapi
        • http-api.ts CDK construct for deploying an HTTP API (if you selected to deploy an HTTP API)
        • rest-api.ts CDK construct for deploying a REST API (if you selected to deploy a REST API)
        • utils.ts Utilities for the API constructs

Ứng dụng được triển khai có kiến trúc như sau:

ClientWAFAPI Gateway(REST API)LambdaCloudWatch(Logs, Metrics)X-Ray(Traces)

REST APIs bao gồm một AWS WAFv2 Web ACL đặt trước API Gateway stage với bộ quy tắc mặc định được quản lý bởi AWS được kích hoạt.

Ở cấp độ cao, các API tRPC bao gồm một router ủy quyền các request đến các procedure cụ thể. Mỗi procedure có một đầu vào và đầu ra, được định nghĩa dưới dạng schema Zod.

Thư mục src/schema chứa các kiểu được chia sẻ giữa mã client và server của bạn. Trong package này, các kiểu này được định nghĩa bằng Zod, một thư viện khai báo và xác thực schema ưu tiên TypeScript.

Một schema ví dụ có thể trông như sau:

import { z } from 'zod';
// Schema definition
export const UserSchema = z.object({
name: z.string(),
height: z.number(),
dateOfBirth: z.string().datetime(),
});
// Corresponding TypeScript type
export type User = z.TypeOf<typeof UserSchema>;

Với schema trên, kiểu User tương đương với TypeScript sau:

interface User {
name: string;
height: number;
dateOfBirth: string;
}

Schema được chia sẻ bởi cả mã server và client, cung cấp một nơi duy nhất để cập nhật khi thực hiện thay đổi đối với các cấu trúc được sử dụng trong API của bạn.

Schema được tự động xác thực bởi API tRPC của bạn tại runtime, giúp tiết kiệm việc tạo logic xác thực tùy chỉnh thủ công trong backend của bạn.

Zod cung cấp các tiện ích mạnh mẽ để kết hợp hoặc dẫn xuất schema như .merge, .pick, .omit và nhiều hơn nữa. Bạn có thể tìm thêm thông tin trên trang tài liệu Zod.

Router tRPC của bạn được định nghĩa trong src/router.ts, đăng ký tất cả các procedure. Mỗi procedure định nghĩa đầu vào, đầu ra và triển khai mong đợi. Điểm vào Lambda handler nằm trong src/handler.ts, chuyển tiếp các request đến router của bạn.

Router mẫu được tạo cho bạn có một thao tác duy nhất, gọi là echo:

import { echo } from './procedures/echo.js';
export const appRouter = router({
echo,
});

Procedure echo ví dụ được tạo cho bạn trong src/procedures/echo.ts:

export const echo = publicProcedure
.input(EchoInputSchema)
.output(EchoOutputSchema)
.query((opts) => ({ message: opts.input.message }));

Để phân tích phần trên:

  • publicProcedure định nghĩa một phương thức công khai trên API, bao gồm middleware được thiết lập trong src/middleware. Middleware này bao gồm tích hợp AWS Lambda Powertools cho logging, tracing và metrics.
  • input chấp nhận một schema Zod định nghĩa đầu vào mong đợi cho thao tác. Các request được gửi cho thao tác này được tự động xác thực với schema này.
  • output chấp nhận một schema Zod định nghĩa đầu ra mong đợi cho thao tác. Bạn sẽ thấy lỗi kiểu trong triển khai của mình nếu bạn không trả về đầu ra phù hợp với schema.
  • query chấp nhận một hàm định nghĩa triển khai cho API của bạn. Triển khai này nhận opts, chứa input được truyền cho thao tác của bạn, cũng như ngữ cảnh khác được thiết lập bởi middleware, có sẵn trong opts.ctx. Hàm được truyền cho query phải trả về một đầu ra phù hợp với schema output.

Việc sử dụng query để định nghĩa triển khai cho biết rằng thao tác không thay đổi dữ liệu. Sử dụng điều này để định nghĩa các phương thức truy xuất dữ liệu. Để triển khai một thao tác thay đổi dữ liệu, hãy sử dụng phương thức mutation thay thế.

Nếu bạn thêm một procedure mới, hãy đảm bảo bạn đăng ký nó bằng cách thêm nó vào router trong src/router.ts.

infra = rest-lambda

tRPC subscriptions cho phép bạn stream dữ liệu từ server đến client bằng Server-Sent Events (SSE). Khi bạn chọn rest-lambda làm loại compute, generator tự động cấu hình cơ sở hạ tầng cần thiết cho streaming, cũng như một streaming Lambda handler và helper schema ZodAsyncIterable.

Để định nghĩa một subscription procedure, sử dụng phương thức .subscription với một hàm async generator. Sử dụng helper ZodAsyncIterable từ src/schema/z-async-iterable.ts để định nghĩa schema đầu ra:

import { publicProcedure } from '../init.js';
import { z } from 'zod';
import { ZodAsyncIterable } from '../schema/z-async-iterable.js';
const InputSchema = z.object({ query: z.string() });
const ChunkSchema = z.object({ text: z.string() });
export const myStream = publicProcedure
.input(InputSchema)
.output(
ZodAsyncIterable({
yield: ChunkSchema,
}),
)
.subscription(async function* (opts) {
// Yield data to the client as it becomes available
for (const chunk of await getResults(opts.input.query)) {
yield { text: chunk };
}
});

Đăng ký subscription trong router của bạn giống như bất kỳ procedure nào khác:

export const appRouter = router({
echo,
myStream,
});

Cơ sở hạ tầng được tạo sử dụng một streaming Lambda handler với ResponseTransferMode.STREAM trong API Gateway cho tất cả các thao tác REST API, cho phép subscriptions hoạt động cùng với các query và mutation thông thường.

Trong triển khai của bạn, bạn có thể trả về các response lỗi cho client bằng cách throw một TRPCError. Chúng chấp nhận một code cho biết loại lỗi, ví dụ:

throw new TRPCError({
code: 'NOT_FOUND',
message: 'The requested resource could not be found',
});

Khi API của bạn phát triển, bạn có thể muốn nhóm các thao tác liên quan lại với nhau.

Bạn có thể nhóm các thao tác lại với nhau bằng cách sử dụng các router lồng nhau, ví dụ:

import { getUser } from './procedures/users/get.js';
import { listUsers } from './procedures/users/list.js';
const appRouter = router({
users: router({
get: getUser,
list: listUsers,
}),
...
})

Client sau đó nhận được nhóm thao tác này, ví dụ gọi thao tác listUsers trong trường hợp này có thể trông như sau:

client.users.list.query();

Logger AWS Lambda Powertools được cấu hình trong src/middleware/logger.ts, và có thể được truy cập trong triển khai API thông qua opts.ctx.logger. Bạn có thể sử dụng điều này để log vào CloudWatch Logs, và/hoặc kiểm soát các giá trị bổ sung để bao gồm trong mọi thông báo log có cấu trúc. Ví dụ:

export const echo = publicProcedure
.input(...)
.output(...)
.query(async (opts) => {
opts.ctx.logger.info('Operation called with input', opts.input);
return ...;
});

Để biết thêm thông tin về logger, vui lòng tham khảo tài liệu AWS Lambda Powertools Logger.

AWS Lambda Powertools metrics được cấu hình trong src/middleware/metrics.ts, và có thể được truy cập trong triển khai API thông qua opts.ctx.metrics. Bạn có thể sử dụng điều này để ghi lại metrics trong CloudWatch mà không cần import và sử dụng AWS SDK, ví dụ:

export const echo = publicProcedure
.input(...)
.output(...)
.query(async (opts) => {
opts.ctx.metrics.addMetric('Invocations', 'Count', 1);
return ...;
});

Để biết thêm thông tin, vui lòng tham khảo tài liệu AWS Lambda Powertools Metrics.

Tracer AWS Lambda Powertools được cấu hình trong src/middleware/tracer.ts, và có thể được truy cập trong triển khai API thông qua opts.ctx.tracer. Bạn có thể sử dụng điều này để thêm traces với AWS X-Ray để cung cấp thông tin chi tiết về hiệu suất và luồng của các request API. Ví dụ:

export const echo = publicProcedure
.input(...)
.output(...)
.query(async (opts) => {
const subSegment = opts.ctx.tracer.getSegment()!.addNewSubsegment('MyAlgorithm');
// ... my algorithm logic to capture
subSegment.close();
return ...;
});

Để biết thêm thông tin, vui lòng tham khảo tài liệu AWS Lambda Powertools Tracer.

Bạn có thể thêm các giá trị bổ sung vào ngữ cảnh được cung cấp cho các procedure bằng cách triển khai middleware.

Ví dụ, hãy triển khai một số middleware để trích xuất một số chi tiết về người dùng gọi từ API của chúng ta trong src/middleware/identity.ts.

auth = iam

Ví dụ này hướng dẫn về identity middleware cho xác thực IAM. Chúng ta tra cứu người gọi trong Cognito bằng cách sử dụng sub được trích xuất từ sự kiện API Gateway.

Đầu tiên, chúng ta định nghĩa những gì chúng ta sẽ thêm vào ngữ cảnh:

export interface IIdentityContext {
identity?: {
sub: string;
username: string;
};
}

Lưu ý rằng chúng ta định nghĩa một thuộc tính tùy chọn bổ sung cho ngữ cảnh. tRPC quản lý việc đảm bảo rằng điều này được định nghĩa trong các procedure đã cấu hình middleware này một cách chính xác.

Tiếp theo, chúng ta sẽ triển khai middleware. Nó có cấu trúc sau:

export const createIdentityPlugin = () => {
const t = initTRPC.context<...>().create();
return t.procedure.use(async (opts) => {
// Add logic here to run before the procedure
const response = await opts.next(...);
// Add logic here to run after the procedure
return response;
});
};

Trong trường hợp của chúng ta, chúng ta muốn trích xuất chi tiết về người dùng Cognito đang gọi. Chúng ta sẽ làm điều đó bằng cách trích xuất ID chủ thể của người dùng (hoặc “sub”) từ sự kiện API Gateway, và truy xuất chi tiết người dùng từ Cognito. Triển khai khác nhau tùy thuộc vào việc sự kiện được cung cấp cho hàm của chúng ta bởi REST API hay HTTP API:

import { CognitoIdentityProvider } from '@aws-sdk/client-cognito-identity-provider';
import { initTRPC, TRPCError } from '@trpc/server';
import { CreateAWSLambdaContextOptions } from '@trpc/server/adapters/aws-lambda';
import { APIGatewayProxyEvent } from 'aws-lambda';
export interface IIdentityContext {
identity?: {
sub: string;
username: string;
};
}
export const createIdentityPlugin = () => {
const t = initTRPC.context<IIdentityContext & CreateAWSLambdaContextOptions<APIGatewayProxyEvent>>().create();
const cognito = new CognitoIdentityProvider();
return t.procedure.use(async (opts) => {
const cognitoAuthenticationProvider = opts.ctx.event.requestContext?.identity?.cognitoAuthenticationProvider;
let sub: string | undefined = undefined;
if (cognitoAuthenticationProvider) {
const providerParts = cognitoAuthenticationProvider.split(':');
sub = providerParts[providerParts.length - 1];
}
if (!sub) {
throw new TRPCError({
code: 'FORBIDDEN',
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 TRPCError({
code: 'FORBIDDEN',
message: `No user found with subjectId ${sub}`,
});
}
// Provide the identity to other procedures in the context
return await opts.next({
ctx: {
...opts.ctx,
identity: {
sub,
username: Users[0].Username!,
},
},
});
});
};
auth = cognito

Khi bạn triển khai với auth: 'cognito', API Gateway Cognito 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 Lambda event. Middleware của chúng ta chỉ đọc các claim đó — không cần thêm lời gọi AWS SDK, không cần xác minh JWT thủ công.

Đầu tiên, chúng ta định nghĩa những gì chúng ta sẽ thêm vào context:

export interface IIdentityContext {
identity?: {
sub: string;
username: string;
};
}

Lưu ý rằng chúng ta định nghĩa một thuộc tính tùy chọn bổ sung cho context. tRPC quản lý đảm bảo rằng điều này được định nghĩa trong các procedure đã cấu hình middleware này một cách chính xác.

Tiếp theo, chính middleware đó:

import { initTRPC, TRPCError } from '@trpc/server';
import { CreateAWSLambdaContextOptions } from '@trpc/server/adapters/aws-lambda';
import { APIGatewayProxyEvent } from 'aws-lambda';
export interface IIdentityContext {
identity?: {
sub: string;
username: string;
};
}
export const createIdentityPlugin = () => {
const t = initTRPC
.context<IIdentityContext & CreateAWSLambdaContextOptions<APIGatewayProxyEvent>>()
.create();
return t.procedure.use(async (opts) => {
const claims = opts.ctx.event.requestContext?.authorizer?.claims as
| Record<string, string>
| undefined;
const sub = claims?.sub;
const username = claims?.username;
if (!sub || !username) {
throw new TRPCError({
code: 'FORBIDDEN',
message: 'Unable to determine calling user',
});
}
return await opts.next({
ctx: {
...opts.ctx,
identity: {
sub,
username,
},
},
});
});
};

Sau đó bạn có thể kết hợp plugin vào bất kỳ procedure nào cần identity của người gọi:

import { publicProcedure } from '../init.js';
import { createIdentityPlugin } from '../middleware/identity.js';
import { z } from 'zod';
export const me = publicProcedure
.concat(createIdentityPlugin())
.output(z.object({ sub: z.string(), username: z.string() }))
.query(({ ctx }) => ({
sub: ctx.identity!.sub,
username: ctx.identity!.username,
}));

Trình tạo API tRPC tạo infrastructure as code CDK hoặc Terraform dựa trên iac đã chọn của bạn. Bạn có thể sử dụng điều này để triển khai API tRPC của mình.

Construct CDK để triển khai API của bạn nằm trong thư mục common/constructs. Bạn có thể sử dụng điều này trong một ứng dụng CDK, ví dụ:

auth = iam | custom
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(),
});
}
}
auth = cognito
import { MyApi, UserIdentity } from '@my-scope/common-constructs';
export class ExampleStack extends Stack {
constructor(scope: Construct, id: string) {
// Add the api to your stack
const identity = new UserIdentity(this, 'Identity');
const api = new MyApi(this, 'MyApi', {
integrations: MyApi.defaultIntegrations(this).build(),
identity,
});
}
}

Construct UserIdentity có thể được tạo bằng generator ts#website#auth.

Điều này thiết lập cơ sở hạ tầng API của bạn, bao gồm AWS API Gateway REST hoặc HTTP API, các hàm AWS Lambda cho logic nghiệp vụ, và xác thực dựa trên phương thức auth đã chọn của bạn.

infra = rest-lambda

Đố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 (AWSManagedRulesCommonRuleSetAWSManagedRulesKnownBadInputsRuleSet), 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,
});
infra = rest-lambda

Đố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:

packages/common/constructs/src/app/apis/my-api.ts
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.

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.

Các cấu trúc CDK cung cấp hỗ trợ tích hợp an toàn kiểu đầy đủ như mô tả bên dưới.

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

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 API
api.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');

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

Để 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ả withOperationOptionswithOverrides, bất kể thứ tự bạn gọi chúng.

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 manner
api.integrations.getFile.bucket.grantRead(...);

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

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ác cấu trúc API CDK được tạo hỗ trợ hai mẫu tích hợp:

  • isolated tạo một hàm Lambda cho mỗi hoạt động. Đây là mặc định cho các API được tạo.
  • shared tạ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:

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

Bạn có thể cấp quyền truy cập vào API của mình như sau:

api.grantInvokeAccess(myIdentityPool.authenticatedRole);

Generator tự động cấu hình một target bundle sử dụng Rolldown để tạo gói triển khai:

Terminal window
pnpm 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.

Bạn có thể sử dụng target serve để chạy một server cục bộ cho API của mình, ví dụ:

Terminal window
pnpm nx serve my-api

Điểm vào cho server cục bộ là src/local-server.ts.

Điều này sẽ tự động reload khi bạn thực hiện thay đổi đối với API của mình.

Bạn có thể tạo một tRPC client để gọi API của mình theo cách an toàn kiểu. Nếu bạn đang gọi API tRPC của mình từ một backend khác, bạn có thể sử dụng client trong src/client/index.ts, ví dụ:

import { createMyApiClient } from '@my-scope/my-api';
const client = createMyApiClient({ url: 'https://my-api-url.example.com/' });
await client.echo.query({ message: 'Hello world!' });

Nếu bạn đang gọi API của mình từ một website React, hãy xem xét sử dụng generator Connection để cấu hình client.

Để biết thêm thông tin về tRPC, vui lòng tham khảo tài liệu tRPC.

Sử dụng generator 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 connection sau liên quan đến dự án này:

tRPC
React to tRPCCall a tRPC API from a React website
tRPCAmazon Aurora
tRPC API to Relational DatabaseConnect a tRPC API to an Aurora relational database
tRPCAmazon DynamoDB
tRPC API to TypeScript DynamoDBConnect a tRPC API to a DynamoDB table