// Package api provides the HTTP server and routing for the banking service. package api import ( "context" "net/http" "github.com/FernandoJVideira/simple_bank/internal/auth" "github.com/FernandoJVideira/simple_bank/internal/config" "github.com/FernandoJVideira/simple_bank/internal/domain/role" "github.com/FernandoJVideira/simple_bank/internal/service" "github.com/FernandoJVideira/simple_bank/internal/worker" "github.com/rs/zerolog/log" db "github.com/FernandoJVideira/simple_bank/internal/db/sqlc" "github.com/gin-gonic/gin" "github.com/gin-contrib/cors" swaggerFiles "github.com/swaggo/files" ginSwagger "github.com/swaggo/gin-swagger" ) // Server serves HTTP requests for our banking service. type Server struct { config config.Config store db.Store tokenMaker auth.Maker router *gin.Engine taskDisributor worker.TaskDistributor httpServer *http.Server userService service.UserService authService service.AuthService } func NewServer( config config.Config, store db.Store, taskDistributor worker.TaskDistributor, tokenMaker auth.Maker, userService service.UserService, authService service.AuthService, ) (*Server, error) { s := &Server{ config: config, store: store, tokenMaker: tokenMaker, taskDisributor: taskDistributor, userService: userService, authService: authService, } // if v, ok := binding.Validator.Engine().(*validator.Validate); ok { // err := v.RegisterValidation("currency", validCurrency) // if err != nil { // return nil, err // } // } s.setupRouter(config) return s, nil } func (s *Server) setupRouter(config config.Config) { router := gin.Default() // Configure CORS middleware router.Use(cors.New(cors.Config{ AllowOrigins: config.AllowedOrigins, AllowMethods: []string{ http.MethodGet, http.MethodPost, http.MethodPut, http.MethodPatch, http.MethodDelete, http.MethodOptions, }, AllowHeaders: []string{ "Accept", "Authorization", "Content-Type", "X-CSRF-Token", }, AllowCredentials: true, })) router.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler)) // Add routes v1 := router.Group("/api/v1") { auth := v1.Group("/auth") { auth.POST("/login", s.loginUser) auth.POST("/register", s.createUser) auth.GET("/verify", s.verifyEmail) auth.POST("/refresh", s.renewAccessToken) } user := v1.Group("/users") { me := user.Group("/me").Use(authMiddleware(s.tokenMaker, []string{role.AdminRole, role.MemberRole})) { me.GET("/", s.getCurrentUser) me.PUT("/", s.updateUser) me.PUT("/password", s.changePassword) } user.GET("/:username", s.getUser) } } s.router = router } // Start runs the HTTP server on a specific address. func (s *Server) Start(address string) error { s.httpServer = &http.Server{ Addr: address, Handler: s.router, } return s.httpServer.ListenAndServe() } func (s *Server) Shutdown(ctx context.Context) error { log.Info().Msg("shutting down Gin HTTP server") if s.httpServer != nil { return s.httpServer.Shutdown(ctx) } return nil }