tRPC
tRPC è un framework per costruire API in TypeScript con type safety end-to-end. Utilizzando tRPC, gli aggiornamenti agli input e output delle operazioni API si riflettono immediatamente nel codice client e sono visibili nel tuo IDE senza bisogno di ricostruire il progetto.
Il generatore di API tRPC crea una nuova API tRPC con configurazione dell’infrastruttura AWS CDK o Terraform. Il backend generato utilizza AWS Lambda per il deployment serverless, esposto tramite un’API AWS API Gateway, e include la validazione degli schemi con Zod. Configura AWS Lambda Powertools per l’osservabilità, inclusi logging, tracciamento AWS X-Ray e metriche Cloudwatch.
Utilizzo
Sezione intitolata “Utilizzo”Generare un’API tRPC
Sezione intitolata “Generare un’API tRPC”Puoi generare una nuova API tRPC in due modi:
- Installa il Nx Console VSCode Plugin se non l'hai già fatto
- Apri la console Nx in VSCode
- Clicca su
Generate (UI)
nella sezione "Common Nx Commands" - Cerca
@aws/nx-plugin - ts#trpc-api
- Compila i parametri richiesti
- Clicca su
Generate
pnpm nx g @aws/nx-plugin:ts#trpc-api
yarn nx g @aws/nx-plugin:ts#trpc-api
npx nx g @aws/nx-plugin:ts#trpc-api
bunx nx g @aws/nx-plugin:ts#trpc-api
Puoi anche eseguire una prova per vedere quali file verrebbero modificati
pnpm nx g @aws/nx-plugin:ts#trpc-api --dry-run
yarn nx g @aws/nx-plugin:ts#trpc-api --dry-run
npx nx g @aws/nx-plugin:ts#trpc-api --dry-run
bunx nx g @aws/nx-plugin:ts#trpc-api --dry-run
Opzioni
Sezione intitolata “Opzioni”Parametro | Tipo | Predefinito | Descrizione |
---|---|---|---|
name Obbligatorio | string | - | The name of the API (required). Used to generate class names and file paths. |
computeType | string | ServerlessApiGatewayRestApi | The type of compute to use to deploy this API. Choose between ServerlessApiGatewayRestApi (default) or ServerlessApiGatewayHttpApi. |
auth | string | IAM | The method used to authenticate with your API. Choose between IAM (default), Cognito or None. |
directory | string | packages | The directory to store the application in. |
iacProvider | string | CDK | The preferred IaC provider |
Output del Generatore
Sezione intitolata “Output del Generatore”Il generatore creerà la seguente struttura del progetto nella directory <directory>/<api-name>
:
Directorysrc
- init.ts Inizializzazione del backend tRPC
- router.ts Definizione del router tRPC (punto di ingresso API del gestore Lambda)
Directoryschema Definizioni degli schemi con Zod
- echo.ts Definizioni di esempio per input e output della procedura “echo”
Directoryprocedures Procedure (o operazioni) esposte dalla tua API
- echo.ts Procedura di esempio
Directorymiddleware
- error.ts Middleware per la gestione degli errori
- logger.ts middleware per configurare AWS Powertools per il logging Lambda
- tracer.ts middleware per configurare AWS Powertools per il tracciamento Lambda
- metrics.ts middleware per configurare AWS Powertools per le metriche Lambda
- local-server.ts Punto di ingresso dell’adapter standalone tRPC per server di sviluppo locale
Directoryclient
- index.ts Client type-safe per chiamate API machine-to-machine
- tsconfig.json Configurazione TypeScript
- project.json Configurazione del progetto e target di build
Infrastruttura
Sezione intitolata “Infrastruttura”Poiché questo generatore fornisce infrastruttura come codice basata sul tuo iacProvider
selezionato, creerà un progetto in packages/common
che include i relativi costrutti CDK o moduli Terraform.
Il progetto comune di infrastruttura come codice è strutturato come segue:
Directorypackages/common/constructs
Directorysrc
Directoryapp/ Construct per l’infrastruttura specifica di un progetto/generatore
- …
Directorycore/ Construct generici riutilizzati dai construct in
app
- …
- index.ts Punto di ingresso che esporta i construct da
app
- project.json Target di build e configurazione del progetto
Directorypackages/common/terraform
Directorysrc
Directoryapp/ Moduli Terraform per l’infrastruttura specifica di un progetto/generatore
- …
Directorycore/ Moduli generici riutilizzati dai moduli in
app
- …
- project.json Target di build e configurazione del progetto
Per la distribuzione della tua API, vengono generati i seguenti file:
Directorypackages/common/constructs/src
Directoryapp
Directoryapis
- <project-name>.ts Costrutto CDK per distribuire la tua API
Directorycore
Directoryapi
- http-api.ts Costrutto CDK per distribuire un’API HTTP (se hai scelto di distribuire un’API HTTP)
- rest-api.ts Costrutto CDK per distribuire un’API REST (se hai scelto di distribuire un’API REST)
- utils.ts Utilities per i costrutti API
Directorypackages/common/terraform/src
Directoryapp
Directoryapis
Directory<project-name>
- <project-name>.tf Modulo per distribuire la tua API
Directorycore
Directoryapi
Directoryhttp-api
- http-api.tf Modulo per distribuire un’API HTTP (se hai scelto di distribuire un’API HTTP)
Directoryrest-api
- rest-api.tf Modulo per distribuire un’API REST (se hai scelto di distribuire un’API REST)
Implementare la tua API tRPC
Sezione intitolata “Implementare la tua API tRPC”A grandi linee, le API tRPC consistono in un router che delega le richieste a procedure specifiche. Ogni procedura ha un input e un output definiti come schema Zod.
La directory src/schema
contiene i tipi condivisi tra codice client e server. In questo pacchetto, questi tipi sono definiti usando Zod, una libreria TypeScript-first per dichiarazione e validazione di schemi.
Uno schema di esempio potrebbe essere:
import { z } from 'zod';
// Definizione dello schemaexport const UserSchema = z.object({ name: z.string(), height: z.number(), dateOfBirth: z.string().datetime(),});
// Tipo TypeScript corrispondenteexport type User = z.TypeOf<typeof UserSchema>;
Dato lo schema sopra, il tipo User
è equivalente al seguente TypeScript:
interface User { name: string; height: number; dateOfBirth: string;}
Gli schemi sono condivisi sia dal codice server che client, fornendo un unico punto di aggiornamento per modifiche alle strutture usate nella tua API.
Gli schemi sono automaticamente validati dalla tua API tRPC a runtime, evitando la necessità di scrivere logiche di validazione manuali nel backend.
Zod fornisce utility potenti per combinare o derivare schemi come .merge
, .pick
, .omit
e altri. Puoi trovare maggiori informazioni sul sito della documentazione Zod.
Router e Procedure
Sezione intitolata “Router e Procedure”Il punto di ingresso della tua API si trova in src/router.ts
. Questo file contiene il gestore Lambda che instrada le richieste alle “procedure” in base all’operazione invocata. Ogni procedura definisce l’input atteso, l’output e l’implementazione.
Il router di esempio generato per te ha una singola operazione chiamata echo
:
import { echo } from './procedures/echo.js';
export const appRouter = router({ echo,});
La procedura echo
di esempio è generata in src/procedures/echo.ts
:
export const echo = publicProcedure .input(EchoInputSchema) .output(EchoOutputSchema) .query((opts) => ({ result: opts.input.message }));
Analizzando il codice:
publicProcedure
definisce un metodo pubblico sull’API, includendo il middleware configurato insrc/middleware
. Questo middleware include l’integrazione con AWS Lambda Powertools per logging, tracciamento e metriche.input
accetta uno schema Zod che definisce l’input atteso per l’operazione. Le richieste per questa operazione sono automaticamente validate rispetto a questo schema.output
accetta uno schema Zod che definisce l’output atteso. Vedrai errori di tipo nell’implementazione se non restituisci un output conforme allo schema.query
accetta una funzione che definisce l’implementazione della tua API. Questa implementazione riceveopts
, che contiene l’input
passato all’operazione, oltre ad altro contesto configurato dal middleware, disponibile inopts.ctx
. La funzione passata aquery
deve restituire un output conforme allo schemaoutput
.
L’uso di query
per definire l’implementazione indica che l’operazione non è mutativa. Usalo per definire metodi di recupero dati. Per operazioni mutative, usa invece il metodo mutation
.
Se aggiungi una nuova procedura, assicurati di registrarla aggiungendola al router in src/router.ts
.
Personalizzare la tua API tRPC
Sezione intitolata “Personalizzare la tua API tRPC”Nella tua implementazione, puoi restituire errori ai client lanciando un TRPCError
. Questi accettano un code
che indica il tipo di errore, ad esempio:
throw new TRPCError({ code: 'NOT_FOUND', message: 'La risorsa richiesta non è stata trovata',});
Organizzare le Operazioni
Sezione intitolata “Organizzare le Operazioni”Man mano che la tua API cresce, potresti voler raggruppare operazioni correlate.
Puoi raggruppare operazioni usando router annidati, ad esempio:
import { getUser } from './procedures/users/get.js';import { listUsers } from './procedures/users/list.js';
const appRouter = router({ users: router({ get: getUser, list: listUsers, }), ...})
I client riceveranno questo raggruppamento, ad esempio invocare l’operazione listUsers
apparirebbe così:
client.users.list.query();
Logging
Sezione intitolata “Logging”Il logger AWS Lambda Powertools è configurato in src/middleware/logger.ts
, e può essere accessibile in un’implementazione API via opts.ctx.logger
. Puoi usarlo per loggare su CloudWatch Logs, e/o controllare valori aggiuntivi da includere in ogni messaggio di log strutturato. Ad esempio:
export const echo = publicProcedure .input(...) .output(...) .query(async (opts) => { opts.ctx.logger.info('Operazione chiamata con input', opts.input);
return ...; });
Per maggiori informazioni sul logger, consulta la documentazione AWS Lambda Powertools Logger.
Registrare Metriche
Sezione intitolata “Registrare Metriche”Le metriche AWS Lambda Powertools sono configurate in src/middleware/metrics.ts
, e possono essere accessibili in un’implementazione API via opts.ctx.metrics
. Puoi usarle per registrare metriche in CloudWatch senza bisogno di importare e usare l’AWS SDK, ad esempio:
export const echo = publicProcedure .input(...) .output(...) .query(async (opts) => { opts.ctx.metrics.addMetric('Invocations', 'Count', 1);
return ...; });
Per maggiori informazioni, consulta la documentazione AWS Lambda Powertools Metrics.
Ottimizzare il Tracciamento X-Ray
Sezione intitolata “Ottimizzare il Tracciamento X-Ray”Il tracer AWS Lambda Powertools è configurato in src/middleware/tracer.ts
, e può essere accessibile in un’implementazione API via opts.ctx.tracer
. Puoi usarlo per aggiungere tracce con AWS X-Ray per fornire insight dettagliati sulle prestazioni e il flusso delle richieste API. Ad esempio:
export const echo = publicProcedure .input(...) .output(...) .query(async (opts) => { const subSegment = opts.ctx.tracer.getSegment()!.addNewSubsegment('MyAlgorithm'); // ... logica del mio algoritmo da tracciare subSegment.close();
return ...; });
Per maggiori informazioni, consulta la documentazione AWS Lambda Powertools Tracer.
Implementare Middleware Personalizzati
Sezione intitolata “Implementare Middleware Personalizzati”Puoi aggiungere valori aggiuntivi al contesto fornito alle procedure implementando middleware.
Come esempio, implementiamo un middleware per estrarre dettagli sull’utente chiamante dalla nostra API in src/middleware/identity.ts
.
Questo esempio assume che auth
sia impostato a IAM
. Per autenticazione Cognito, il middleware di identità è più diretto, estraendo i claim rilevanti dall’event
.
Prima definiamo cosa aggiungeremo al contesto:
export interface IIdentityContext { identity?: { sub: string; username: string; };}
Nota che definiamo una proprietà opzionale aggiuntiva al contesto. tRPC gestisce l’assicurarsi che questa sia definita nelle procedure che hanno configurato correttamente questo middleware.
Poi implementiamo il middleware stesso. Ha la seguente struttura:
export const createIdentityPlugin = () => { const t = initTRPC.context<...>().create(); return t.procedure.use(async (opts) => { // Aggiungi logica qui da eseguire prima della procedura
const response = await opts.next(...);
// Aggiungi logica qui da eseguire dopo la procedura
return response; });};
Nel nostro caso, vogliamo estrarre dettagli sull’utente Cognito chiamante. Lo faremo estraendo l’ID subject (o “sub”) dell’utente dall’evento API Gateway, e recuperando i dettagli utente da Cognito. L’implementazione varia leggermente a seconda che l’evento sia fornito da un’API REST o HTTP:
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: `Impossibile determinare l'utente chiamante`, }); }
const { Users } = await cognito.listUsers({ // Assume che l'ID user pool sia configurato nell'ambiente lambda UserPoolId: process.env.USER_POOL_ID!, Limit: 1, Filter: `sub="${sub}"`, });
if (!Users || Users.length !== 1) { throw new TRPCError({ code: 'FORBIDDEN', message: `Nessun utente trovato con subjectId ${sub}`, }); }
// Fornisci l'identità ad altre procedure nel contesto return await opts.next({ ctx: { ...opts.ctx, identity: { sub, username: Users[0].Username!, }, }, }); });};
import { CognitoIdentityProvider } from '@aws-sdk/client-cognito-identity-provider';import { initTRPC, TRPCError } from '@trpc/server';import { CreateAWSLambdaContextOptions } from '@trpc/server/adapters/aws-lambda';import { APIGatewayProxyEventV2WithIAMAuthorizer } from 'aws-lambda';
export interface IIdentityContext { identity?: { sub: string; username: string; };}
export const createIdentityPlugin = () => { const t = initTRPC.context<IIdentityContext & CreateAWSLambdaContextOptions<APIGatewayProxyEventV2WithIAMAuthorizer>>().create();
const cognito = new CognitoIdentityProvider();
return t.procedure.use(async (opts) => { const cognitoIdentity = opts.ctx.event.requestContext?.authorizer?.iam ?.cognitoIdentity as unknown as | { amr: string[]; } | undefined;
const sub = (cognitoIdentity?.amr ?? []) .flatMap((s) => (s.includes(':CognitoSignIn:') ? [s] : [])) .map((s) => { const parts = s.split(':'); return parts[parts.length - 1]; })?.[0];
if (!sub) { throw new TRPCError({ code: 'FORBIDDEN', message: `Impossibile determinare l'utente chiamante`, }); }
const { Users } = await cognito.listUsers({ // Assume che l'ID user pool sia configurato nell'ambiente lambda UserPoolId: process.env.USER_POOL_ID!, Limit: 1, Filter: `sub="${sub}"`, });
if (!Users || Users.length !== 1) { throw new TRPCError({ code: 'FORBIDDEN', message: `Nessun utente trovato con subjectId ${sub}`, }); }
// Fornisci l'identità ad altre procedure nel contesto return await opts.next({ ctx: { ...opts.ctx, identity: { sub, username: Users[0].Username!, }, }, }); });};
Deploy della tua API tRPC
Sezione intitolata “Deploy della tua API tRPC”Il generatore di API tRPC crea infrastruttura come codice CDK o Terraform in base al iacProvider
selezionato. Puoi usarlo per fare il deploy della tua API tRPC.
Il costrutto CDK per il deploy della tua API si trova nella cartella common/constructs
. Puoi consumarlo in un’applicazione CDK, ad esempio:
import { MyApi } from ':my-scope/common-constructs`;
export class ExampleStack extends Stack { constructor(scope: Construct, id: string) { // Aggiungi l'api allo stack const api = new MyApi(this, 'MyApi', { integrations: MyApi.defaultIntegrations(this).build(), }); }}
Questo configura l’infrastruttura API, inclusa un’API AWS API Gateway REST o HTTP, funzioni AWS Lambda per la business logic, e autenticazione basata sul metodo auth
scelto.
I moduli Terraform per il deploy della tua API si trovano nella cartella common/terraform
. Puoi usarli in una configurazione Terraform:
module "my_api" { source = "../../common/terraform/src/app/apis/my-api"
# Variabili d'ambiente per la funzione Lambda env = { ENVIRONMENT = var.environment LOG_LEVEL = "INFO" }
# Politiche IAM aggiuntive se necessarie additional_iam_policy_statements = [ # Aggiungi permessi aggiuntivi richiesti dalla tua API ]
tags = local.common_tags}
Questo configura:
- Una funzione AWS Lambda che serve tutte le procedure tRPC
- API Gateway HTTP/REST API come trigger della funzione
- Ruoli e permessi IAM
- Gruppo di log CloudWatch
- Configurazione tracciamento X-Ray
- Configurazione CORS
Il modulo Terraform fornisce diversi output utilizzabili:
# Accedi all'endpoint APIoutput "api_url" { value = module.my_api.stage_invoke_url}
# Accedi ai dettagli della funzione Lambdaoutput "lambda_function_name" { value = module.my_api.lambda_function_name}
# Accedi al ruolo IAM per concedere permessi aggiuntivioutput "lambda_execution_role_arn" { value = module.my_api.lambda_execution_role_arn}
Puoi personalizzare le impostazioni CORS passando variabili al modulo:
module "my_api" { source = "../../common/terraform/src/app/apis/my-api"
# Configurazione CORS personalizzata cors_allow_origins = ["https://myapp.com", "https://staging.myapp.com"] cors_allow_methods = ["GET", "POST", "PUT", "DELETE"] cors_allow_headers = [ "authorization", "content-type", "x-custom-header" ]
tags = local.common_tags}
Integrazioni
Sezione intitolata “Integrazioni”I costrutti CDK per le API REST/HTTP sono configurati per fornire un’interfaccia type-safe per definire le integrazioni per ciascuna delle tue operazioni.
I costrutti CDK forniscono supporto completo per l’integrazione type-safe come descritto di seguito.
Integrazioni Predefinite
Sezione intitolata “Integrazioni Predefinite”Puoi utilizzare il metodo statico defaultIntegrations
per sfruttare il pattern predefinito, che definisce una singola funzione AWS Lambda per ogni operazione:
new MyApi(this, 'MyApi', { integrations: MyApi.defaultIntegrations(this).build(),});
I moduli Terraform utilizzano automaticamente il router pattern con una singola funzione Lambda. Nessuna configurazione aggiuntiva è necessaria:
module "my_api" { source = "../../common/terraform/src/app/apis/my-api"
# Il modulo crea automaticamente una singola funzione Lambda # che gestisce tutte le operazioni API tags = local.common_tags}
Accesso alle Integrazioni
Sezione intitolata “Accesso alle Integrazioni”Puoi accedere alle funzioni AWS Lambda sottostanti tramite la proprietà integrations
del costrutto API in modo type-safe. Ad esempio, se la tua API definisce un’operazione chiamata sayHello
e devi aggiungere dei permessi a questa funzione, puoi farlo come segue:
const api = new MyApi(this, 'MyApi', { integrations: MyApi.defaultIntegrations(this).build(),});
// sayHello è tipizzato in base alle operazioni definite nella tua APIapi.integrations.sayHello.handler.addToRolePolicy(new PolicyStatement({ effect: Effect.ALLOW, actions: [...], resources: [...],}));
Con il router pattern di Terraform, esiste solo una funzione Lambda. Puoi accedervi tramite gli output del modulo:
# Concedi permessi aggiuntivi alla singola funzione Lambdaresource "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/*" } ] })}
Personalizzazione delle Opzioni Predefinite
Sezione intitolata “Personalizzazione delle Opzioni Predefinite”Se desideri personalizzare le opzioni utilizzate durante la creazione delle funzioni Lambda per ogni integrazione predefinita, puoi usare il metodo withDefaultOptions
. Ad esempio, per far risiedere tutte le funzioni Lambda in una VPC:
const vpc = new Vpc(this, 'Vpc', ...);
new MyApi(this, 'MyApi', { integrations: MyApi.defaultIntegrations(this) .withDefaultOptions({ vpc, }) .build(),});
Per personalizzare opzioni come la configurazione VPC, devi modificare il modulo Terraform generato. Esempio per aggiungere il supporto VPC:
# Aggiungi variabili VPCvariable "vpc_subnet_ids" { description = "Lista di ID subnet VPC per la funzione Lambda" type = list(string) default = []}
variable "vpc_security_group_ids" { description = "Lista di ID security group VPC per la funzione Lambda" type = list(string) default = []}
# Aggiorna la risorsa Lambda functionresource "aws_lambda_function" "api_lambda" { # ... configurazione esistente ...
# Aggiungi configurazione VPC vpc_config { subnet_ids = var.vpc_subnet_ids security_group_ids = var.vpc_security_group_ids }}
Utilizza il modulo con la configurazione VPC:
module "my_api" { source = "../../common/terraform/src/app/apis/my-api"
# Configurazione VPC vpc_subnet_ids = [aws_subnet.private_a.id, aws_subnet.private_b.id] vpc_security_group_ids = [aws_security_group.lambda_sg.id]
tags = local.common_tags}
Override delle Integrazioni
Sezione intitolata “Override delle Integrazioni”Puoi sovrascrivere le integrazioni per operazioni specifiche usando il metodo withOverrides
. Ogni override deve specificare una proprietà integration
tipizzata correttamente. Esempio per reindirizzare un’API getDocumentation
:
new MyApi(this, 'MyApi', { integrations: MyApi.defaultIntegrations(this) .withOverrides({ getDocumentation: { integration: new HttpIntegration('https://example.com/documentation'), }, }) .build(),});
Le integrazioni sovrascritte non avranno più la proprietà handler
quando accedute tramite api.integrations.getDocumentation
.
Puoi aggiungere proprietà personalizzate alle integrazioni mantenendo il type-safety. Esempio con integrazione S3:
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(),});
// Accesso type-safe alla proprietà bucket definitaapi.integrations.getFile.bucket.grantRead(...);
Override degli Authorizer
Sezione intitolata “Override degli Authorizer”Puoi sovrascrivere gli authorizer specificando options
nelle integrazioni. Esempio con autenticazione Cognito:
new MyApi(this, 'MyApi', { integrations: MyApi.defaultIntegrations(this) .withOverrides({ getDocumentation: { integration: new HttpIntegration('https://example.com/documentation'), options: { authorizer: new CognitoUserPoolsAuthorizer(...) // Per REST API } }, }) .build(),});
Integrazioni Esplicite
Sezione intitolata “Integrazioni Esplicite”Puoi definire manualmente ogni integrazione. Utile per usare tipi diversi per ogni operazione:
new MyApi(this, 'MyApi', { integrations: { sayHello: { integration: new LambdaIntegration(...), }, getDocumentation: { integration: new HttpIntegration(...), }, },});
Per integrazioni esplicite con Terraform, modifica il modulo generato:
- Rimuovi le route proxy predefinite
- Sostituisci la singola Lambda con funzioni individuali
- Crea integrazioni specifiche per ogni operazione:
# Aggiungi funzioni Lambda individuali resource "aws_lambda_function" "say_hello_handler" { handler = "sayHello.handler" # ... configurazione ... }
# Crea integrazioni e route specifiche resource "aws_apigatewayv2_integration" "say_hello_integration" { integration_uri = aws_lambda_function.say_hello_handler.invoke_arn # ... configurazione ... }
# Aggiungi risorse API Gateway specifiche resource "aws_api_gateway_resource" "say_hello_resource" { path_part = "sayHello" }
resource "aws_api_gateway_method" "say_hello_method" { http_method = "POST" }
Router Pattern
Sezione intitolata “Router Pattern”Per usare una singola Lambda per tutte le richieste, modifica defaultIntegrations
:
export class MyApi<...> extends ... {
public static defaultIntegrations = (scope: Construct) => { const router = new Function(scope, 'RouterHandler', { ... }); return IntegrationBuilder.rest({ buildDefaultIntegration: (op) => ({ integration: new LambdaIntegration(router), }), }); };}
Il router pattern è l’approccio predefinito di Terraform:
module "my_api" { source = "../../common/terraform/src/app/apis/my-api" tags = local.common_tags}
Concedere Accesso (Solo IAM)
Sezione intitolata “Concedere Accesso (Solo IAM)”Se hai scelto di usare autenticazione IAM
, puoi concedere accesso alla tua API:
api.grantInvokeAccess(myIdentityPool.authenticatedRole);
# Crea una politica IAM per consentire l'invocazione dell'APIresource "aws_iam_policy" "api_invoke_policy" { name = "MyApiInvokePolicy" description = "Politica per consentire l'invocazione dell'API tRPC"
policy = jsonencode({ Version = "2012-10-17" Statement = [ { Effect = "Allow" Action = "execute-api:Invoke" Resource = "${module.my_api.api_execution_arn}/*/*" } ] })}
# Allega la politica a un ruolo IAM (es. per utenti autenticati)resource "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}
# O allega a un ruolo esistente per nomeresource "aws_iam_role_policy_attachment" "api_invoke_access_existing" { role = "MyExistingRole" policy_arn = aws_iam_policy.api_invoke_policy.arn}
Gli output chiave dal modulo API utilizzabili per politiche IAM sono:
module.my_api.api_execution_arn
- Per concedere permessi execute-api:Invokemodule.my_api.api_arn
- L’ARN API Gatewaymodule.my_api.lambda_function_arn
- L’ARN funzione Lambda
Server tRPC Locale
Sezione intitolata “Server tRPC Locale”Puoi usare il target serve
per eseguire un server locale per la tua API, ad esempio:
pnpm nx run @my-scope/my-api:serve
yarn nx run @my-scope/my-api:serve
npx nx run @my-scope/my-api:serve
bunx nx run @my-scope/my-api:serve
Il punto di ingresso per il server locale è src/local-server.ts
.
Questo ricaricherà automaticamente le modifiche alla tua API.
Invocare la tua API tRPC
Sezione intitolata “Invocare la tua API tRPC”Puoi creare un client tRPC per invocare la tua API in modo type-safe. Se stai chiamando la tua API tRPC da un altro backend, puoi usare il client in src/client/index.ts
, ad esempio:
import { createMyApiClient } from ':my-scope/my-api';
const client = createMyApiClient({ url: 'https://my-api-url.example.com/' });
await client.echo.query({ message: 'Hello world!' });
Se stai chiamando la tua API da un sito React, considera di usare il generatore API Connection per configurare il client.
Ulteriori Informazioni
Sezione intitolata “Ulteriori Informazioni”Per maggiori informazioni su tRPC, consulta la documentazione tRPC.