diff --git a/stack/trpc/explicacao.md b/stack/trpc/explicacao.md index ea09b2c..ceb59b4 100644 --- a/stack/trpc/explicacao.md +++ b/stack/trpc/explicacao.md @@ -1,13 +1,36 @@ --- -order: 3 +order: a icon: question label: "O que é tRPC?" --- -# O que é tRPC +# O que é tRPC? -A denominação tRPC é uma abreviação de "TypeScript Remote Procedure Call", uma biblioteca do TypeScript que se insipira no RPC (Remote Procedure Call), um protocolo específico de comunicação que permite a comunicação entre um cliente e servidor em diferentes dipostivos. +tRPC é uma **biblioteca para desenvolvedores TypeScript** de aplicações web, que permite a **criação de APIs** totalmente **tipadas** de ponta a ponta. -Essa biblioteca trabalha com uma estrutura que facilita a visualização dos endpoints (pontos de comunicação) e a compreensão do que se passa por eles. Deste modo, temos acesso aos tipos de dados, que estão sendo comunicados, pelo lado cliente e, assim, temos um melhor monitoramento do funcionamento e de possíveis erros. +Utilizando o poder do TypeScript para garantir segurança de tipos em todo o fluxo de dados, ela torna também fácil a maneira de escrever endpoints no backend, para serem usados de maneira segura no frontend, a partir dos contratos de API pré-estabelecidos no design do projeto -Em resumo, tRPC ajuda a tornar a comunicação entre cliente e servidor mais clara, segura e eficiente, uma vez que possibilita uma maior transparência dos dados percorridos no sistema. +## Conceitos Básicos de RPC e tRPC + +### O que é RPC? + +RPC, ou _Remote Procedure Call_, é um protocolo que permite chamar **procedimentos** (ou rotinas) em um computador (servidor), a partir de outro computador na rede (cliente), sem que o programador precise codificar explicitamente os detalhes que permitem essa interação remota. O RPC **abstrai a complexidade da comunicação de rede**, permitindo que o desenvolvedor se concentre na lógica do procedimento. + +Em _APIs HTTP/REST tradicionais_, você realiza uma requisição, por meio de um `URL`, e obtém uma resposta. Em uma _API RPC_, você chama uma `função` e obtém uma resposta. + +==- Rest x RPC + +```tsx +// HTTP/REST +const res = await fetch("/api/users/1"); +const user = await res.json(); + +// RPC +const user = await api.users.getById({ id: 1 }); +``` + +=== + +### Como o tRPC se Relaciona com RPC? + +tRPC é uma biblioteca que implementa o RPC e é projetada para _monorepos_ com TypeScript full-stack. diff --git a/stack/trpc/instalacao.md b/stack/trpc/instalacao.md index 60bd369..565bee5 100644 --- a/stack/trpc/instalacao.md +++ b/stack/trpc/instalacao.md @@ -1,41 +1,27 @@ --- -order: 2 +order: b icon: tools -label: "Instalação" +label: "Como instalar o tRPC?" --- -# Instalação +## Escolha seu ambiente -O tRPC possui vários tipos de pacotes com conteúdos extras, para instalar o pacote padrão: +O tRPC pode ser utilizado em uma varidade muito ampla de **_stacks_ diferentes**. Então, o seu **primeiro passo** é escolher **onde você quer utilizar o tRPC**. -!!! Requisitos +## Exemplos de Aplicações -- Deve-se certificar que a versão do TypeScript seja igual ou superior à versão 4.7.0. -- É recomendado a atribuição "strict": true no arquivo `tsconfig.json`, já que não há suporte para o contrário. - !!! +A documentação do tRPC inclui uma seção de `Example Apps`, que são _templates_ e _exemplos práticos_ para você **aproveitar** e implementar o tRPC em **diferentes cenários**. -+++ npm -`npm install @trpc/server @trpc/client` -+++ yarn -`yarn add @trpc/server @trpc/client` -+++ pnpm -`pnpm add @trpc/server @trpc/client` -+++ bun -`bun add @trpc/server @trpc/client` -+++ +[!ref icon="/assets/logos-tecnologias/trpc.svg"](https://trpc.io/docs/example-apps) -## Pacotes recomendados +## Sobre a configuração -Para projetos em Next.js é recomendado a instalação de uma versão que é uma combinação da versão para React (React Query) com algumas ferramentas específicas a mais de integração para o Next: +Para configurar o tRPC no backend, existem [adapters para diferentes frameworks](https://trpc.io/docs/server/adapters), bem como para [um simples repositório com Node.js](https://trpc.io/docs/quickstart). -+++ npm -`npm install @trpc/server @trpc/client @trpc/react-query @trpc/next @tanstack/react-query zod` -+++ yarn -`yarn add @trpc/server @trpc/client @trpc/react-query @trpc/next @tanstack/react-query zod` -+++ pnpm -`pnpm add @trpc/server @trpc/client @trpc/react-query @trpc/next @tanstack/react-query zod` -+++ bun -`bun add @trpc/server @trpc/client @trpc/react-query @trpc/next @tanstack/react-query zod` -+++ +Para o frontend, você pode olhar as integrações do próprio tRPC com [React (construiído a partir do React Query)](https://trpc.io/docs/client/react) ou com [Next.js](https://trpc.io/docs/client/nextjs), ou olhar por integrações de terceiros para uma série de frameworks, ou pode até mesmo configurar para [um simples repositório com TypeScript rodando](https://trpc.io/docs/client/vanilla/setup). -Para projetos somente em React, basta o mesmo procedimento anterior, agora sem o parâmetro `@trpc/next` e `zod` (caso não use zod em React) +## Próximos passos + +Escolhida sua **stack** e instaldao o **tRPC**, basta agora criar sua aplicação seguindo modelos ou design patterns definidos com sua equipe do projeto. + +Na próxima seção da nossa documentação, ["Como utilizar o tRPC?"](./utilizacao.md), abordaremos a configuração do tRPC utilizando o [T3 Stack](/stack/), uma combinação popular que inclui Next.js, Prisma, Tailwind CSS, entre outros. Fique atento! diff --git a/stack/trpc/pratica.md b/stack/trpc/pratica.md deleted file mode 100644 index 0e4f409..0000000 --- a/stack/trpc/pratica.md +++ /dev/null @@ -1,193 +0,0 @@ ---- -order: 1 -icon: rocket -label: Prática ---- - -# Prática - -tRPC é uma ferramenta para comunicação entre back-end e front-end, então começaremos definindo rotas no back: - -## Iniciando o tRPC no back-end - -A primeira tarefa a ser feita é iniciar o tRPC no back-end. O tRPC funciona através de chamadas de funções de um lado da aplicação para outro e, para termos acesso às propriedades e aos métodos dessa ferramenta, precisamos inicializar uma instância de roteador. - -Assim, criaremos um arquivo `trpc.ts` onde inicializaremos o tRPC por meio de uma `const t` (nome usado somente para exemplo) e exportaremos as propriedades `router`e `procedure` da instância. - -```ts "./server/trpc.ts" -import { initTRPC } from "@trpc/server"; - -const t = initTRPC.create(); -export const router = t.router; -export const publicProcedure = t.procedure; -``` - -
- -### Por que exportar? - -Exportamos duas propriedades que definimos no arquivo `trpc.ts` para facilitar o uso delas em quaisquer outros arquivos e alguma possível manutenção dessa aplicação, pois precisaremos fazer alterações no "arquivo fonte" e não em todos os lugares onde as usarmos. - -### Uso das propriedades - -Para o lado cliente poder se comunicar com o servidor é preciso definir "rotas de comunicação", pois é por meio das rotas que o servidor é direcionado ao procedimento/protocolo específico, definidas usando o `router`. - -Em seguida, a rota levará a um procedimento (`procedure`) no qual é passado uma função que pode chamar determinadas funções do banco de dados e/ou efetuar outras ações. Logo, também precisamos usar a propriedade `procedure` para definirmos o que deve ser feito e as funções a serem chamadas em uma determinada rota. - -No caso, `procedures` está definido como publicProcedure pois, no exemplo, definiremos requisições que não exigirão autenticação. - -## Definindo as rotas - -Então, importamos em outro arquivo, mais por questão de organização, as propriedades `router` e `publicProcedure` e definimos um conjunto de rotas em uma `const appRouter`. Também deve-se importar o banco de dados feito em sua aplicação, pois nas rotas serão definidas requisições para o mesmo. -
- -Para fazer as definições, é usado um objeto/dicionário onde as chaves serão os nomes das rotas e os valores serão as ações efetuadas no momento em que elas forem chamadas pelo lado cliente. - -```ts "./server/index.ts" -import { db } from "./db"; // Banco de dados previamente construído -import { publicProcedure, router } from "./trpc"; // Propriedades que exportamos no trpc.ts - -const appRouter = router({ - userList: publicProcedure.query(async () => { - const users = await db.user.findMany(); - return users; - }), -}); -``` - -Usamos o `publicProcedure`, que definirmos anteriormente, para efetuar requisições/procedimento ao servidor. -Um procedimento pode ser: - -- `query` busca de informação -- `mutation` criação, atualização ou delete de informação -- `subscription` cria uma ligação persistente com o servidor e recebe mudanças. É o famoso websocket. - -No caso, estamos definindo uma requisição `userList` que irá listar todos os usuários de um servidor, logo usamos `query`. - -## Entrada de Dados - -Para receber entrada de informações do lado cliente, basta usar o `input()` que irá receber informações e as retornará para o `query()` podendo ser, primeiramente, validadas, caso efetuado um tratamento de dados. -Usamos o pacote "zod" para fazer a validação da entrada de dados. -Os campos nos quais deseja fazer alguma validação coloque z.tipoDeDadoDesejado(), exemplo: - -```ts "./server/index.ts" -import { z } from "zod"; -const appRouter = router({ - userById: publicProcedure - .input(z.string()) // No caso queremos que o input seja uma string (o nome) - .query(async (opts) => { - const { input } = opts; - const user = await db.user.findById(input); - return user; - }), -}); -``` - -O `query()` recebe um objeto com várias informações como dados de contexto, de usuário, log-In etc. Portanto, para isolarmos os dados de entrada/input usamos o `{input}` que irá desestruturar o objeto e pegar somente os dados que queremos para fazermos as requisições. - -!!! -É possível passar um objeto com alguns parâmetros de mensagens personalizadas, por exemplo: - -```ts -const name = z.string({ - required_error: "É requirido um nome", - invalid_type_error: "O nome deve ser uma string", -}); -``` - -Para mais informações sobre o a validação de dados, clique [aqui](https://zod.dev) -!!! - -## Servidor - -O servidor é o que irá ouvir as requisições e, de acordo com as rotas definidas, dar uma determinada resposta. Porém, ainda não iniciamos nenhum servidor, logo, a seguinte etapa será iniciar um. É importado o método `createHTPPServer`do próprio tRPC, que irá criar o servidor, sendo necessário passar um roteador para o mesmo saber como reagir às requisições. Também usado o método listen, que define o endereço em que o servidor receberá requisições. - -```ts "./server/index.ts" -import { createHTTPServer } from "@trpc/server/adapters/standalone"; -const appRouter = router({ - // Todas as rotas aqui, anteriormente definidas. -}); -const server = createHTTPServer({ - router: appRouter, -}); -server.listen(3000); -``` - -## Configurando servidor no lado cliente - -### Definindo a conexão entre servidor e cliente - -Da mesma forma que é necessário criar um servidor para conseguir estabelecer uma comunicação com o cliente, é necessário haver no lado cliente uma maneira de se comunicar com o servidor, uma maneira por onde mandar suas requisições. - -O lado cliente fica ciente das informações que estão sendo manipuladas por meio dos tipos de dados do roteador. Logo, para estabelecer essa conexão primeiro temos que exportar o tipo do nosso roteador adicionando o seguinte trecho no arquivo `/server/index.ts`: - -```ts ./server/index.ts -export type AppRouter = typeof appRouter; -``` - -Então, o `AppRouter` é importado e passado ao método `createTRPCProxyclient` para a criação do proxy. Como é um argumento de tipo, ou seja, são passados os tipos de dados em que a função tem que trabalhar, ele é declarado entre os símbolos <>, uma característica do TypeScript. -
- -Assim, também iremos definir um `httpBatchLink` que é um tipo de link que lida com requisições em lote como se fosse uma, declarando o endereço do nosso servidor para efetuarmos as nossas requisições e de forma mais otimizada: - -```ts "./client/index.ts" -import { createTRPCProxyClient, httpBatchLink } from "@trpc/client"; -import type { AppRouter } from "./server/index.ts"; - -export const trpc = createTRPCProxyClient({ - links: [ - httpBatchLink({ - url: "http://localhost:3000", - }), - ], -}); -``` - -Com o proxy `trpc`, exportamos para facilitar o reuso em outros arquivos ou podemos manipulá-lo no mesmo. - -### Fazendo requisições no lado cliente - -Com o proxy definido e exportado, podemos importar o proxy `trpc` para qualquer arquivo e fazermos requisições através dele, no exemplo usaremos no mesmo arquivo: - -```ts "./client/index.ts" -// import trpc from "./client/index.ts" (Caso esteja manipulando -// o proxy em um arquivo diferente daquele em que foi definido, não é o caso) -import { createTRPCProxyClient, httpBatchLink } from "@trpc/client"; -import type { AppRouter } from "./server/index.ts"; - -export const trpc = createTRPCProxyClient({ - links: [ - httpBatchLink({ - url: "http://localhost:3000", - }), - ], -}); - -const user = await trpc.userById.query("1"); -const createdUser = await trpc.userCreate.mutate({ name: "sachinraja" }); -``` - -Como estabelecemos uma conexão cliente-servidor dos tipos de dados e definimos o endereço do servidor, temos acesso às rotas definidadas no back-end e podemos efetuar as requisições. -
- -Neste exemplo usamos a rota definida anteriormente `userById` para efetuarmos a requisição ao servidor, que irá responder com informações de um usuário filtrado pelo seu ID. Também usamos a rota `userCreate` que cria um usuário com nome. - -
- -#### - -::: sample -Para mais informações sobre tRPC, consulte [aqui](https://trpc.io/docs/quickstart) -::: - - diff --git a/stack/trpc/utilizacao/chamando-rotas.md b/stack/trpc/utilizacao/chamando-rotas.md new file mode 100644 index 0000000..b441655 --- /dev/null +++ b/stack/trpc/utilizacao/chamando-rotas.md @@ -0,0 +1,21 @@ +--- +order: c +icon: package-dependencies +label: Chamando as rotas +--- + +!!! +Essa documentação assume que você esteja usando o tRPC em um repositório T3 Stack +!!! + +## Server-side + +Para chamar uma rota tRPC e algumas procedures suas em um server component, assista ao vídeo abaixo: + +[!embed](https://youtu.be/j3pjQItk9Co?si=IZNdP1-IVxx27gW8) + +## Client-side + +Para chamar uma rota tRPC e algumas procedures suas em um client component, assista ao vídeo abaixo: + +[!embed](https://youtu.be/j3pjQItk9Co?si=IZNdP1-IVxx27gW8) diff --git a/stack/trpc/utilizacao/conceitos.md b/stack/trpc/utilizacao/conceitos.md new file mode 100644 index 0000000..ae9f774 --- /dev/null +++ b/stack/trpc/utilizacao/conceitos.md @@ -0,0 +1,19 @@ +--- +order: a +icon: project-roadmap +label: Alguns conceitos +--- + +Veremos aqui alguns termos que são **frequentemente usados no ecossistema do tRPC**, incluindo essa seção da documentação de como utilziar o tRPC. + +=== Procedure +Um endpoint da API, que criaremos em uma rota do backend e, então, chamaremos no frontend. Pode ser uma **query**, uma **mutation** ou uma **subscription**, porém só trataremos de queries e mutations aqui nesta documentação; +=== Query +Uma procedure para obter dados; +=== Mutation +Uma procedure para criar, atualizar ou deletar dados armazenados; +=== Router +Uma coleção de procedures (e/ou outros routers); +=== Context +Material externo que toda procedure pode acessar, para sua lógica interna. +=== diff --git a/stack/trpc/utilizacao/definindo-rotas.md b/stack/trpc/utilizacao/definindo-rotas.md new file mode 100644 index 0000000..a9698d0 --- /dev/null +++ b/stack/trpc/utilizacao/definindo-rotas.md @@ -0,0 +1,28 @@ +--- +order: b +icon: package-dependents +label: Definindo rotas +--- + +!!! +Essa documentação assume que você esteja usando o tRPC em um repositório T3 Stack +!!! + +## Criando uma query + +Para criar uma procedure cujo objetivo é recuperar dados do banco de dados, assista ao vídeo abaixo, onde demonstramos como: + +- Criar uma rota +- Criar uma query publica +- Utilizar o context em uma procedure + +[!embed](https://youtu.be/j3pjQItk9Co?si=IZNdP1-IVxx27gW8) + +## Criando uma mutation + +Para criar uma procedure cujo objetivo é alterar dados armazenados em um banco de dados, assista ao vídeo abaixo, onde demonstramos como: + +- Criar uma mutation protegida +- Utilizar o input em uma procedure + +[!embed](https://youtu.be/j3pjQItk9Co?si=IZNdP1-IVxx27gW8) diff --git a/stack/trpc/utilizacao/index.yml b/stack/trpc/utilizacao/index.yml new file mode 100644 index 0000000..306eae0 --- /dev/null +++ b/stack/trpc/utilizacao/index.yml @@ -0,0 +1,3 @@ +icon: command-palette +label: Como utilizar o tRPC? +order: c