---
title: "Como Criar uma API REST com Go em 2026"
url: "https://golang.com.br/aprenda/api-rest-go/"
markdown_url: "https://golang.com.br/aprenda/api-rest-go.MD"
description: "Crie uma API REST com Go usando apenas a standard library: rotas, JSON, CRUD com banco de dados, middleware e deploy. Tutorial completo com código."
date: "2026-01-29"
author: ""
---

# Como Criar uma API REST com Go em 2026

Crie uma API REST com Go usando apenas a standard library: rotas, JSON, CRUD com banco de dados, middleware e deploy. Tutorial completo com código.


# Como Criar uma API REST com Go

Go é perfeito para APIs: rápido, simples, e a biblioteca padrão já inclui tudo que você precisa.

## O que Vamos Construir

Uma API de tarefas (TODO) com:
- Listar todas as tarefas
- Criar nova tarefa
- Buscar tarefa por ID
- Atualizar tarefa
- Deletar tarefa

## Setup do Projeto

```bash
mkdir todo-api
cd todo-api
go mod init todo-api
```

## API Básica com net/http

Crie `main.go`:

```go
package main

import (
    "encoding/json"
    "fmt"
    "net/http"
    "strconv"
    "sync"
)

// Modelo
type Task struct {
    ID        int    `json:"id"`
    Title     string `json:"title"`
    Completed bool   `json:"completed"`
}

// "Banco de dados" em memória
var (
    tasks  = make(map[int]Task)
    nextID = 1
    mu     sync.Mutex
)

func main() {
    http.HandleFunc("/tasks", handleTasks)
    http.HandleFunc("/tasks/", handleTaskByID)
    
    fmt.Println("Servidor rodando em http://localhost:8080")
    http.ListenAndServe(":8080", nil)
}
```

## Handlers

### Listar e Criar Tarefas

```go
func handleTasks(w http.ResponseWriter, r *http.Request) {
    switch r.Method {
    case "GET":
        listTasks(w, r)
    case "POST":
        createTask(w, r)
    default:
        http.Error(w, "Método não permitido", http.StatusMethodNotAllowed)
    }
}

func listTasks(w http.ResponseWriter, r *http.Request) {
    mu.Lock()
    defer mu.Unlock()
    
    taskList := make([]Task, 0, len(tasks))
    for _, task := range tasks {
        taskList = append(taskList, task)
    }
    
    w.Header().Set("Content-Type", "application/json")
    json.NewEncoder(w).Encode(taskList)
}

func createTask(w http.ResponseWriter, r *http.Request) {
    var task Task
    if err := json.NewDecoder(r.Body).Decode(&task); err != nil {
        http.Error(w, err.Error(), http.StatusBadRequest)
        return
    }
    
    mu.Lock()
    task.ID = nextID
    nextID++
    tasks[task.ID] = task
    mu.Unlock()
    
    w.Header().Set("Content-Type", "application/json")
    w.WriteHeader(http.StatusCreated)
    json.NewEncoder(w).Encode(task)
}
```

### Buscar, Atualizar e Deletar

```go
func handleTaskByID(w http.ResponseWriter, r *http.Request) {
    // Extrai ID da URL: /tasks/123
    idStr := r.URL.Path[len("/tasks/"):]
    id, err := strconv.Atoi(idStr)
    if err != nil {
        http.Error(w, "ID inválido", http.StatusBadRequest)
        return
    }
    
    switch r.Method {
    case "GET":
        getTask(w, r, id)
    case "PUT":
        updateTask(w, r, id)
    case "DELETE":
        deleteTask(w, r, id)
    default:
        http.Error(w, "Método não permitido", http.StatusMethodNotAllowed)
    }
}

func getTask(w http.ResponseWriter, r *http.Request, id int) {
    mu.Lock()
    task, ok := tasks[id]
    mu.Unlock()
    
    if !ok {
        http.Error(w, "Tarefa não encontrada", http.StatusNotFound)
        return
    }
    
    w.Header().Set("Content-Type", "application/json")
    json.NewEncoder(w).Encode(task)
}

func updateTask(w http.ResponseWriter, r *http.Request, id int) {
    mu.Lock()
    defer mu.Unlock()
    
    if _, ok := tasks[id]; !ok {
        http.Error(w, "Tarefa não encontrada", http.StatusNotFound)
        return
    }
    
    var task Task
    if err := json.NewDecoder(r.Body).Decode(&task); err != nil {
        http.Error(w, err.Error(), http.StatusBadRequest)
        return
    }
    
    task.ID = id
    tasks[id] = task
    
    w.Header().Set("Content-Type", "application/json")
    json.NewEncoder(w).Encode(task)
}

func deleteTask(w http.ResponseWriter, r *http.Request, id int) {
    mu.Lock()
    defer mu.Unlock()
    
    if _, ok := tasks[id]; !ok {
        http.Error(w, "Tarefa não encontrada", http.StatusNotFound)
        return
    }
    
    delete(tasks, id)
    w.WriteHeader(http.StatusNoContent)
}
```

