Introdução
\n\nGraphQL é uma linguagem de consulta para APIs que permite que os clientes obtenham apenas os dados necessários. Em combinação com TypeScript, torna-se uma ferramenta poderosa para criar APIs com segurança de tipos, escaláveis e documentadas. Neste tutorial passo a passo, criaremos na prática uma API GraphQL completa em TypeScript usando Apollo Server e TypeGraphQL.
Você aprenderá:
\n- \n
- Como configurar um projeto com TypeScript e Apollo Server \n
- Como definir um schema GraphQL usando decoradores do TypeGraphQL \n
- Como escrever resolvers com tipagem completa \n
- Como conectar um banco de dados e executar consultas \n
Este material será útil tanto para iniciantes quanto para desenvolvedores já familiarizados com REST API, mas que desejam aprender a abordagem moderna para construir APIs.
\n\n1. Configuração do projeto e instalação de dependências
\n\nVamos começar com a inicialização do projeto. Certifique-se de ter Node.js (versão 16+) e npm/yarn instalados.
\n\nmkdir graphql-ts-tutorial\ncd graphql-ts-tutorial\nnpm init -y\n\nInstale os pacotes necessários:
\n\nnpm install apollo-server graphql reflect-metadata type-graphql class-validator\nnpm install -D typescript @types/node ts-node\n\nCrie o arquivo tsconfig.json:
{\n "compilerOptions": {\n "target": "ES2020",\n "module": "commonjs",\n "lib": ["ES2020"],\n "experimentalDecorators": true,\n "emitDecoratorMetadata": true,\n "strict": true,\n "esModuleInterop": true,\n "outDir": "./dist",\n "rootDir": "./src"\n },\n "include": ["src/**/*"]\n}\n\nObserve as flags experimentalDecorators e emitDecoratorMetadata — elas são necessárias para o funcionamento do TypeGraphQL.
2. Definição do schema e tipos com TypeGraphQL
\n\nCrie a pasta src e o arquivo src/types/User.ts. Aqui descreveremos o modelo de usuário.
import { ObjectType, Field, ID, InputType } from "type-graphql";\n\n@ObjectType()\nexport class User {\n @Field(() => ID)\n id!: number;\n\n @Field()\n name!: string;\n\n @Field()\n email!: string;\n\n @Field()\n createdAt!: Date;\n}\n\nExplicação:
\n- \n
@ObjectType()— marca a classe como um tipo GraphQL. \n @Field()— indica quais campos estarão disponíveis na API. \n @Field(() => ID)— para o tipo escalar ID. \n
Agora crie um InputType para mutações (criação de usuário):
@InputType()\nexport class CreateUserInput {\n @Field()\n name!: string;\n\n @Field()\n email!: string;\n}\n\nEste tipo será usado nos resolvers para validação dos dados de entrada.
\n\n3. Escrevendo os resolvers
\n\nCrie o arquivo src/resolvers/UserResolver.ts. Aqui implementaremos a lógica das consultas e mutações.
import { Resolver, Query, Mutation, Arg } from "type-graphql";\nimport { User, CreateUserInput } from "../types/User";\n\n// Simulação de banco de dados\nlet users: User[] = [\n { id: 1, name: "Ivan Ivanov", email: "ivan@example.com", createdAt: new Date() },\n { id: 2, name: "Maria Petrova", email: "maria@example.com", createdAt: new Date() }\n];\n\nlet nextId = 3;\n\n@Resolver()\nexport class UserResolver {\n @Query(() => [User])\n async users(): Promise<User[]> {\n return users;\n }\n\n @Query(() => User, { nullable: true })\n async user(@Arg("id") id: number): Promise<User | undefined> {\n return users.find(u => u.id === id);\n }\n\n @Mutation(() => User)\n async createUser(@Arg("data") data: CreateUserInput): Promise<User> {\n const newUser: User = {\n id: nextId++,\n name: data.name,\n email: data.email,\n createdAt: new Date()\n };\n users.push(ne