Por que Go é a linguagem ideal para APIs?
\n\nQuando se trata de criar APIs de alta carga, Go (Golang) ocupa com confiança um lugar no topo. Sua natureza compilada, suporte embutido para concorrência através de goroutines e sintaxe minimalista permitem escrever microsserviços rápidos e confiáveis. Mas qual protocolo escolher para seu próximo projeto: o clássico REST, o flexível GraphQL ou o ultrarrápido gRPC?
\n\nNeste artigo, não vamos apenas listar as diferenças — vamos escrever código real em Go para cada abordagem, analisar benchmarks e dar critérios claros de escolha. Vamos lá!
\n\nAPI REST em Go: o clássico comprovado
\n\nREST (Representational State Transfer) continua sendo o padrão de facto para APIs públicas. Go oferece uma excelente biblioteca padrão net/http, além de frameworks populares como gin e echo.
Exemplo de servidor REST em Go puro
\n\nVamos começar com um serviço CRUD simples para gerenciar tarefas. Veja como é uma API REST mínima em Go sem dependências externas:
\n\npackage main\n\nimport (\n "encoding/json"\n "log"\n "net/http"\n "sync"\n)\n\ntype Task struct {\n ID int `json:"id"`\n Name string `json:"name"`\n}\n\nvar (\n tasks = []Task{{ID: 1, Name: "Estudar Go"}}\n mu sync.Mutex\n nextID = 2\n)\n\nfunc getTasks(w http.ResponseWriter, r *http.Request) {\n mu.Lock()\n defer mu.Unlock()\n w.Header().Set("Content-Type", "application/json")\n json.NewEncoder(w).Encode(tasks)\n}\n\nfunc createTask(w http.ResponseWriter, r *http.Request) {\n var task Task\n if err := json.NewDecoder(r.Body).Decode(&task); err != nil {\n http.Error(w, err.Error(), http.StatusBadRequest)\n return\n }\n mu.Lock()\n task.ID = nextID\n nextID++\n tasks = append(tasks, task)\n mu.Unlock()\n w.WriteHeader(http.StatusCreated)\n json.NewEncoder(w).Encode(task)\n}\n\nfunc main() {\n http.HandleFunc("/tasks", func(w http.ResponseWriter, r *http.Request) {\n switch r.Method {\n case http.MethodGet:\n getTasks(w, r)\n case http.MethodPost:\n createTask(w, r)\n default:\n http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)\n }\n })\n log.Println("API REST iniciada na porta :8080")\n log.Fatal(http.ListenAndServe(":8080", nil))\n}\n\n\nVantagens do REST em Go:
\n- \n
- Simplicidade e previsibilidade — cada endpoint retorna uma estrutura de dados fixa \n
- Excelente capacidade de cache através de cabeçalhos HTTP \n
- Amplo suporte de ferramentas (Swagger, Postman) \n
Desvantagens: Over-fetching e under-fetching de dados. Se o cliente precisa apenas do nome da tarefa, ele ainda receberá o JSON completo.
\n\nGraphQL em Go: flexibilidade nas consultas
\n\nGraphQL resolve o problema de redundância de dados. O cliente decide quais campos precisa. A comunidade Go oferece a poderosa biblioteca gqlgen, que gera código a partir do esquema.
Exemplo de servidor GraphQL com gqlgen
\n\nPrimeiro, definimos o esquema schema.graphql:
type Task {\n id: ID!\n name: String!\n}\n\ntype Query {\n tasks: [Task!]!\n}\n\ntype Mutation {\n createTask(name: String!): Task!\n}\n\n\nAgora, executamos a geração e escrevemos os resolvers em Go:
\n\npackage main\n\nimport (\n "log"\n "net/http"\n "github.com/99designs/gqlgen/graphql/handler"\n "github.com/99designs/gqlgen/graphql/playground"\n)\n\n// Supondo que o código gerado já exista\ntype Resolver struct {\n tasks []Task\n mu sync.Mutex\n}\n\nfunc (r *Resolver) Tasks(ctx context.Context) ([]Task, error) {\n r.mu.Lock()\n defer r.mu.Unlock()\n return r.tasks, nil\n}\n\nfunc (r *Resolver) CreateTask(ctx context.Context, name string) (*Task, error) {\n r.mu.Lock()\n defer r.mu.Unlock()\n