Files
api_tmpl/internal/handlers/http/server.go
T
2026-01-08 01:15:07 +00:00

131 lines
3.1 KiB
Go

// 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
}