Pular para o conteúdo

tRPC

tRPC é um framework para construir APIs em TypeScript com segurança de tipos de ponta a ponta. Usando tRPC, atualizações nas entradas e saídas das operações da API são refletidas imediatamente no código do cliente e visíveis em sua IDE sem necessidade de reconstruir o projeto.

O gerador de API tRPC cria uma nova API tRPC com configuração de infraestrutura AWS CDK. O backend gerado utiliza AWS Lambda para implantação serverless e inclui validação de esquema usando Zod. Configura AWS Lambda Powertools para observabilidade, incluindo logging, rastreamento com AWS X-Ray e métricas no CloudWatch.

Uso

Gerar uma API tRPC

Você pode gerar uma nova API tRPC de duas formas:

  1. Instale o Nx Console VSCode Plugin se ainda não o fez
  2. Abra o console Nx no VSCode
  3. Clique em Generate (UI) na seção "Common Nx Commands"
  4. Procure por @aws/nx-plugin - ts#trpc-api
  5. Preencha os parâmetros obrigatórios
    • Clique em Generate

    Opções

    Parâmetro Tipo Padrão Descrição
    name Obrigatório 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.

    Saída do Gerador

    O gerador criará a seguinte estrutura de projeto no diretório <directory>/<api-name>:

    • Directoryschema
      • Directorysrc
        • index.ts Ponto de entrada do esquema
        • Directoryprocedures
          • echo.ts Definições de esquema compartilhadas para o procedimento “echo”, usando Zod
      • tsconfig.json Configuração TypeScript
      • project.json Configuração do projeto e targets de build
    • Directorybackend
      • Directorysrc
        • init.ts Inicialização do backend tRPC
        • router.ts Definição do roteador tRPC (ponto de entrada do handler Lambda)
        • Directoryprocedures Procedimentos (ou operações) expostos pela API
          • echo.ts Exemplo de procedimento
        • Directorymiddleware
          • error.ts Middleware para tratamento de erros
          • logger.ts Middleware para configurar AWS Powertools para logging em Lambda
          • tracer.ts Middleware para configurar AWS Powertools para rastreamento em Lambda
          • metrics.ts Middleware para configurar AWS Powertools para métricas em Lambda
        • local-server.ts Ponto de entrada do adaptador standalone tRPC para servidor de desenvolvimento local
        • Directoryclient
          • index.ts Cliente type-safe para chamadas máquina-a-máquina
      • tsconfig.json Configuração TypeScript
      • project.json Configuração do projeto e targets de build

    O gerador também criará constructs CDK para implantação da API, localizados no diretório packages/common/constructs.

    Implementando sua API tRPC

    Como visto acima, existem dois componentes principais em uma API tRPC: schema e backend, definidos como pacotes individuais no workspace.

    Schema

    O pacote schema define os tipos compartilhados entre clientes e servidor. Esses tipos são definidos usando Zod, uma biblioteca de declaração e validação de esquemas com foco em TypeScript.

    Um exemplo de esquema:

    import { z } from 'zod';
    // Definição do esquema
    export const UserSchema = z.object({
    name: z.string(),
    height: z.number(),
    dateOfBirth: z.string().datetime(),
    });
    // Tipo TypeScript correspondente
    export type User = z.TypeOf<typeof UserSchema>;

    O tipo User acima é equivalente a:

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

    Esquemas são validados automaticamente pela API tRPC em runtime, eliminando a necessidade de lógica de validação manual.

    Zod oferece utilitários poderosos como .merge, .pick, .omit e outros. Mais informações na documentação do Zod.

    Backend

    A pasta backend contém a implementação da API, onde são definidas operações, entradas, saídas e implementações.

    O ponto de entrada principal está em src/router.ts, que contém o handler Lambda que roteia requisições para os procedimentos. Cada procedimento define input, output e implementação.

    O roteador de exemplo possui uma operação echo:

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

    O procedimento echo em src/procedures/echo.ts:

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

    Explicação:

    • publicProcedure define um método público com middleware configurado em src/middleware
    • input aceita um esquema Zod para validação automática
    • output define o esquema de saída, gerando erros de tipo se não conformado
    • query define a implementação para operações não mutativas. Use mutation para operações mutativas

    Novas operações devem ser registradas em src/router.ts.

    Personalizando sua API tRPC

    Erros

    Retorne erros lançando TRPCError:

    throw new TRPCError({
    code: 'NOT_FOUND',
    message: 'Recurso não encontrado',
    });

    Organização de Operações

    Agrupe operações com roteadores aninhados:

    const appRouter = router({
    users: router({
    get: getUser,
    list: listUsers,
    }),
    })

    Clientes acessam como client.users.list.query().

    Logging

    O logger AWS Powertools está em src/middleware/logger.ts e é acessado via opts.ctx.logger:

    export const echo = publicProcedure
    .query(async (opts) => {
    opts.ctx.logger.info('Operação chamada com input', opts.input);
    });

    Consulte a documentação do Logger.

    Métricas

    Métricas são acessadas via opts.ctx.metrics:

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

    Veja documentação de Métricas.

    Rastreamento com X-Ray

    O tracer está em src/middleware/tracer.ts e é acessado via opts.ctx.tracer:

    export const echo = publicProcedure
    .query(async (opts) => {
    const subSegment = opts.ctx.tracer.getSegment()!.addNewSubsegment('MyAlgorithm');
    subSegment.close();
    });

    Consulte documentação do Tracer.

    Middleware Customizado

    Exemplo de middleware para extrair identidade do usuário:

    // Código REST permanece inalterado

    Implantando a API tRPC

    Use o construct CDK gerado em common/constructs:

    import { MyApi } from ':my-scope/common-constructs`;
    export class ExampleStack extends Stack {
    constructor(scope: Construct, id: string) {
    const api = new MyApi(this, 'MyApi', {
    integrations: MyApi.defaultIntegrations(this).build(),
    });
    }
    }

    Para autenticação Cognito:

    import { MyApi, UserIdentity } from ':my-scope/common-constructs';
    export class ExampleStack extends Stack {
    constructor(scope: Construct, id: string) {
    const identity = new UserIdentity(this, 'Identity');
    const api = new MyApi(this, 'MyApi', {
    identity,
    });
    }
    }

    Concessão de Acesso (IAM)

    Para autenticação IAM:

    api.grantInvokeAccess(myIdentityPool.authenticatedRole);

    Servidor Local

    Execute o servidor local com:

    Terminal window
    pnpm nx run @my-scope/my-api:serve

    Invocando a API

    Crie um cliente type-safe:

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

    Para React, use o gerador API Connection.

    Mais Informações

    Consulte a documentação do tRPC.