O problema do REST
No REST cada recurso é uma URL. Isso leva a dois incômodos frequentes:
- Over-fetching:
GET /usuarios/1te devolve todos os campos mesmo que você só precise do nome. - Under-fetching: para renderizar uma tela às vezes são necessárias várias
chamadas (
/usuarios/1, depois/usuarios/1/pedidos...), o clássico problema "N+1 requisições".
GraphQL
GraphQL oferece um único endpoint (/graphql) e um schema tipado
que descreve quais dados existem. O cliente pede exatamente os campos de que
precisa, nem mais nem menos, em uma única requisição.
type Usuario {
id: ID!
nome: String!
email: String!
}
type Query {
usuario(id: ID!): Usuario
}
Uma query (leitura) declara o formato exato do que quer:
query {
usuario(id: "1") {
nome # peço só nome e email,
email # não o resto dos campos
}
}
E uma mutation (escrita) cria ou modifica dados:
mutation {
crearUsuario(nome: "Ana") {
id
}
}
Resolvers
Por trás de cada campo do schema há uma função chamada resolver, que resolve (calcula ou busca) o valor desse campo. Um resolver não é mágica: é só uma função. Recebe argumentos padrão:
// resolver(pai, args, contexto, info)
const resolvers = {
Query: {
usuario(_pai, args, contexto) {
return contexto.usuarios.find((u) => u.id === args.id);
},
},
};
- pai: o resultado do campo de nível superior (raiz: costuma ser ignorado).
- args: os argumentos da query (
{ id: "1" }). - contexto: dados compartilhados por requisição (BD, usuário autenticado...).
O motor do GraphQL percorre a query, chama o resolver de cada campo pedido e monta a resposta com o formato exato solicitado.