GraphQL: peça só os campos que quiser
Numa API comum, quem escreve o servidor decide o que vem na resposta. Em GraphQL, quem decide é quem faz o pedido. O servidor publica a lista do que existe, e cada cliente monta a resposta que precisa naquela tela.
O que GraphQL resolve
Uma tela de aplicativo mostra a foto e o nome de um livro. A rota que devolve esse livro manda quarenta campos, porque foi desenhada para a tela de detalhe. Trinta e oito atravessam a rede de graça, no 4G do usuário, toda vez que a lista carrega.
O outro lado do mesmo problema aparece na tela seguinte. Falta um dado, a rota não tem ele, e o app dispara três chamadas em sequência para montar uma coisa só. Os dois nomes dessa dor são over-fetching e under-fetching, e a resposta do GraphQL para os dois é a mesma: mover a escolha dos campos do servidor para o pedido.
Os conceitos que você precisa antes da primeira linha
- Schema. O contrato do servidor, escrito numa linguagem própria chamada SDL. Ele declara quais tipos existem, quais campos cada tipo tem e de que tipo é cada campo. Nada que esteja fora do schema pode ser pedido, e o servidor recusa antes de executar qualquer coisa.
- Tipo e campo. Um tipo agrupa campos que andam juntos, como
Livrocomtitulo,autoreano. Campos apontam para outros tipos, e é assim que o schema vira um grafo em vez de uma lista de rotas. - Query. A operação de leitura. Você escreve o formato que quer e o servidor devolve JSON com exatamente esse formato, campo por campo, na mesma hierarquia. Escrever a consulta já é escrever o desenho da resposta.
- Resolver. A função que sabe onde buscar o valor de um campo. Um resolver lê do banco, outro chama uma API de terceiro, outro devolve uma constante. O GraphQL só chama os resolvers dos campos que apareceram no pedido.
- Um endereço só. Um servidor GraphQL costuma expor uma única rota, quase sempre
/graphql, e recebe tudo porPOST. O que muda entre um pedido e outro é o corpo da requisição, nunca a URL.
O contrato por dentro: schema, tipos e a consulta que escolhe campos
GraphQL troca os vários endereços do REST por um endpoint só, e move o contrato pro schema: uma declaração tipada de tudo que a API sabe responder. É tipagem estática aplicada à API: o cliente sabe de antemão que campos existem e de que tipo, e uma consulta pedindo campo inexistente é recusada antes de tocar em banco.
- O schema define tipos com campos:
type Cliente { id: ID!, nome: String!, pedidos: [Pedido!]! }. A exclamação é "nunca nulo", os colchetes são lista. Os tipos base (Int,Float,String,Boolean,ID) são os scalars. - Query lê, mutation escreve: a consulta tem a forma do dado que volta, e o cliente pede só os campos que quer, inclusive atravessando relações num pedido só. É a resposta ao under/overfetching que a seção anterior descreveu.
- Resolver é quem busca de verdade: cada campo do schema tem uma função no servidor que sabe encontrá-lo (no banco, num serviço, onde for). O GraphQL é a fachada tipada, e o dado continua vindo de onde sempre veio.
# a consulta tem a forma da resposta
query {
cliente(id: 42) {
nome
pedidos {
total
}
}
}
# resposta: só o que foi pedido
{ "data": { "cliente": {
"nome": "Ana",
"pedidos": [ { "total": 150.0 } ] } } }
Compare com o REST da página anterior: lá o servidor decide a forma da resposta, aqui o cliente desenha. Nenhum dos dois é upgrade do outro: são contratos diferentes pra necessidades diferentes.
Hello world: uma API GraphQL em seis passos
O caminho abaixo é o da documentação oficial do GraphQL.js, com Express e o pacote graphql-http. São três dependências e um arquivo.
-
Abra o terminal e confira se o Node.js está na máquina:
node --version npm --versionSe o terminal responder que o comando não existe, instale a versão LTS antes de seguir. Veja a página de Node.js para o passo a passo.
-
Crie a pasta do projeto e prepare o
package.json:mkdir hello-graphql cd hello-graphql npm init -y npm pkg set type=moduleA última linha marca o projeto como módulo ES, que é o que permite escrever
importem vez derequireno arquivo do servidor. -
Instale as três dependências:
npm install express graphql-http graphql --saveEsse é o comando da documentação oficial. O
graphqlé o motor que interpreta e executa a consulta, ographql-httptraduz requisição HTTP para chamada do motor, e oexpressé o servidor web que atende a porta. -
Crie um arquivo
server.jsna pasta, com este conteúdo:import { buildSchema } from 'graphql'; import { createHandler } from 'graphql-http/lib/use/express'; import express from 'express'; // O schema declara os campos que existem. O cliente escolhe quais quer. const schema = buildSchema(` type Livro { id: ID titulo: String autor: String ano: Int paginas: Int sinopse: String } type Query { livro: Livro } `); // O resolver devolve o objeto inteiro. Quem corta é o GraphQL. const root = { livro() { return { id: '1', titulo: 'Dom Casmurro', autor: 'Machado de Assis', ano: 1899, paginas: 256, sinopse: 'Bentinho conta a própria vida e tenta provar uma suspeita que nunca sai do lugar.', }; }, }; const app = express(); app.all('/graphql', createHandler({ schema: schema, rootValue: root })); app.listen(4000); console.log('Servidor GraphQL no ar em http://localhost:4000/graphql');Repare no
root. Ele devolve os seis campos sempre, sem saber o que foi pedido. Quem recorta a resposta é o motor do GraphQL, depois, comparando o objeto com a consulta que chegou. -
Suba o servidor:
node server.jsDeixe esse terminal aberto. Para encerrar depois, aperte Ctrl + C.
-
Abra um segundo terminal e envie as duas consultas. Primeiro pedindo um campo:
curl -X POST http://localhost:4000/graphql \ -H 'Content-Type: application/json' \ -d '{"query":"{ livro { titulo } }"}'Agora pedindo os seis, para o mesmo endereço:
curl -X POST http://localhost:4000/graphql \ -H 'Content-Type: application/json' \ -d '{"query":"{ livro { id titulo autor ano paginas sinopse } }"}'
A prova de que funcionou. As duas respostas têm tamanhos diferentes, e a URL foi a mesma nas duas vezes. A primeira volta assim:
{"data":{"livro":{"titulo":"Dom Casmurro"}}}
E a segunda volta assim:
{"data":{"livro":{"id":"1","titulo":"Dom Casmurro","autor":"Machado de Assis","ano":1899,"paginas":256,"sinopse":"Bentinho conta a própria vida e tenta provar uma suspeita que nunca sai do lugar."}}}
Aqui foram 44 bytes contra 200 bytes no mesmo POST /graphql, no mesmo servidor, com o mesmo resolver rodando. Nenhuma rota nova foi criada para a versão curta. É esse o ponto inteiro do GraphQL, e ele cabe nessas duas linhas de terminal.
Para ver o contrato agindo, peça um campo que não existe no schema:
curl -X POST http://localhost:4000/graphql \
-H 'Content-Type: application/json' \
-d '{"query":"{ livro { editora } }"}'
A resposta é Cannot query field "editora" on type "Livro", com a linha e a coluna do erro. O servidor recusou antes de chamar o resolver. Se o terminal do servidor reclamar de EADDRINUSE, outro programa ocupa a porta 4000. Troque o 4000 por 4001 no arquivo e nos comandos curl.
O que GraphQL não é
A confusão mais comum é achar que GraphQL fala com o banco de dados. O nome tem "QL" de query language, a consulta parece SQL de longe, e a conclusão vem sozinha: bastaria apontar o GraphQL para o banco e ele resolveria o resto.
Não funciona assim. GraphQL é um protocolo entre cliente e servidor, e a documentação oficial responde direto à pergunta de sempre sobre substituir ORM: a especificação é agnóstica à fonte de dados e não implementa mapeamento objeto-relacional. Quem busca o dado é o resolver que você escreve, e ele pode ler de PostgreSQL, de um arquivo, de outra API ou de uma constante, como no exemplo acima.
A consequência prática aparece no primeiro projeto real. Se um campo do schema for lento, o problema está no resolver dele, não na consulta que o cliente escreveu. E a consulta que pede uma lista com um campo aninhado dispara um resolver por item, o famoso N+1, que continua sendo trabalho de quem escreve o servidor.
Fontes
- GraphQL, Introduction to GraphQL, a introdução oficial ao schema, às queries e aos resolvers. Conferida em 15/08/2026.
- GraphQL.js, Running an Express GraphQL Server, de onde saíram o comando
npm install express graphql-http graphql --save, o uso debuildSchemae o esqueleto doserver.jscomapp.all('/graphql', createHandler(...))na porta 4000. Conferida em 15/08/2026. - GraphQL.js, graphql-http, a página que documenta o
createHandlere o import degraphql-http/lib/use/express. Conferida em 15/08/2026. - GraphQL FAQ, General, onde está a resposta "Does GraphQL replace ORMs? No", usada na seção sobre banco de dados. Conferida em 15/08/2026.
O hello world desta página foi executado em 15/08/2026, numa pasta vazia, com Node.js v22.23.0 e npm 10.9.8. O npm install trouxe express 5.2.1, graphql-http 1.23.0 e graphql 17.0.2. O servidor subiu na porta 4000 e imprimiu a linha do console.log. A consulta de um campo devolveu 44 bytes e a de seis campos devolveu 200 bytes, os dois JSON exatamente como estão transcritos acima. A consulta com o campo editora devolveu a mensagem de erro citada.
Para continuar
O próximo passo é REST, que resolve o mesmo problema por outro caminho, com uma rota por recurso e o significado carregado pelo verbo e pelo código de status. O servidor deste tutorial rodou sobre Node.js, e entender o que acontece embaixo do Express ajuda quando a porta não abre. O mapa tem o resto da stack.
O curso desta trilha está em preparação. A lista paga menos.
Os tutoriais daqui continuam gratuitos. O que está a caminho é um curso pago que transforma esse mapa em formação guiada, na ordem certa e com projeto. Deixe seu e-mail: você recebe os estudos novos gratuitos e, no lançamento, o desconto de quem entrou na lista primeiro.