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.
- 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:
