diff options
Diffstat (limited to 'backend/cmd/api')
-rw-r--r-- | backend/cmd/api/main.go | 215 |
1 files changed, 107 insertions, 108 deletions
diff --git a/backend/cmd/api/main.go b/backend/cmd/api/main.go index e1d0824..f882175 100644 --- a/backend/cmd/api/main.go +++ b/backend/cmd/api/main.go @@ -1,40 +1,77 @@ package main import ( - "log" + "fmt" "net/http" + "os" "time" - "finance/backend/internal/api/auth" - "finance/backend/internal/api/v1/accounts" - "finance/backend/internal/api/v1/goals" - "finance/backend/internal/api/v1/loans" - "finance/backend/internal/api/v1/transactions" + "finance/backend/handlers" "finance/backend/internal/config" "finance/backend/internal/database" + "finance/backend/internal/logger" + "finance/backend/internal/middleware" + "finance/backend/internal/models" "github.com/gin-contrib/cors" "github.com/gin-gonic/gin" ) func main() { - // Load Configuration + // Initialize logger + log := logger.NewLogger(os.Stdout, logger.INFO) + log.Info("Starting API server...") + + // Load configuration cfg, err := config.LoadConfig() if err != nil { - log.Fatalf("Failed to load configuration: %v", err) + log.Fatal("Failed to load configuration:", err) + } + + // Set Gin mode based on environment + if cfg.Environment == "production" { + gin.SetMode(gin.ReleaseMode) + } else { + gin.SetMode(gin.DebugMode) + } + + // Initialize database + err = database.InitDatabase(cfg) + if err != nil { + log.Fatal("Failed to connect to database:", err) } - // Initialize Database - if err := database.InitDatabase(cfg); err != nil { - log.Fatalf("Failed to initialize database: %v", err) + // Auto migrate database models + err = database.DB.AutoMigrate( + &models.User{}, + &models.Account{}, + &models.Transaction{}, + &models.Goal{}, + &models.Loan{}, + ) + if err != nil { + log.Fatal("Failed to migrate database:", err) } - // Setup Gin Router - r := gin.Default() + // Initialize handlers + goalHandler := handlers.NewGoalHandler() + // Initialize other handlers as needed + // userHandler := handlers.NewUserHandler() + // accountHandler := handlers.NewAccountHandler() + // transactionHandler := handlers.NewTransactionHandler() + // loanHandler := handlers.NewLoanHandler() + // authHandler := handlers.NewAuthHandler() + + // Create a new Gin router without default middleware + r := gin.New() + + // Add custom middleware + r.Use(middleware.RequestLogger(log)) + r.Use(middleware.ErrorHandler()) // Configure CORS r.Use(cors.New(cors.Config{ - AllowOrigins: []string{"http://localhost:3000"}, + AllowOrigins: []string{"*"}, AllowMethods: []string{"GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"}, AllowHeaders: []string{"Origin", "Content-Type", "Accept", "Authorization"}, ExposeHeaders: []string{"Content-Length"}, @@ -42,115 +79,77 @@ func main() { MaxAge: 12 * time.Hour, })) + // Set up custom handlers for 404 and 405 + r.NoRoute(middleware.NotFoundHandler()) + r.NoMethod(middleware.MethodNotAllowedHandler()) + // Public utility endpoints - r.GET("/ping", func(c *gin.Context) { - c.JSON(http.StatusOK, gin.H{ - "message": "pong", - }) + r.GET("/health", func(c *gin.Context) { + c.JSON(http.StatusOK, gin.H{"status": "ok", "timestamp": time.Now().Unix()}) }) - // Add database status endpoint - r.GET("/db-status", func(c *gin.Context) { - // Try to get a connection from the pool + r.GET("/dbstatus", func(c *gin.Context) { sqlDB, err := database.DB.DB() if err != nil { - c.JSON(http.StatusInternalServerError, gin.H{ - "status": "error", - "message": "Failed to get database connection", - "error": err.Error(), - }) + c.JSON(http.StatusInternalServerError, gin.H{"status": "error", "message": "Database connection error"}) return } - - // Check if database is reachable err = sqlDB.Ping() if err != nil { - c.JSON(http.StatusInternalServerError, gin.H{ - "status": "error", - "message": "Database is not reachable", - "error": err.Error(), - }) + c.JSON(http.StatusInternalServerError, gin.H{"status": "error", "message": "Database ping failed"}) return } - - c.JSON(http.StatusOK, gin.H{ - "status": "success", - "message": "Database connection is healthy", - }) + c.JSON(http.StatusOK, gin.H{"status": "ok", "message": "Database connection is healthy"}) }) // API v1 routes v1 := r.Group("/api/v1") - { - // Auth routes (public) - v1.POST("/auth/signup", auth.Signup(cfg)) - v1.POST("/auth/login", auth.Login(cfg)) - - // Protected routes - protected := v1.Group("") - protected.Use(auth.AuthMiddleware(cfg)) - { - // User routes - protected.GET("/users/me", func(c *gin.Context) { - // Get user from context (set by auth middleware) - user, exists := c.Get("user") - if !exists { - c.JSON(http.StatusNotFound, gin.H{"error": "User not found"}) - return - } - - c.JSON(http.StatusOK, gin.H{"user": user}) - }) - - // Account routes - accountRoutes := protected.Group("/accounts") - { - accountRoutes.GET("", accounts.GetAccounts()) - accountRoutes.GET("/:id", accounts.GetAccountByID()) - accountRoutes.POST("", accounts.CreateAccount()) - accountRoutes.PUT("/:id", accounts.UpdateAccount()) - accountRoutes.DELETE("/:id", accounts.DeleteAccount()) - } - - // Transaction routes - transactionRoutes := protected.Group("/transactions") - { - transactionRoutes.GET("", transactions.GetTransactions()) - transactionRoutes.GET("/:id", transactions.GetTransactionByID()) - transactionRoutes.POST("", transactions.CreateTransaction()) - transactionRoutes.PUT("/:id", transactions.UpdateTransaction()) - transactionRoutes.DELETE("/:id", transactions.DeleteTransaction()) - } - - // Goal routes - goalRoutes := protected.Group("/goals") - { - goalRoutes.GET("", goals.GetGoals()) - goalRoutes.GET("/:id", goals.GetGoalByID()) - goalRoutes.POST("", goals.CreateGoal()) - goalRoutes.PUT("/:id", goals.UpdateGoal()) - goalRoutes.DELETE("/:id", goals.DeleteGoal()) - goalRoutes.PATCH("/:id/progress", goals.UpdateGoalProgress()) // Specific endpoint for updating progress - } - - // Loan routes - loanRoutes := protected.Group("/loans") - { - loanRoutes.GET("", loans.GetLoans()) - loanRoutes.GET("/:id", loans.GetLoanByID()) - loanRoutes.POST("", loans.CreateLoan()) - loanRoutes.PUT("/:id", loans.UpdateLoan()) - loanRoutes.DELETE("/:id", loans.DeleteLoan()) - } - } - } - // Run the server - serverAddr := ":8080" // TODO: Make this configurable via cfg - log.Printf("Starting server on %s", serverAddr) - err = r.Run(serverAddr) - if err != nil { - // Use Fatalf to exit if server fails to start - log.Fatalf("Failed to start server: %v", err) + // Authentication routes (no JWT required) + // v1.POST("/register", authHandler.Register) + // v1.POST("/login", authHandler.Login) + + // Protected routes (JWT required) + protected := v1.Group("") + // protected.Use(authHandler.JWTAuth) + + // User routes + // protected.GET("/users/me", userHandler.GetCurrentUser) + // protected.PUT("/users/me", userHandler.UpdateCurrentUser) + + // Account routes + // protected.GET("/accounts", accountHandler.GetAccounts) + // protected.GET("/accounts/:id", accountHandler.GetAccountByID) + // protected.POST("/accounts", accountHandler.CreateAccount) + // protected.PUT("/accounts/:id", accountHandler.UpdateAccount) + // protected.DELETE("/accounts/:id", accountHandler.DeleteAccount) + + // Transaction routes + // protected.GET("/transactions", transactionHandler.GetTransactions) + // protected.GET("/transactions/:id", transactionHandler.GetTransactionByID) + // protected.POST("/transactions", transactionHandler.CreateTransaction) + // protected.PUT("/transactions/:id", transactionHandler.UpdateTransaction) + // protected.DELETE("/transactions/:id", transactionHandler.DeleteTransaction) + + // Goal routes + protected.GET("/goals", goalHandler.GetGoals) + protected.GET("/goals/:id", goalHandler.GetGoal) + protected.POST("/goals", goalHandler.CreateGoal) + protected.PUT("/goals/:id", goalHandler.UpdateGoal) + protected.DELETE("/goals/:id", goalHandler.DeleteGoal) + protected.PATCH("/goals/:id/progress", goalHandler.UpdateGoalProgress) + + // Loan routes + // protected.GET("/loans", loanHandler.GetLoans) + // protected.GET("/loans/:id", loanHandler.GetLoanByID) + // protected.POST("/loans", loanHandler.CreateLoan) + // protected.PUT("/loans/:id", loanHandler.UpdateLoan) + // protected.DELETE("/loans/:id", loanHandler.DeleteLoan) + + // Start server + serverAddr := fmt.Sprintf("%s:%d", cfg.ServerHost, cfg.ServerPort) + log.Info("Server starting on", serverAddr) + if err := r.Run(serverAddr); err != nil { + log.Fatal("Server failed to start:", err) } } |