## Testando a API

Execute o servidor:
```bash
go run main.go
```

### Com cURL

```bash
# Criar tarefa
curl -X POST http://localhost:8080/tasks \
  -H "Content-Type: application/json" \
  -d '{"title": "Aprender Go", "completed": false}'

# Listar tarefas
curl http://localhost:8080/tasks

# Buscar tarefa
curl http://localhost:8080/tasks/1

# Atualizar tarefa
curl -X PUT http://localhost:8080/tasks/1 \
  -H "Content-Type: application/json" \
  -d '{"title": "Aprender Go", "completed": true}'

# Deletar tarefa
curl -X DELETE http://localhost:8080/tasks/1
```

## Usando Gin (Framework Popular)

Para projetos maiores, frameworks como Gin simplificam o código:

```bash
go get -u github.com/gin-gonic/gin
```

```go
package main

import (
    "net/http"
    "github.com/gin-gonic/gin"
)

type Task struct {
    ID        int    `json:"id"`
    Title     string `json:"title"`
    Completed bool   `json:"completed"`
}

var tasks = []Task{}
var nextID = 1

func main() {
    r := gin.Default()
    
    r.GET("/tasks", listTasks)
    r.POST("/tasks", createTask)
    r.GET("/tasks/:id", getTask)
    r.PUT("/tasks/:id", updateTask)
    r.DELETE("/tasks/:id", deleteTask)
    
    r.Run(":8080")
}

func listTasks(c *gin.Context) {
    c.JSON(http.StatusOK, tasks)
}

func createTask(c *gin.Context) {
    var task Task
    if err := c.ShouldBindJSON(&task); err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
        return
    }
    task.ID = nextID
    nextID++
    tasks = append(tasks, task)
    c.JSON(http.StatusCreated, task)
}

// ... outros handlers similares
```

## Boas Práticas

### 1. Estrutura de Projeto
```
todo-api/
├── main.go
├── handlers/
│   └── tasks.go
├── models/
│   └── task.go
├── middleware/
│   └── logging.go
└── go.mod
```

### 2. Middleware de Logging

```go
func loggingMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        start := time.Now()
        next.ServeHTTP(w, r)
        log.Printf("%s %s %v", r.Method, r.URL.Path, time.Since(start))
    })
}
```

### 3. Tratamento de Erros

```go
type APIError struct {
    Code    int    `json:"code"`
    Message string `json:"message"`
}

func respondWithError(w http.ResponseWriter, code int, message string) {
    w.Header().Set("Content-Type", "application/json")
    w.WriteHeader(code)
    json.NewEncoder(w).Encode(APIError{Code: code, Message: message})
}
```

## Deploy

### Docker

```dockerfile
FROM golang:1.22-alpine AS builder
WORKDIR /app
COPY . .
RUN go build -o main .

FROM alpine:latest
WORKDIR /app
COPY --from=builder /app/main .
EXPOSE 8080
CMD ["./main"]
```

```bash
docker build -t todo-api .
docker run -p 8080:8080 todo-api
```

## Próximos Passos

- Adicionar banco de dados (PostgreSQL, MySQL)
- Implementar autenticação (JWT)
- Adicionar testes automatizados
- Documentar com Swagger

---

## Veja Também

- [Go para Iniciantes](/aprenda/go-para-iniciantes/)
- [Perguntas de Entrevista Go](/aprenda/perguntas-entrevista-go/)
- [Vagas Go](/vagas/)

---

*Última atualização: Janeiro 2026*

---

## Continue aprendendo

- [Go com PostgreSQL](/aprenda/golang-postgresql/) — Conecte sua API ao banco de dados
- [Testes em Go](/aprenda/testes-go/) — Teste sua API com table-driven tests
- [Autenticação JWT](/aprenda/golang-jwt-autenticacao/) — Adicione autenticação à sua API
- [Go com Docker](/aprenda/golang-docker/) — Faça deploy da sua API em containers
- [Tratamento de Erros](/aprenda/golang-erros/) — Error handling profissional
- [Vagas Back-end Go](/vagas/backend/) — Encontre vagas de backend
