GraphQL vs REST em Go: o que escolher em 2025

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

GraphQL vs REST em Go: duelo de titãs, ou como não errar na escolha

\n\n

Se você programa em Go há pelo menos seis meses, certamente já se deparou com o debate eterno: REST ou GraphQL? Um é o bom e velho "cavalo de batalha", o outro é um "carro esportivo" moderno com várias opções. Mas no mundo Go, onde desempenho e simplicidade são religião, a escolha nem sempre é óbvia.

\n\n

Neste artigo, não vamos apenas listar prós e contras. Vamos escrever código real em Go, medir o tempo de execução e analisar quando GraphQL é um tiro no pé e quando é um passe VIP para o mundo das APIs eficientes. Vamos nessa!

\n\n

REST em Go: estabilidade e previsibilidade

\n\n

REST é como um martelo velho e testado. Não brilha, mas martela pregos perfeitamente. Em Go, APIs REST são escritas com net/http ou frameworks leves como gin e chi. Vamos ver um exemplo simples:

\n\n
package main\n\nimport (\n    "encoding/json"\n    "net/http"\n)\n\ntype User struct {\n    ID   int    `json:"id"`\n    Name string `json:"name"`\n}\n\nfunc getUserHandler(w http.ResponseWriter, r *http.Request) {\n    user := User{ID: 1, Name: "Alexei"}\n    w.Header().Set("Content-Type", "application/json")\n    json.NewEncoder(w).Encode(user)\n}\n\nfunc main() {\n    http.HandleFunc("/api/user", getUserHandler)\n    http.ListenAndServe(":8080", nil)\n}
\n\n

Bonito? Sim. Simples? Muito. Mas e se o frontend precisar apenas do nome do usuário e estivermos enviando o objeto inteiro? Em REST, isso é chamado de over-fetching — excesso de dados. E em Go, onde estamos acostumados a controlar cada byte, isso pode irritar.

\n\n

O problema N+1 no REST

\n\n

Suponha que temos uma lista de pedidos e para cada um precisamos do nome do usuário. No REST, fazemos N requisições (lento) ou criamos um endpoint separado /api/orders-with-users (vários endpoints). Go lida com isso através de consultas JOIN no banco de dados, mas no nível da API ainda parece rústico.

\n\n

GraphQL em Go: potência e flexibilidade

\n\n

GraphQL é como um canivete suíço: um único endpoint, e o cliente decide quais dados precisa. Em Go, existe o framework gqlgen (da 99designs) — ele gera código a partir do schema, o que é bem no estilo Go (menos boilerplate, mais ação).

\n\n
// schema.graphql\ntype Query {\n    user(id: Int!): User\n}\n\ntype User {\n    id: Int!\n    name: String!\n    orders: [Order!]!\n}\n\ntype Order {\n    id: Int!\n    total: Float!\n}
\n\n

Agora a implementação em Go:

\n\n
package graph\n\nimport (\n    "context"\n    "fmt"\n)\n\ntype Resolver struct{}\n\nfunc (r *Resolver) User(ctx context.Context, args struct{ ID int }) (*User, error) {\n    // Na prática — consulta ao BD\n    return &User{\n        ID:   args.ID,\n        Name: "Maria",\n        Orders: []*Order{\n            {ID: 1, Total: 250.50},\n        },\n    }, nil\n}
\n\n

O cliente solicita apenas name — recebe apenas name. Sem over-fetching. Mas há um detalhe: se o cliente solicitar orders para 10 usuários, e cada um tiver 50 pedidos — o banco de dados pode cair de joelhos. Isso é chamado de problema N+1 no GraphQL, e em Go é resolvido com DataLoaders.

\n\n

DataLoader — salvador do N+1

\n\n
import "github.com/graph-gophers/dataloader"\n\ntype UserLoader struct {\n    *dataloader.Loader\n}\n\nfunc NewUserLoader() *UserLoader {\n    return &UserLoader{\n        Loader: dataloader.NewBatchedLoader(func(ctx context.Context, keys dataloader.Keys) []*dataloader.Result {\n            // Agrupa consultas ao BD\n            userIDs := make([]int, len(keys))\n            for i, key := range keys {\n                userIDs[i] = key.Int()\n            }\n            users := batchFetchUsers(userIDs) // Uma única consulta SQL com WHERE IN\n            results := make([]*dataloader.Result, len(ke                

Blogs

Book Recommendations