@aws/nx-plugin-mcp 0.119.0 → 0.121.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/aws-nx-mcp.js +23 -35
- package/docs/guides/astro-docs.mdx +142 -0
- package/docs/guides/connection/py-agent-a2a.mdx +105 -0
- package/docs/guides/connection/py-agent-mcp.mdx +147 -0
- package/docs/guides/connection/react-agui.mdx +240 -0
- package/docs/guides/connection/react-fastapi.mdx +1476 -0
- package/docs/guides/connection/react-py-agent.mdx +198 -0
- package/docs/guides/connection/react-smithy.mdx +1355 -0
- package/docs/guides/connection/react-trpc.mdx +447 -0
- package/docs/guides/connection/react-ts-agent.mdx +198 -0
- package/docs/guides/connection/smithy-rdb.mdx +161 -0
- package/docs/guides/connection/trpc-rdb.mdx +127 -0
- package/docs/guides/connection/ts-agent-a2a.mdx +106 -0
- package/docs/guides/connection/ts-agent-mcp.mdx +144 -0
- package/docs/guides/connection/ts-agent-rdb.mdx +141 -0
- package/docs/guides/connection/ts-mcp-server-rdb.mdx +135 -0
- package/docs/guides/connection.mdx +126 -0
- package/docs/guides/docker-bundling.mdx +403 -0
- package/docs/guides/fastapi.mdx +509 -0
- package/docs/guides/license.mdx +293 -0
- package/docs/guides/nx-generator.mdx +588 -0
- package/docs/guides/py-agent.mdx +483 -0
- package/docs/guides/py-mcp-server.mdx +161 -0
- package/docs/guides/python-lambda-function.mdx +207 -0
- package/docs/guides/python-project.mdx +228 -0
- package/docs/guides/react-website-auth.mdx +216 -0
- package/docs/guides/react-website.mdx +421 -0
- package/docs/guides/runtime-config.mdx +312 -0
- package/docs/guides/terraform-project.mdx +317 -0
- package/docs/guides/trpc.mdx +816 -0
- package/docs/guides/ts-agent.mdx +436 -0
- package/docs/guides/ts-lambda-function.mdx +218 -0
- package/docs/guides/ts-mcp-server.mdx +169 -0
- package/docs/guides/ts-nx-plugin.mdx +159 -0
- package/docs/guides/ts-rdb.mdx +759 -0
- package/docs/guides/ts-smithy-api.mdx +661 -0
- package/docs/guides/typescript-infrastructure.mdx +408 -0
- package/docs/guides/typescript-project.mdx +312 -0
- package/docs/guides/workspace.mdx +181 -0
- package/docs/snippets/agent/architecture.mdx +72 -0
- package/docs/snippets/agent/bedrock-deployment.mdx +172 -0
- package/docs/snippets/agent/runtime-arn.mdx +64 -0
- package/docs/snippets/api/api-architecture.mdx +93 -0
- package/docs/snippets/api/api-choice-note.mdx +6 -0
- package/docs/snippets/api/cors-configuration-cdk-note.mdx +25 -0
- package/docs/snippets/api/cors-configuration-terraform-note.mdx +28 -0
- package/docs/snippets/api/shared-constructs.mdx +38 -0
- package/docs/snippets/api/type-safe-api-integrations.mdx +643 -0
- package/docs/snippets/api/waf-configuration.mdx +37 -0
- package/docs/snippets/connection/a2a-infrastructure.mdx +63 -0
- package/docs/snippets/connection/lambda-rdb-ssl-requirements.mdx +40 -0
- package/docs/snippets/connection/mcp-server-rdb-ssl-requirements.mdx +35 -0
- package/docs/snippets/connection/rdb-api-infrastructure.mdx +72 -0
- package/docs/snippets/connection/react-agent-infrastructure.mdx +61 -0
- package/docs/snippets/connection/strands-agent-rdb-ssl-requirements.mdx +35 -0
- package/docs/snippets/lambda-function/architecture.mdx +36 -0
- package/docs/snippets/lambda-function/deploying-your-function.mdx +118 -0
- package/docs/snippets/mcp/architecture.mdx +58 -0
- package/docs/snippets/mcp/assistant-docs.mdx +10 -0
- package/docs/snippets/mcp/bedrock-deployment.mdx +167 -0
- package/docs/snippets/mcp/config.mdx +13 -0
- package/docs/snippets/mcp/configuration-py.mdx +42 -0
- package/docs/snippets/mcp/configuration-ts.mdx +53 -0
- package/docs/snippets/mcp/observability.mdx +8 -0
- package/docs/snippets/mcp/shared-constructs.mdx +32 -0
- package/docs/snippets/pdk-migration/example/01-migrate-api.mdx +602 -0
- package/docs/snippets/pdk-migration/example/02-migrate-website.mdx +915 -0
- package/docs/snippets/pdk-migration/example/03-migrate-infra.mdx +161 -0
- package/docs/snippets/pdk-migration/example/04-deploy.mdx +229 -0
- package/docs/snippets/pdk-migration/faq/aws-arch.mdx +17 -0
- package/docs/snippets/pdk-migration/faq/cdk-graph.mdx +29 -0
- package/docs/snippets/pdk-migration/faq/infrastructure-python-java.mdx +19 -0
- package/docs/snippets/pdk-migration/faq/pdk-nag.mdx +15 -0
- package/docs/snippets/pdk-migration/faq/pipeline.mdx +15 -0
- package/docs/snippets/pdk-migration/faq/type-safe-api.mdx +310 -0
- package/docs/snippets/pdk-migration/faq/use-of-projen.mdx +15 -0
- package/docs/snippets/prerequisites.mdx +20 -0
- package/docs/snippets/required-prerequisites.mdx +12 -0
- package/docs/snippets/shared-constructs.mdx +40 -0
- package/docs/snippets/tools/acurl.mdx +73 -0
- package/docs/snippets/ts-bundle.mdx +14 -0
- package/package.json +1 -1
- package/src/py/agent/schema.json +1 -1
- package/src/py/fast-api/schema.json +2 -2
- package/src/py/mcp-server/schema.json +1 -1
- package/src/smithy/ts/api/schema.json +2 -2
- package/src/trpc/backend/schema.json +2 -2
- package/src/ts/agent/schema.json +1 -1
- package/src/ts/mcp-server/schema.json +1 -1
|
@@ -0,0 +1,816 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: tRPC
|
|
3
|
+
description: Reference documentation for tRPC
|
|
4
|
+
generator: ts#trpc-api
|
|
5
|
+
---
|
|
6
|
+
import { FileTree, Tabs, TabItem } from '@astrojs/starlight/components';
|
|
7
|
+
import Link from '@components/link.astro';
|
|
8
|
+
import RunGenerator from '@components/run-generator.astro';
|
|
9
|
+
import GeneratorParameters from '@components/generator-parameters.astro';
|
|
10
|
+
import NxCommands from '@components/nx-commands.astro';
|
|
11
|
+
import Infrastructure from '@components/infrastructure.astro';
|
|
12
|
+
import Snippet from '@components/snippet.astro';
|
|
13
|
+
import OptionFilter from '@components/option-filter.astro';
|
|
14
|
+
|
|
15
|
+
[tRPC](https://trpc.io/) is a framework for building APIs in TypeScript with end-to-end type safety. Using tRPC, updates to API operation inputs and outputs are immediately reflected in client code and are visible in your IDE without the need to rebuild your project.
|
|
16
|
+
|
|
17
|
+
The tRPC API generator creates a new tRPC API with AWS CDK or Terraform infrastructure setup. The generated backend uses AWS Lambda for serverless deployment, exposed via an AWS API Gateway API, and includes schema validation using [Zod](https://zod.dev/). It sets up [AWS Lambda Powertools](https://docs.powertools.aws.dev/lambda/typescript/latest/) for observability, including logging, AWS X-Ray tracing and Cloudwatch Metrics.
|
|
18
|
+
|
|
19
|
+
## Usage
|
|
20
|
+
|
|
21
|
+
### Generate a tRPC API
|
|
22
|
+
|
|
23
|
+
You can generate a new tRPC API in two ways:
|
|
24
|
+
|
|
25
|
+
<RunGenerator generator="ts#trpc-api" />
|
|
26
|
+
|
|
27
|
+
### Options
|
|
28
|
+
|
|
29
|
+
<GeneratorParameters generator="ts#trpc-api" />
|
|
30
|
+
|
|
31
|
+
<Snippet name="api/api-choice-note" />
|
|
32
|
+
|
|
33
|
+
:::tip[API Type]
|
|
34
|
+
Select `ServerlessApiGatewayRestApi` (default) as your `computeType` if you would like to use [tRPC Subscriptions](https://trpc.io/docs/server/subscriptions) to stream responses.
|
|
35
|
+
:::
|
|
36
|
+
|
|
37
|
+
:::tip[Integration Pattern]
|
|
38
|
+
The `integrationPattern` option defaults to `isolated`, which creates one Lambda per tRPC procedure. Select `shared` if you would prefer a single shared Lambda handler for the whole API, with optional per-procedure overrides.
|
|
39
|
+
:::
|
|
40
|
+
|
|
41
|
+
## Generator Output
|
|
42
|
+
|
|
43
|
+
The generator will create the following project structure in the `<directory>/<api-name>` directory:
|
|
44
|
+
|
|
45
|
+
<FileTree>
|
|
46
|
+
- src
|
|
47
|
+
- init.ts Backend tRPC initialisation
|
|
48
|
+
- handler.ts Lambda handler entrypoint
|
|
49
|
+
- router.ts tRPC router definition
|
|
50
|
+
- schema Schema definitions using Zod
|
|
51
|
+
- echo.ts Example definitions for the input and output of the "echo" procedure
|
|
52
|
+
- z-async-iterable.ts Zod helper for subscriptions (REST API only)
|
|
53
|
+
- procedures Procedures (or operations) exposed by your API
|
|
54
|
+
- echo.ts Example procedure
|
|
55
|
+
- middleware
|
|
56
|
+
- error.ts Middleware for error handling
|
|
57
|
+
- logger.ts middleware for configuring AWS Powertools for Lambda logging
|
|
58
|
+
- tracer.ts middleware for configuring AWS Powertools for Lambda tracing
|
|
59
|
+
- metrics.ts middleware for configuring AWS Powertools for Lambda metrics
|
|
60
|
+
- local-server.ts tRPC standalone adapter entrypoint for local development server
|
|
61
|
+
- client
|
|
62
|
+
- index.ts Type-safe client for machine-to-machine API calls
|
|
63
|
+
- tsconfig.json TypeScript configuration
|
|
64
|
+
- project.json Project configuration and build targets
|
|
65
|
+
|
|
66
|
+
</FileTree>
|
|
67
|
+
|
|
68
|
+
### Infrastructure
|
|
69
|
+
|
|
70
|
+
<Snippet name="shared-constructs" />
|
|
71
|
+
|
|
72
|
+
<Snippet name="api/shared-constructs" />
|
|
73
|
+
|
|
74
|
+
#### Architecture
|
|
75
|
+
|
|
76
|
+
<Snippet name="api/api-architecture" />
|
|
77
|
+
|
|
78
|
+
## Implementing your tRPC API
|
|
79
|
+
|
|
80
|
+
At a high-level, tRPC APIs consist of a router which delegates requests to specific procedures. Each procedure has an input and output, defined as a Zod schema.
|
|
81
|
+
|
|
82
|
+
### Schema
|
|
83
|
+
|
|
84
|
+
The `src/schema` directory contains the types that are shared between your client and server code. In this package, these types are defined using [Zod](https://zod.dev/), a TypeScript-first schema declaration and validation library.
|
|
85
|
+
|
|
86
|
+
An example schema might look as follows:
|
|
87
|
+
|
|
88
|
+
```ts
|
|
89
|
+
import { z } from 'zod';
|
|
90
|
+
|
|
91
|
+
// Schema definition
|
|
92
|
+
export const UserSchema = z.object({
|
|
93
|
+
name: z.string(),
|
|
94
|
+
height: z.number(),
|
|
95
|
+
dateOfBirth: z.string().datetime(),
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
// Corresponding TypeScript type
|
|
99
|
+
export type User = z.TypeOf<typeof UserSchema>;
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Given the above schema, the `User` type is equivalent to the following TypeScript:
|
|
103
|
+
|
|
104
|
+
```ts
|
|
105
|
+
interface User {
|
|
106
|
+
name: string;
|
|
107
|
+
height: number;
|
|
108
|
+
dateOfBirth: string;
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Schemas are shared by both server and client code, providing a single place to update when making changes to the structures used in your API.
|
|
113
|
+
|
|
114
|
+
Schemas are automatically validated by your tRPC API at runtime, which saves hand-crafting custom validation logic in your backend.
|
|
115
|
+
|
|
116
|
+
Zod provides powerful utilities to combine or derive schemas such as `.merge`, `.pick`, `.omit` and more. You can find more information on the [Zod documentation website](https://zod.dev/?id=basic-usage).
|
|
117
|
+
|
|
118
|
+
### Router and Procedures
|
|
119
|
+
|
|
120
|
+
Your tRPC router is defined in `src/router.ts`, which registers all procedures. Each procedure defines the expected input, output, and implementation. The Lambda handler entry point is in `src/handler.ts`, which forwards requests to your router.
|
|
121
|
+
|
|
122
|
+
The sample router generated for you has a single operation, called `echo`:
|
|
123
|
+
|
|
124
|
+
```ts
|
|
125
|
+
import { echo } from './procedures/echo.js';
|
|
126
|
+
|
|
127
|
+
export const appRouter = router({
|
|
128
|
+
echo,
|
|
129
|
+
});
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
The example `echo` procedure is generated for you in `src/procedures/echo.ts`:
|
|
133
|
+
|
|
134
|
+
```ts
|
|
135
|
+
export const echo = publicProcedure
|
|
136
|
+
.input(EchoInputSchema)
|
|
137
|
+
.output(EchoOutputSchema)
|
|
138
|
+
.query((opts) => ({ result: opts.input.message }));
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
To break down the above:
|
|
142
|
+
|
|
143
|
+
- `publicProcedure` defines a public method on the API, including the middleware set up in `src/middleware`. This middleware includes AWS Lambda Powertools integration for logging, tracing and metrics.
|
|
144
|
+
- `input` accepts a Zod schema which defines the expected input for the operation. Requests sent for this operation are automatically validated against this schema.
|
|
145
|
+
- `output` accepts a Zod schema which defines the expected output for the operation. You will see type errors in your implementation if you don't return an output which conforms to the schema.
|
|
146
|
+
- `query` accepts a function which defines the implementation for your API. This implementation receives `opts`, which contains the `input` passed to your operation, as well as other context set up by middleware, available in `opts.ctx`. The function passed to `query` must return an output which conforms to the `output` schema.
|
|
147
|
+
|
|
148
|
+
The use of `query` to define the implementation indicates that the operation is not mutative. Use this to define methods to retrieve data. To implement a mutative operation, use the `mutation` method instead.
|
|
149
|
+
|
|
150
|
+
If you add a new procedure, make sure you register it by adding it to the router in `src/router.ts`.
|
|
151
|
+
|
|
152
|
+
<OptionFilter when={{ computeType: 'ServerlessApiGatewayRestApi' }} description="Streaming subscriptions — REST API only, uses SSE">
|
|
153
|
+
### Subscriptions (Streaming)
|
|
154
|
+
|
|
155
|
+
tRPC subscriptions allow you to stream data from the server to the client using [Server-Sent Events (SSE)](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events). When you select `ServerlessApiGatewayRestApi` as your compute type, the generator automatically configures the infrastructure required for streaming, as well as a streaming Lambda handler and the `ZodAsyncIterable` schema helper.
|
|
156
|
+
|
|
157
|
+
To define a subscription procedure, use the `.subscription` method with an async generator function. Use the `ZodAsyncIterable` helper from `src/schema/z-async-iterable.ts` to define the output schema:
|
|
158
|
+
|
|
159
|
+
```ts
|
|
160
|
+
import { publicProcedure } from '../init.js';
|
|
161
|
+
import { z } from 'zod';
|
|
162
|
+
import { ZodAsyncIterable } from '../schema/z-async-iterable.js';
|
|
163
|
+
|
|
164
|
+
const InputSchema = z.object({ query: z.string() });
|
|
165
|
+
const ChunkSchema = z.object({ text: z.string() });
|
|
166
|
+
|
|
167
|
+
export const myStream = publicProcedure
|
|
168
|
+
.input(InputSchema)
|
|
169
|
+
.output(
|
|
170
|
+
ZodAsyncIterable({
|
|
171
|
+
yield: ChunkSchema,
|
|
172
|
+
}),
|
|
173
|
+
)
|
|
174
|
+
.subscription(async function* (opts) {
|
|
175
|
+
// Yield data to the client as it becomes available
|
|
176
|
+
for (const chunk of await getResults(opts.input.query)) {
|
|
177
|
+
yield { text: chunk };
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
Register the subscription in your router just like any other procedure:
|
|
183
|
+
|
|
184
|
+
```ts
|
|
185
|
+
export const appRouter = router({
|
|
186
|
+
echo,
|
|
187
|
+
myStream,
|
|
188
|
+
});
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
The generated infrastructure uses a streaming Lambda handler with `ResponseTransferMode.STREAM` in API Gateway for all REST API operations, which enables subscriptions to work alongside regular queries and mutations.
|
|
192
|
+
</OptionFilter>
|
|
193
|
+
|
|
194
|
+
## Customising your tRPC API
|
|
195
|
+
|
|
196
|
+
### Errors
|
|
197
|
+
|
|
198
|
+
In your implementation, you can return error responses to clients by throwing a `TRPCError`. These accept a `code` which indicates the type of error, for example:
|
|
199
|
+
|
|
200
|
+
```ts
|
|
201
|
+
throw new TRPCError({
|
|
202
|
+
code: 'NOT_FOUND',
|
|
203
|
+
message: 'The requested resource could not be found',
|
|
204
|
+
});
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### Organising Your Operations
|
|
208
|
+
|
|
209
|
+
As your API grows, you may wish to group related operations together.
|
|
210
|
+
|
|
211
|
+
You can group operations together using nested routers, for example:
|
|
212
|
+
|
|
213
|
+
```ts
|
|
214
|
+
import { getUser } from './procedures/users/get.js';
|
|
215
|
+
import { listUsers } from './procedures/users/list.js';
|
|
216
|
+
|
|
217
|
+
const appRouter = router({
|
|
218
|
+
users: router({
|
|
219
|
+
get: getUser,
|
|
220
|
+
list: listUsers,
|
|
221
|
+
}),
|
|
222
|
+
...
|
|
223
|
+
})
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
Clients then receive this grouping of operations, for example invoking the `listUsers` operation in this case might look as follows:
|
|
227
|
+
|
|
228
|
+
```ts
|
|
229
|
+
client.users.list.query();
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
### Logging
|
|
233
|
+
|
|
234
|
+
The AWS Lambda Powertools logger is configured in `src/middleware/logger.ts`, and can be accessed in an API implementation via `opts.ctx.logger`. You can use this to log to CloudWatch Logs, and/or control additional values to include in every structured log message. For example:
|
|
235
|
+
|
|
236
|
+
```ts {5}
|
|
237
|
+
export const echo = publicProcedure
|
|
238
|
+
.input(...)
|
|
239
|
+
.output(...)
|
|
240
|
+
.query(async (opts) => {
|
|
241
|
+
opts.ctx.logger.info('Operation called with input', opts.input);
|
|
242
|
+
|
|
243
|
+
return ...;
|
|
244
|
+
});
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
For more information about the logger, please refer to the [AWS Lambda Powertools Logger documentation](https://docs.powertools.aws.dev/lambda/typescript/latest/core/logger/).
|
|
248
|
+
|
|
249
|
+
### Recording Metrics
|
|
250
|
+
|
|
251
|
+
AWS Lambda Powertools metrics are configured in `src/middleware/metrics.ts`, and can be accessed in an API implementation via `opts.ctx.metrics`. You can use this to record metrics in CloudWatch without the need to import and use the AWS SDK, for example:
|
|
252
|
+
|
|
253
|
+
```ts {5}
|
|
254
|
+
export const echo = publicProcedure
|
|
255
|
+
.input(...)
|
|
256
|
+
.output(...)
|
|
257
|
+
.query(async (opts) => {
|
|
258
|
+
opts.ctx.metrics.addMetric('Invocations', 'Count', 1);
|
|
259
|
+
|
|
260
|
+
return ...;
|
|
261
|
+
});
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
For more information, please refer to the [AWS Lambda Powertools Metrics documentation](https://docs.powertools.aws.dev/lambda/typescript/latest/core/metrics/).
|
|
265
|
+
|
|
266
|
+
### Fine-tuning X-Ray Tracing
|
|
267
|
+
|
|
268
|
+
The AWS Lambda Powertools tracer is configured in `src/middleware/tracer.ts`, and can be accessed in an API implementation via `opts.ctx.tracer`. You can use this to add traces with AWS X-Ray to provide detailed insights into the performance and flow of API requests. For example:
|
|
269
|
+
|
|
270
|
+
```ts {5-7}
|
|
271
|
+
export const echo = publicProcedure
|
|
272
|
+
.input(...)
|
|
273
|
+
.output(...)
|
|
274
|
+
.query(async (opts) => {
|
|
275
|
+
const subSegment = opts.ctx.tracer.getSegment()!.addNewSubsegment('MyAlgorithm');
|
|
276
|
+
// ... my algorithm logic to capture
|
|
277
|
+
subSegment.close();
|
|
278
|
+
|
|
279
|
+
return ...;
|
|
280
|
+
});
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
For more information, please refer to the [AWS Lambda Powertools Tracer documentation](https://docs.powertools.aws.dev/lambda/typescript/latest/core/tracer/).
|
|
284
|
+
|
|
285
|
+
### Implementing Custom Middleware
|
|
286
|
+
|
|
287
|
+
You can add additional values to the context provided to procedures by implementing middleware.
|
|
288
|
+
|
|
289
|
+
As an example, let's implement some middlware to extract some details about the calling user from our API in `src/middleware/identity.ts`.
|
|
290
|
+
|
|
291
|
+
<OptionFilter when={{ auth: 'IAM' }} description="Identity middleware example for IAM-authenticated APIs">
|
|
292
|
+
This example walks through identity middleware for `IAM` authentication. We look up the caller in Cognito using the sub extracted from the API Gateway event.
|
|
293
|
+
|
|
294
|
+
First, we define what we'll add to the context:
|
|
295
|
+
|
|
296
|
+
```ts
|
|
297
|
+
export interface IIdentityContext {
|
|
298
|
+
identity?: {
|
|
299
|
+
sub: string;
|
|
300
|
+
username: string;
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
Note that we define an additional _optional_ property to the context. tRPC manages ensuring that this is defined in procedures which have correctly configured this middleware.
|
|
306
|
+
|
|
307
|
+
Next, we'll implement the middlware itself. This has the following structure:
|
|
308
|
+
|
|
309
|
+
```ts
|
|
310
|
+
export const createIdentityPlugin = () => {
|
|
311
|
+
const t = initTRPC.context<...>().create();
|
|
312
|
+
return t.procedure.use(async (opts) => {
|
|
313
|
+
// Add logic here to run before the procedure
|
|
314
|
+
|
|
315
|
+
const response = await opts.next(...);
|
|
316
|
+
|
|
317
|
+
// Add logic here to run after the procedure
|
|
318
|
+
|
|
319
|
+
return response;
|
|
320
|
+
});
|
|
321
|
+
};
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
In our case, we want to extract details about the calling Cognito user. We'll do that by extracting the user's subject ID (or "sub") from the API Gateway event, and retrieving user details from Cognito. The implementation varies depending on whether the event was provided to our function by a REST API or an HTTP API:
|
|
325
|
+
|
|
326
|
+
<Tabs syncKey="http-rest">
|
|
327
|
+
<TabItem label="REST API" _filter={{ computeType: 'ServerlessApiGatewayRestApi' }}>
|
|
328
|
+
```ts
|
|
329
|
+
import { CognitoIdentityProvider } from '@aws-sdk/client-cognito-identity-provider';
|
|
330
|
+
import { initTRPC, TRPCError } from '@trpc/server';
|
|
331
|
+
import { CreateAWSLambdaContextOptions } from '@trpc/server/adapters/aws-lambda';
|
|
332
|
+
import { APIGatewayProxyEvent } from 'aws-lambda';
|
|
333
|
+
|
|
334
|
+
export interface IIdentityContext {
|
|
335
|
+
identity?: {
|
|
336
|
+
sub: string;
|
|
337
|
+
username: string;
|
|
338
|
+
};
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
export const createIdentityPlugin = () => {
|
|
342
|
+
const t = initTRPC.context<IIdentityContext & CreateAWSLambdaContextOptions<APIGatewayProxyEvent>>().create();
|
|
343
|
+
|
|
344
|
+
const cognito = new CognitoIdentityProvider();
|
|
345
|
+
|
|
346
|
+
return t.procedure.use(async (opts) => {
|
|
347
|
+
const cognitoAuthenticationProvider = opts.ctx.event.requestContext?.identity?.cognitoAuthenticationProvider;
|
|
348
|
+
|
|
349
|
+
let sub: string | undefined = undefined;
|
|
350
|
+
if (cognitoAuthenticationProvider) {
|
|
351
|
+
const providerParts = cognitoAuthenticationProvider.split(':');
|
|
352
|
+
sub = providerParts[providerParts.length - 1];
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
if (!sub) {
|
|
356
|
+
throw new TRPCError({
|
|
357
|
+
code: 'FORBIDDEN',
|
|
358
|
+
message: `Unable to determine calling user`,
|
|
359
|
+
});
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
const { Users } = await cognito.listUsers({
|
|
363
|
+
// Assumes user pool id is configured in lambda environment
|
|
364
|
+
UserPoolId: process.env.USER_POOL_ID!,
|
|
365
|
+
Limit: 1,
|
|
366
|
+
Filter: `sub="${sub}"`,
|
|
367
|
+
});
|
|
368
|
+
|
|
369
|
+
if (!Users || Users.length !== 1) {
|
|
370
|
+
throw new TRPCError({
|
|
371
|
+
code: 'FORBIDDEN',
|
|
372
|
+
message: `No user found with subjectId ${sub}`,
|
|
373
|
+
});
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
// Provide the identity to other procedures in the context
|
|
377
|
+
return await opts.next({
|
|
378
|
+
ctx: {
|
|
379
|
+
...opts.ctx,
|
|
380
|
+
identity: {
|
|
381
|
+
sub,
|
|
382
|
+
username: Users[0].Username!,
|
|
383
|
+
},
|
|
384
|
+
},
|
|
385
|
+
});
|
|
386
|
+
});
|
|
387
|
+
};
|
|
388
|
+
```
|
|
389
|
+
</TabItem>
|
|
390
|
+
<TabItem label="HTTP API" _filter={{ computeType: 'ServerlessApiGatewayHttpApi' }}>
|
|
391
|
+
```ts
|
|
392
|
+
import { CognitoIdentityProvider } from '@aws-sdk/client-cognito-identity-provider';
|
|
393
|
+
import { initTRPC, TRPCError } from '@trpc/server';
|
|
394
|
+
import { CreateAWSLambdaContextOptions } from '@trpc/server/adapters/aws-lambda';
|
|
395
|
+
import { APIGatewayProxyEventV2WithIAMAuthorizer } from 'aws-lambda';
|
|
396
|
+
|
|
397
|
+
export interface IIdentityContext {
|
|
398
|
+
identity?: {
|
|
399
|
+
sub: string;
|
|
400
|
+
username: string;
|
|
401
|
+
};
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
export const createIdentityPlugin = () => {
|
|
405
|
+
const t = initTRPC.context<IIdentityContext & CreateAWSLambdaContextOptions<APIGatewayProxyEventV2WithIAMAuthorizer>>().create();
|
|
406
|
+
|
|
407
|
+
const cognito = new CognitoIdentityProvider();
|
|
408
|
+
|
|
409
|
+
return t.procedure.use(async (opts) => {
|
|
410
|
+
const cognitoIdentity = opts.ctx.event.requestContext?.authorizer?.iam
|
|
411
|
+
?.cognitoIdentity as unknown as
|
|
412
|
+
| {
|
|
413
|
+
amr: string[];
|
|
414
|
+
}
|
|
415
|
+
| undefined;
|
|
416
|
+
|
|
417
|
+
const sub = (cognitoIdentity?.amr ?? [])
|
|
418
|
+
.flatMap((s) => (s.includes(':CognitoSignIn:') ? [s] : []))
|
|
419
|
+
.map((s) => {
|
|
420
|
+
const parts = s.split(':');
|
|
421
|
+
return parts[parts.length - 1];
|
|
422
|
+
})?.[0];
|
|
423
|
+
|
|
424
|
+
if (!sub) {
|
|
425
|
+
throw new TRPCError({
|
|
426
|
+
code: 'FORBIDDEN',
|
|
427
|
+
message: `Unable to determine calling user`,
|
|
428
|
+
});
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
const { Users } = await cognito.listUsers({
|
|
432
|
+
// Assumes user pool id is configured in lambda environment
|
|
433
|
+
UserPoolId: process.env.USER_POOL_ID!,
|
|
434
|
+
Limit: 1,
|
|
435
|
+
Filter: `sub="${sub}"`,
|
|
436
|
+
});
|
|
437
|
+
|
|
438
|
+
if (!Users || Users.length !== 1) {
|
|
439
|
+
throw new TRPCError({
|
|
440
|
+
code: 'FORBIDDEN',
|
|
441
|
+
message: `No user found with subjectId ${sub}`,
|
|
442
|
+
});
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
// Provide the identity to other procedures in the context
|
|
446
|
+
return await opts.next({
|
|
447
|
+
ctx: {
|
|
448
|
+
...opts.ctx,
|
|
449
|
+
identity: {
|
|
450
|
+
sub,
|
|
451
|
+
username: Users[0].Username!,
|
|
452
|
+
},
|
|
453
|
+
},
|
|
454
|
+
});
|
|
455
|
+
});
|
|
456
|
+
};
|
|
457
|
+
```
|
|
458
|
+
</TabItem>
|
|
459
|
+
</Tabs>
|
|
460
|
+
</OptionFilter>
|
|
461
|
+
|
|
462
|
+
<OptionFilter when={{ auth: 'Cognito' }} description="Identity middleware example for Cognito-authenticated APIs">
|
|
463
|
+
When you deploy with `auth: 'Cognito'`, the API Gateway Cognito User Pools authorizer verifies the JWT that the caller supplies in the `Authorization` header and places the verified claims on the Lambda event at `event.requestContext.authorizer.claims`. Our middleware just reads those claims — no extra AWS SDK calls, no manual JWT verification.
|
|
464
|
+
|
|
465
|
+
First, we define what we'll add to the context:
|
|
466
|
+
|
|
467
|
+
```ts
|
|
468
|
+
export interface IIdentityContext {
|
|
469
|
+
identity?: {
|
|
470
|
+
sub: string;
|
|
471
|
+
username: string;
|
|
472
|
+
};
|
|
473
|
+
}
|
|
474
|
+
```
|
|
475
|
+
|
|
476
|
+
Note that we define an additional _optional_ property on the context. tRPC manages ensuring that this is defined in procedures which have correctly configured this middleware.
|
|
477
|
+
|
|
478
|
+
Next, the middleware itself. The generator wires the authorizer to accept ID tokens, so `cognito:username` is the canonical username claim; we fall back to `username` for access tokens in case you reconfigure the authorizer:
|
|
479
|
+
|
|
480
|
+
```ts
|
|
481
|
+
import { initTRPC, TRPCError } from '@trpc/server';
|
|
482
|
+
import { CreateAWSLambdaContextOptions } from '@trpc/server/adapters/aws-lambda';
|
|
483
|
+
import { APIGatewayProxyEvent } from 'aws-lambda';
|
|
484
|
+
|
|
485
|
+
export interface IIdentityContext {
|
|
486
|
+
identity?: {
|
|
487
|
+
sub: string;
|
|
488
|
+
username: string;
|
|
489
|
+
};
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
export const createIdentityPlugin = () => {
|
|
493
|
+
const t = initTRPC
|
|
494
|
+
.context<IIdentityContext & CreateAWSLambdaContextOptions<APIGatewayProxyEvent>>()
|
|
495
|
+
.create();
|
|
496
|
+
|
|
497
|
+
return t.procedure.use(async (opts) => {
|
|
498
|
+
const claims = opts.ctx.event.requestContext?.authorizer?.claims as
|
|
499
|
+
| Record<string, string>
|
|
500
|
+
| undefined;
|
|
501
|
+
|
|
502
|
+
const sub = claims?.sub;
|
|
503
|
+
const username = claims?.['cognito:username'] ?? claims?.username;
|
|
504
|
+
|
|
505
|
+
if (!sub || !username) {
|
|
506
|
+
throw new TRPCError({
|
|
507
|
+
code: 'FORBIDDEN',
|
|
508
|
+
message: 'Unable to determine calling user',
|
|
509
|
+
});
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
return await opts.next({
|
|
513
|
+
ctx: {
|
|
514
|
+
...opts.ctx,
|
|
515
|
+
identity: {
|
|
516
|
+
sub,
|
|
517
|
+
username,
|
|
518
|
+
},
|
|
519
|
+
},
|
|
520
|
+
});
|
|
521
|
+
});
|
|
522
|
+
};
|
|
523
|
+
```
|
|
524
|
+
|
|
525
|
+
You can then mix the plugin into any procedure that needs the caller's identity:
|
|
526
|
+
|
|
527
|
+
```ts
|
|
528
|
+
import { publicProcedure } from '../init.js';
|
|
529
|
+
import { createIdentityPlugin } from '../middleware/identity.js';
|
|
530
|
+
import { z } from 'zod';
|
|
531
|
+
|
|
532
|
+
export const me = publicProcedure
|
|
533
|
+
.concat(createIdentityPlugin())
|
|
534
|
+
.output(z.object({ sub: z.string(), username: z.string() }))
|
|
535
|
+
.query(({ ctx }) => ({
|
|
536
|
+
sub: ctx.identity!.sub,
|
|
537
|
+
username: ctx.identity!.username,
|
|
538
|
+
}));
|
|
539
|
+
```
|
|
540
|
+
|
|
541
|
+
:::tip[Verifying the token]
|
|
542
|
+
You don't need `aws-jwt-verify` or any other JWT-verification library here — the API Gateway Cognito User Pools authorizer has already verified the signature, issuer, audience, and expiry by the time your Lambda runs. If any of those checks fail, API Gateway returns `401 Unauthorized` and your handler is never invoked.
|
|
543
|
+
:::
|
|
544
|
+
</OptionFilter>
|
|
545
|
+
|
|
546
|
+
## Deploying your tRPC API
|
|
547
|
+
|
|
548
|
+
The tRPC API generator creates CDK or Terraform infrastructure as code based on your selected `iacProvider`. You can use this to deploy your tRPC API.
|
|
549
|
+
|
|
550
|
+
<Infrastructure>
|
|
551
|
+
<Fragment slot="cdk">
|
|
552
|
+
The CDK construct for deploying your API lives in the `common/constructs` folder. You can consume this in a CDK application, for example:
|
|
553
|
+
|
|
554
|
+
<OptionFilter when={{ auth: ['IAM', 'Custom'] }} description="CDK usage for IAM or Custom authentication">
|
|
555
|
+
```ts {6-8}
|
|
556
|
+
import { MyApi } from ':my-scope/common-constructs';
|
|
557
|
+
|
|
558
|
+
export class ExampleStack extends Stack {
|
|
559
|
+
constructor(scope: Construct, id: string) {
|
|
560
|
+
// Add the api to your stack
|
|
561
|
+
const api = new MyApi(this, 'MyApi', {
|
|
562
|
+
integrations: MyApi.defaultIntegrations(this).build(),
|
|
563
|
+
});
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
```
|
|
567
|
+
|
|
568
|
+
:::caution[Custom Lambda Authorizer]
|
|
569
|
+
When using `Custom` auth, the construct creates a Lambda Authorizer internally from the generated `src/authorizer.ts` file, which **denies all requests by default**. You must implement your authorization logic in that file before your API will accept any traffic.
|
|
570
|
+
:::
|
|
571
|
+
</OptionFilter>
|
|
572
|
+
|
|
573
|
+
<OptionFilter when={{ auth: 'Cognito' }} description="CDK usage with Cognito authentication — pass the identity construct">
|
|
574
|
+
```ts {6,9}
|
|
575
|
+
import { MyApi, UserIdentity } from ':my-scope/common-constructs';
|
|
576
|
+
|
|
577
|
+
export class ExampleStack extends Stack {
|
|
578
|
+
constructor(scope: Construct, id: string) {
|
|
579
|
+
// Add the api to your stack
|
|
580
|
+
const identity = new UserIdentity(this, 'Identity');
|
|
581
|
+
|
|
582
|
+
const api = new MyApi(this, 'MyApi', {
|
|
583
|
+
integrations: MyApi.defaultIntegrations(this).build(),
|
|
584
|
+
identity,
|
|
585
|
+
});
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
```
|
|
589
|
+
|
|
590
|
+
The `UserIdentity` construct can be generated using the <Link path="/guides/react-website-auth">`ts#react-website-auth` generator</Link>.
|
|
591
|
+
</OptionFilter>
|
|
592
|
+
|
|
593
|
+
This sets up your API infrastructure, including an AWS API Gateway REST or HTTP API, AWS Lambda functions for business logic, and authentication based on your chosen `auth` method.
|
|
594
|
+
|
|
595
|
+
<Snippet name="api/cors-configuration-cdk-note" />
|
|
596
|
+
</Fragment>
|
|
597
|
+
<Fragment slot="terraform">
|
|
598
|
+
The Terraform modules for deploying your API are in the `common/terraform` folder. You can use this in a Terraform configuration.
|
|
599
|
+
|
|
600
|
+
The API module stages its Lambda deployment zip in a shared S3 asset bucket — see the <Link path="/guides/terraform-project">Terraform infrastructure guide</Link> for details. Instantiate the `core/asset-bucket` module once per deployment and pass its `bucket_name` output into every API / Lambda module via the `asset_bucket_name` input:
|
|
601
|
+
|
|
602
|
+
<OptionFilter when={{ auth: ['IAM', 'Custom'] }} description="Terraform usage for IAM or Custom authentication">
|
|
603
|
+
```hcl {1-3, 8}
|
|
604
|
+
module "asset_bucket" {
|
|
605
|
+
source = "../../common/terraform/src/core/asset-bucket"
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
module "my_api" {
|
|
609
|
+
source = "../../common/terraform/src/app/apis/my-api"
|
|
610
|
+
|
|
611
|
+
asset_bucket_name = module.asset_bucket.bucket_name
|
|
612
|
+
|
|
613
|
+
# Environment variables for the Lambda function
|
|
614
|
+
env = {
|
|
615
|
+
ENVIRONMENT = var.environment
|
|
616
|
+
LOG_LEVEL = "INFO"
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
# Additional IAM policies if needed
|
|
620
|
+
additional_iam_policy_statements = [
|
|
621
|
+
# Add any additional permissions your API needs
|
|
622
|
+
]
|
|
623
|
+
|
|
624
|
+
tags = local.common_tags
|
|
625
|
+
}
|
|
626
|
+
```
|
|
627
|
+
</OptionFilter>
|
|
628
|
+
|
|
629
|
+
<OptionFilter when={{ auth: 'Cognito' }} description="Terraform usage with Cognito authentication — supply user pool and client">
|
|
630
|
+
```hcl {1-3, 8-9}
|
|
631
|
+
module "asset_bucket" {
|
|
632
|
+
source = "../../common/terraform/src/core/asset-bucket"
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
module "my_api" {
|
|
636
|
+
source = "../../common/terraform/src/app/apis/my-api"
|
|
637
|
+
|
|
638
|
+
asset_bucket_name = module.asset_bucket.bucket_name
|
|
639
|
+
|
|
640
|
+
user_pool_id = local.user_pool_id
|
|
641
|
+
user_pool_client_ids = [local.client_id]
|
|
642
|
+
|
|
643
|
+
# Environment variables for the Lambda function
|
|
644
|
+
env = {
|
|
645
|
+
ENVIRONMENT = var.environment
|
|
646
|
+
LOG_LEVEL = "INFO"
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
# Additional IAM policies if needed
|
|
650
|
+
additional_iam_policy_statements = [
|
|
651
|
+
# Add any additional permissions your API needs
|
|
652
|
+
]
|
|
653
|
+
|
|
654
|
+
tags = local.common_tags
|
|
655
|
+
}
|
|
656
|
+
```
|
|
657
|
+
|
|
658
|
+
You can set up the Cognito User Pool and Client using the appropriate Terraform resources or modules.
|
|
659
|
+
</OptionFilter>
|
|
660
|
+
|
|
661
|
+
This sets up:
|
|
662
|
+
|
|
663
|
+
1. An AWS Lambda function that serves all tRPC procedures
|
|
664
|
+
2. API Gateway HTTP/REST API as the function trigger
|
|
665
|
+
3. IAM roles and permissions
|
|
666
|
+
4. CloudWatch log group
|
|
667
|
+
5. X-Ray tracing configuration
|
|
668
|
+
6. CORS configuration
|
|
669
|
+
|
|
670
|
+
<Snippet name="api/cors-configuration-terraform-note" />
|
|
671
|
+
|
|
672
|
+
The Terraform module provides several outputs you can use:
|
|
673
|
+
|
|
674
|
+
```hcl
|
|
675
|
+
# Access the API endpoint
|
|
676
|
+
output "api_url" {
|
|
677
|
+
value = module.my_api.stage_invoke_url
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
# Access Lambda function details
|
|
681
|
+
output "lambda_function_name" {
|
|
682
|
+
value = module.my_api.lambda_function_name
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
# Access IAM role for granting additional permissions
|
|
686
|
+
output "lambda_execution_role_arn" {
|
|
687
|
+
value = module.my_api.lambda_execution_role_arn
|
|
688
|
+
}
|
|
689
|
+
```
|
|
690
|
+
|
|
691
|
+
You can customize CORS settings by passing variables to the module:
|
|
692
|
+
|
|
693
|
+
```hcl
|
|
694
|
+
module "my_api" {
|
|
695
|
+
source = "../../common/terraform/src/app/apis/my-api"
|
|
696
|
+
|
|
697
|
+
asset_bucket_name = module.asset_bucket.bucket_name
|
|
698
|
+
|
|
699
|
+
# Custom CORS configuration
|
|
700
|
+
cors_allow_origins = ["https://myapp.com", "https://staging.myapp.com"]
|
|
701
|
+
cors_allow_methods = ["GET", "POST", "PUT", "DELETE"]
|
|
702
|
+
cors_allow_headers = [
|
|
703
|
+
"authorization",
|
|
704
|
+
"content-type",
|
|
705
|
+
"x-custom-header"
|
|
706
|
+
]
|
|
707
|
+
|
|
708
|
+
tags = local.common_tags
|
|
709
|
+
}
|
|
710
|
+
```
|
|
711
|
+
|
|
712
|
+
<OptionFilter when={{ auth: 'Custom' }} description="Custom Lambda Authorizer usage with Terraform">
|
|
713
|
+
:::caution[Custom Lambda Authorizer]
|
|
714
|
+
When using `Custom` auth, your API is protected by a Lambda Authorizer that **denies all requests by default**. You must implement your authorization logic in the generated `src/authorizer.ts` file before your API will accept any traffic.
|
|
715
|
+
:::
|
|
716
|
+
</OptionFilter>
|
|
717
|
+
</Fragment>
|
|
718
|
+
</Infrastructure>
|
|
719
|
+
|
|
720
|
+
<OptionFilter when={{ computeType: 'ServerlessApiGatewayRestApi' }} description="WAF — REST APIs get a WAF Web ACL by default">
|
|
721
|
+
### WAF
|
|
722
|
+
|
|
723
|
+
<Snippet name="api/waf-configuration" parentHeading="WAF" />
|
|
724
|
+
</OptionFilter>
|
|
725
|
+
|
|
726
|
+
### Integrations
|
|
727
|
+
|
|
728
|
+
<Snippet name="api/type-safe-api-integrations" parentHeading="Integrations" />
|
|
729
|
+
|
|
730
|
+
:::tip[CDK Type-Safe Integrations]
|
|
731
|
+
If you selected CDK for your `iacProvider`, when you add or remove a procedure in your tRPC API, these changes will be reflected immediately in the CDK construct without the need to rebuild.
|
|
732
|
+
:::
|
|
733
|
+
|
|
734
|
+
<OptionFilter when={{ auth: 'IAM' }} description="Granting API invoke access — IAM-authenticated APIs only">
|
|
735
|
+
### Granting Access (IAM Only)
|
|
736
|
+
|
|
737
|
+
You can grant access to your API as follows:
|
|
738
|
+
|
|
739
|
+
<Infrastructure>
|
|
740
|
+
<Fragment slot="cdk">
|
|
741
|
+
```ts
|
|
742
|
+
api.grantInvokeAccess(myIdentityPool.authenticatedRole);
|
|
743
|
+
```
|
|
744
|
+
</Fragment>
|
|
745
|
+
<Fragment slot="terraform">
|
|
746
|
+
```hcl
|
|
747
|
+
# Create an IAM policy to allow invoking the API
|
|
748
|
+
resource "aws_iam_policy" "api_invoke_policy" {
|
|
749
|
+
name = "MyApiInvokePolicy"
|
|
750
|
+
description = "Policy to allow invoking the tRPC API"
|
|
751
|
+
|
|
752
|
+
policy = jsonencode({
|
|
753
|
+
Version = "2012-10-17"
|
|
754
|
+
Statement = [
|
|
755
|
+
{
|
|
756
|
+
Effect = "Allow"
|
|
757
|
+
Action = "execute-api:Invoke"
|
|
758
|
+
Resource = "${module.my_api.api_execution_arn}/*/*"
|
|
759
|
+
}
|
|
760
|
+
]
|
|
761
|
+
})
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
# Attach the policy to an IAM role (e.g., for authenticated users)
|
|
765
|
+
resource "aws_iam_role_policy_attachment" "api_invoke_access" {
|
|
766
|
+
role = aws_iam_role.authenticated_user_role.name
|
|
767
|
+
policy_arn = aws_iam_policy.api_invoke_policy.arn
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
# Or attach to an existing role by name
|
|
771
|
+
resource "aws_iam_role_policy_attachment" "api_invoke_access_existing" {
|
|
772
|
+
role = "MyExistingRole"
|
|
773
|
+
policy_arn = aws_iam_policy.api_invoke_policy.arn
|
|
774
|
+
}
|
|
775
|
+
```
|
|
776
|
+
|
|
777
|
+
The key outputs from the API module that you can use for IAM policies are:
|
|
778
|
+
|
|
779
|
+
- `module.my_api.api_execution_arn` - For granting execute-api:Invoke permissions
|
|
780
|
+
- `module.my_api.api_arn` - The API Gateway ARN
|
|
781
|
+
- `module.my_api.lambda_function_arn` - The Lambda function ARN
|
|
782
|
+
</Fragment>
|
|
783
|
+
</Infrastructure>
|
|
784
|
+
</OptionFilter>
|
|
785
|
+
|
|
786
|
+
### Bundle Target
|
|
787
|
+
|
|
788
|
+
<Snippet name="ts-bundle" />
|
|
789
|
+
|
|
790
|
+
## Local tRPC Server
|
|
791
|
+
|
|
792
|
+
You can use the `serve` target to run a local server for your API, for example:
|
|
793
|
+
|
|
794
|
+
<NxCommands commands={['serve my-api']} />
|
|
795
|
+
|
|
796
|
+
The entry point for the local server is `src/local-server.ts`.
|
|
797
|
+
|
|
798
|
+
This will automatically reload when you make changes to your API.
|
|
799
|
+
|
|
800
|
+
## Invoking your tRPC API
|
|
801
|
+
|
|
802
|
+
You can create a tRPC client to invoke your API in a type-safe manner. If you are calling your tRPC API from another backend, you can use the client in `src/client/index.ts`, for example:
|
|
803
|
+
|
|
804
|
+
```ts
|
|
805
|
+
import { createMyApiClient } from ':my-scope/my-api';
|
|
806
|
+
|
|
807
|
+
const client = createMyApiClient({ url: 'https://my-api-url.example.com/' });
|
|
808
|
+
|
|
809
|
+
await client.echo.query({ message: 'Hello world!' });
|
|
810
|
+
```
|
|
811
|
+
|
|
812
|
+
If you are calling your API from a React website, consider using the <Link path="guides/connection/react-trpc">Connection</Link> generator to configure the client.
|
|
813
|
+
|
|
814
|
+
## More Information
|
|
815
|
+
|
|
816
|
+
For more information about tRPC, please refer to the [tRPC documentation](https://trpc.io/docs).
|