Exemplo de aplicativo GO com Banco de Dados

Exemplo de aplicativo GO com Banco de Dados


Quer criar uma API com GO e MYSQL?

Nesse tutorial vamos aprenda a desenvolver, configurar sua API em GO.

  1. Crie um arquivo main.go na raiz do seu projeto com o seguinte conteúdo
package main

import (
    "database/sql"
    "encoding/json"
    "fmt"
    "log"
    "net/http"
    "os"
    "path/filepath"
    "strconv"

    _ "github.com/go-sql-driver/mysql"
    "github.com/gorilla/mux"
    "github.com/joho/godotenv"
)

// Estrutura do usuário para as operações CRUD
type Usuario struct {
    ID    int    `json:"id"`
    Nome  string `json:"nome"`
    Email string `json:"email"`
}

var db *sql.DB

// Função de inicialização
func init() {
    // Tentativa de carregar o arquivo .env em diferentes locais
    if err := loadEnvFile(); err != nil {
        log.Println("Aviso: Não foi possível carregar o arquivo .env")
    }

    // Configurar a conexão com o banco de dados usando variáveis de ambiente
    dbHost := os.Getenv("DB_HOST")
    dbUser := os.Getenv("DB_USER")
    dbPassword := os.Getenv("DB_PASSWORD")
    dbName := os.Getenv("DB_NAME")
    dbPort := os.Getenv("DB_PORT")

    dsn := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s", dbUser, dbPassword, dbHost, dbPort, dbName)

    var errConn error
    db, errConn = sql.Open("mysql", dsn)
    if errConn != nil {
        log.Fatal("Erro ao abrir a conexão com o banco de dados:", errConn)
    }

    err := db.Ping()
    if err != nil {
        log.Fatal("Erro ao conectar ao banco de dados:", err)
    }

    fmt.Println("Conectado ao banco de dados MySQL com sucesso!")
}

// Função para tentar carregar o arquivo .env de diferentes locais
func loadEnvFile() error {
    // Primeiro, tenta carregar o arquivo .env do diretório especificado em CODE_DIR, se definido
    codeDir := os.Getenv("CODE_DIR")
    if codeDir != "" {
        envPath := filepath.Join(codeDir, ".env")
        if _, err := os.Stat(envPath); err == nil {
            return godotenv.Load(envPath)
        }
    }

    // Tenta carregar o arquivo .env no diretório atual
    if err := godotenv.Load(); err == nil {
        return nil
    }

    // Tenta carregar o arquivo .env a partir do diretório raiz do contêiner
    envPath := "/.env"
    if _, err := os.Stat(envPath); err == nil {
        return godotenv.Load(envPath)
    }

    // Alternativa: tenta carregar o arquivo .env do diretório /app, se existir
    altPath := filepath.Join("/app", ".env")
    if _, err := os.Stat(altPath); err == nil {
        return godotenv.Load(altPath)
    }

    // Retorna erro caso o arquivo não seja encontrado em nenhum dos locais
    return fmt.Errorf("arquivo .env não encontrado nos locais padrão")
}

// Função principal que configura as rotas e inicia o servidor
func main() {
    router := mux.NewRouter()

    // Definição das rotas da API CRUD
    router.HandleFunc("/usuarios", getUsuarios).Methods("GET")
    router.HandleFunc("/usuarios/{id}", getUsuario).Methods("GET")
    router.HandleFunc("/usuarios", createUsuario).Methods("POST")
    router.HandleFunc("/usuarios/{id}", updateUsuario).Methods("PUT")
    router.HandleFunc("/usuarios/{id}", deleteUsuario).Methods("DELETE")

    fmt.Println("Servidor iniciado na porta 3240")
    log.Fatal(http.ListenAndServe(":3240", router))
}

// Handler para obter todos os usuários
func getUsuarios(w http.ResponseWriter, r *http.Request) {
    rows, err := db.Query("SELECT id, nome, email FROM usuarios")
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
    defer rows.Close()

    var usuarios []Usuario
    for rows.Next() {
        var usuario Usuario
        if err := rows.Scan(&usuario.ID, &usuario.Nome, &usuario.Email); err != nil {
            http.Error(w, err.Error(), http.StatusInternalServerError)
            return
        }
        usuarios = append(usuarios, usuario)
    }
    json.NewEncoder(w).Encode(usuarios)
}

// Handler para obter um usuário pelo ID
func getUsuario(w http.ResponseWriter, r *http.Request) {
    params := mux.Vars(r)
    id, err := strconv.Atoi(params["id"])
    if err != nil {
        http.Error(w, "ID inválido", http.StatusBadRequest)
        return
    }

    var usuario Usuario
    err = db.QueryRow("SELECT id, nome, email FROM usuarios WHERE id = ?", id).Scan(&usuario.ID, &usuario.Nome, &usuario.Email)
    if err != nil {
        if err == sql.ErrNoRows {
            http.Error(w, "Usuário não encontrado", http.StatusNotFound)
        } else {
            http.Error(w, err.Error(), http.StatusInternalServerError)
        }
        return
    }
    json.NewEncoder(w).Encode(usuario)
}

// Handler para criar um novo usuário
func createUsuario(w http.ResponseWriter, r *http.Request) {
    var usuario Usuario
    json.NewDecoder(r.Body).Decode(&usuario)

    res, err := db.Exec("INSERT INTO usuarios (nome, email) VALUES (?, ?)", usuario.Nome, usuario.Email)
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }

    id, err := res.LastInsertId()
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
    usuario.ID = int(id)
    json.NewEncoder(w).Encode(usuario)
}

// Handler para atualizar um usuário existente
func updateUsuario(w http.ResponseWriter, r *http.Request) {
    params := mux.Vars(r)
    id, err := strconv.Atoi(params["id"])
    if err != nil {
        http.Error(w, "ID inválido", http.StatusBadRequest)
        return
    }

    var usuario Usuario
    json.NewDecoder(r.Body).Decode(&usuario)
    usuario.ID = id

    _, err = db.Exec("UPDATE usuarios SET nome = ?, email = ? WHERE id = ?", usuario.Nome, usuario.Email, usuario.ID)
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
    json.NewEncoder(w).Encode(usuario)
}

// Handler para deletar um usuário
func deleteUsuario(w http.ResponseWriter, r *http.Request) {
    params := mux.Vars(r)
    id, err := strconv.Atoi(params["id"])
    if err != nil {
        http.Error(w, "ID inválido", http.StatusBadRequest)
        return
    }

    _, err = db.Exec("DELETE FROM usuarios WHERE id = ?", id)
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }

    w.WriteHeader(http.StatusNoContent)
}

2. Crie um arquivo run.sh na raiz do seu projeto com o seguinte conteúdo.

#!/bin/bash

# Inicializar o módulo Go, caso ainda não esteja inicializado
if [ ! -f "go.mod" ]; then
    echo "Inicializando o módulo Go..."
    go mod init meu-projeto
fi

# Instalar dependências
echo "Instalando dependências..."
go get -u github.com/go-sql-driver/mysql github.com/gorilla/mux github.com/joho/godotenv

# Construir o aplicativo
echo "Construindo o aplicativo..."
go build -o app main.go

# Executar o aplicativo
echo "Executando o aplicativo..."
./app

Testando o CRUD com Postman

Com o aplicativo registrado e iniciado corretamente com sucesso, temos o acesso testado e 100% funcional, no qual demonstramos em imagens abaixo:

Adicionando um usuário:

Atualizando um usuário:

Removendo um usuário: