

Guia das APIs em Rust e todo código-fonte incluído © 2025 by Cleuton Sampaio is licensed under CC BY-SA 4.0
Este é um ebook interativo, com código-fonte disponível para você utilizar à vontade. Leia a licença de uso.
GraphQL é uma linguagem de consulta e um ambiente de execução para APIs criado pelo Facebook em 2012 e lançado publicamente em 2015. Diferente das APIs tradicionais baseadas em REST, onde você acessa dados por múltiplos endpoints pré-definidos, o GraphQL permite que o cliente peça exatamente os dados que precisa, de forma única e estruturada, em uma única requisição.
O cliente define a forma da resposta, quais campos, de quais objetos, com quais filtros e profundidade, e o servidor retorna apenas isso, sem sobrecarga. Ele funciona com um schema centralizado, escrito em SDL (Schema Definition Language), que descreve todos os tipos, campos, operações (queries, mutations, subscriptions) e suas relações, permitindo auto-documentação e validação em tempo de execução.
Além disso, suporta evolução contínua da API sem versão, pois novos campos podem ser adicionados sem quebrar clientes antigos. Entre as principais vantagens estão: redução de over-fetching e under-fetching de dados, menos round trips entre cliente e servidor, tipagem forte, introspecção (a API pode descrever a si mesma), melhor controle do cliente sobre os dados e maior eficiência em aplicações com interfaces complexas ou dispositivos móveis com conexão limitada. É especialmente útil em sistemas com múltiplos clientes (web, mobile, IoT) que precisam de diferentes combinações de dados da mesma fonte.
O exemplo monta um schema GraphQL bem enxuto, com um tipo Usuario que tem dois campos (id e nome), uma raiz de consultas (Query) e uma raiz de mutações (Mutation). Na Query você encontra o campo usuarios, que retorna uma lista fixa de usuários. Já na Mutation há o campo criarUsuario(id: Int, nome: String), que recebe um id e um nome, adiciona esse novo usuário ao vetor interno e devolve o objeto criado.
Tudo isso fica acessível em /graphql (para chamadas HTTP) e em /playground (uma IDE web que carrega automaticamente o schema e deixa você testar tanto a query usuarios quanto a mutação criarUsuario).

O arquivo main.rs implementa esta API:
use axum::{
routing::{get, post},
Extension, Router,
};
use async_graphql::{
Context, EmptySubscription, Object, Schema, SimpleObject,
};
use async_graphql_axum::{GraphQLRequest, GraphQLResponse};
use std::{net::SocketAddr, sync::{Arc, Mutex}};
use tower_http::cors::{Any, CorsLayer};
/// Objeto de domínio: usuário simples
#[derive(SimpleObject, Clone)]
struct Usuario {
id: i32,
nome: String,
}
/// Raiz das consultas (queries) GraphQL
struct RaizDeConsulta;
#[Object]
impl RaizDeConsulta {
/// Lê todos os usuários do estado compartilhado
async fn usuarios(&self, ctx: &Context<'_>) -> Vec<Usuario> {
let db = ctx.data::<Arc<Mutex<Vec<Usuario>>>>().unwrap();
let guard = db.lock().unwrap();
guard.clone()
}
}
/// Raiz das mutações (mutations) GraphQL
struct RaizDeMutacao;
#[Object]
impl RaizDeMutacao {
/// Cria um novo usuário e adiciona ao vetor compartilhado
async fn criar_usuario(&self, ctx: &Context<'_>, id: i32, nome: String) -> Usuario {
let usuario = Usuario { id, nome: nome.clone() };
let db = ctx.data::<Arc<Mutex<Vec<Usuario>>>>().unwrap();
db.lock().unwrap().push(usuario.clone());
usuario
}
}
#[tokio::main]
async fn main() {
// Estado inicial
let estado_usuarios = Arc::new(Mutex::new(vec![
Usuario { id: 1, nome: "Fulano".into() },
Usuario { id: 2, nome: "Cicrano".into() },
]));
// Monta o schema e injeta o estado como dado
let esquema = Schema::build(
RaizDeConsulta,
RaizDeMutacao,
EmptySubscription,
)
.data(estado_usuarios)
.finish();
// Constrói o servidor Axum
let aplicacao = Router::new()
.route("/graphql", post(manipulador_graphql))
.route("/playground", get(abrir_playground))
.layer(Extension(esquema))
.layer(CorsLayer::new().allow_origin(Any));
let endereco: SocketAddr = "0.0.0.0:4000".parse().unwrap();
println!("Playground em http://{}", endereco);
axum::Server::bind(&endereco)
.serve(aplicacao.into_make_service())
.await
.unwrap();
}
/// Handler principal de operações GraphQL
async fn manipulador_graphql(
Extension(esquema): Extension<Schema<RaizDeConsulta, RaizDeMutacao, EmptySubscription>>,
requisicao: GraphQLRequest,
) -> GraphQLResponse {
esquema.execute(requisicao.into_inner()).await.into()
}
/// Serve o GraphQL Playground (IDE web)
async fn abrir_playground() -> axum::response::Html<String> {
axum::response::Html(
async_graphql::http::playground_source(
async_graphql::http::GraphQLPlaygroundConfig::new("/graphql"),
)
)
}
Este exemplo monta uma API GraphQL em Rust de forma bem direta:
Usuario (com id e nome) anotado com #[derive(SimpleObject, Clone)], que gera automaticamente todo o código necessário para expor esse struct no schema GraphQL.Criamos duas “raízes”:
RaizDeConsulta (Query) com um método usuarios que, via ctx.data::<Arc<Mutex<Vec<Usuario>>>>(), acessa um vetor compartilhado de usuários e o retorna.RaizDeMutacao (Mutation) com um método criar_usuario(id, nome) que bloqueia o mutex, adiciona um novo Usuario ao vetor e devolve esse usuário.No main:
estado_usuarios como um Arc<Mutex<Vec<Usuario>>> com dois usuários iniciais.RaizDeConsulta, RaizDeMutacao e EmptySubscription, e injetamos estado_usuarios com .data(...).Montamos um servidor Axum que:
/graphql para processar queries e mutations via manipulador_graphql./playground para servir o Playground (IDE web interativa).cargo run sobe o servidor em 0.0.0.0:4000.No Playground você vê o schema carregado (tipos, queries e mutation) e pode testar, por exemplo:
query { usuarios { id nome } }
mutation { criarUsuario(id:3, nome:"Beltrano") { id nome } }
Tudo isso acontece de forma assíncrona (Tokio) e segura para concorrência (Arc<Mutex>).
O arquivo testes.txt tem exemplos de como invocar essa API com curl.