Files
tp/main_dc/yalarba/api_es/cmd/main.go
T
2025-10-29 06:24:22 +05:00

228 lines
5.7 KiB
Go

package main
import (
"encoding/json"
"fmt"
"log"
"net/http"
"os"
"time"
"github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"
"gorm.io/driver/postgres"
"gorm.io/gorm"
"gorm.io/gorm/logger"
)
// Модели для БД
type User struct {
ID uint `json:"id" gorm:"primarykey"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
DeletedAt gorm.DeletedAt `json:"deleted_at,omitempty" gorm:"index"`
Name string `json:"name" gorm:"size:100;not null"`
Email string `json:"email" gorm:"size:255;uniqueIndex;not null"`
Password string `json:"-" gorm:"size:255;not null"` // Пароль не возвращаем в JSON
}
type Config struct {
DBHost string
DBPort string
DBUser string
DBPassword string
DBName string
AppPort string
}
var db *gorm.DB
var config Config
func main() {
// Загрузка конфигурации
config = Config{
DBHost: getEnv("DB_HOST", "db"),
DBPort: getEnv("DB_PORT", "5432"),
DBUser: getEnv("DB_USER", "postgres"),
DBPassword: getEnv("DB_PASSWORD", "postgres"),
DBName: getEnv("DB_NAME", "mydb"),
AppPort: getEnv("APP_PORT", "8081"),
}
// Инициализация БД
if err := initDB(); err != nil {
log.Fatal("Failed to connect to database:", err)
}
// Автомиграция
if err := db.AutoMigrate(&User{}); err != nil {
log.Fatal("Failed to migrate database:", err)
}
r := chi.NewRouter()
// Стандартные middleware
r.Use(middleware.Logger)
r.Use(middleware.Recoverer)
r.Use(middleware.Timeout(60 * time.Second))
// Маршруты API
r.Route("/api", func(r chi.Router) {
r.Get("/", handleRoot)
r.Get("/users", getUsers)
r.Post("/users", createUser)
r.Get("/users/{id}", getUser)
r.Put("/users/{id}", updateUser)
r.Delete("/users/{id}", deleteUser)
})
// Health check
r.Get("/health", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(map[string]string{"status": "healthy"})
})
// Запуск сервера
log.Printf("Server starting on port %s", config.AppPort)
if err := http.ListenAndServe(":"+config.AppPort, r); err != nil {
log.Fatal("Failed to start server:", err)
}
}
func initDB() error {
dsn := fmt.Sprintf("host=%s user=%s password=%s dbname=%s port=%s sslmode=disable TimeZone=UTC",
config.DBHost, config.DBUser, config.DBPassword, config.DBName, config.DBPort)
var err error
db, err = gorm.Open(postgres.Open(dsn), &gorm.Config{
Logger: logger.Default.LogMode(logger.Info),
})
if err != nil {
return err
}
sqlDB, err := db.DB()
if err != nil {
return err
}
// Настройка пула соединений
sqlDB.SetMaxIdleConns(10)
sqlDB.SetMaxOpenConns(100)
sqlDB.SetConnMaxLifetime(time.Hour)
log.Println("Successfully connected to database")
return nil
}
func getEnv(key, defaultValue string) string {
if value := os.Getenv(key); value != "" {
return value
}
return defaultValue
}
// Обработчики API
func handleRoot(w http.ResponseWriter, r *http.Request) {
response := map[string]string{
"message": "EasySite REST API Server",
"version": "1.0.0",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
}
func getUsers(w http.ResponseWriter, r *http.Request) {
var users []User
if err := db.Find(&users).Error; err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(users)
}
func createUser(w http.ResponseWriter, r *http.Request) {
var user User
if err := json.NewDecoder(r.Body).Decode(&user); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
if err := db.Create(&user).Error; err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusCreated)
json.NewEncoder(w).Encode(user)
}
func getUser(w http.ResponseWriter, r *http.Request) {
id := chi.URLParam(r, "id")
var user User
if err := db.First(&user, id).Error; err != nil {
if err == gorm.ErrRecordNotFound {
http.Error(w, "User not found", http.StatusNotFound)
} else {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
return
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(user)
}
func updateUser(w http.ResponseWriter, r *http.Request) {
id := chi.URLParam(r, "id")
var user User
if err := db.First(&user, id).Error; err != nil {
if err == gorm.ErrRecordNotFound {
http.Error(w, "User not found", http.StatusNotFound)
} else {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
return
}
var updateData User
if err := json.NewDecoder(r.Body).Decode(&updateData); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
if err := db.Model(&user).Updates(updateData).Error; err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(user)
}
func deleteUser(w http.ResponseWriter, r *http.Request) {
id := chi.URLParam(r, "id")
var user User
if err := db.First(&user, id).Error; err != nil {
if err == gorm.ErrRecordNotFound {
http.Error(w, "User not found", http.StatusNotFound)
} else {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
return
}
if err := db.Delete(&user).Error; err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(map[string]string{"message": "User deleted successfully"})
}