package api import ( "context" "log" "math/rand" "net/http" "os" "os/signal" "time" "github.com/gin-gonic/gin" gomysql "github.com/go-sql-driver/mysql" "gorm.io/gorm" gormlogger "gorm.io/gorm/logger" ) type Service struct { Gin *gin.Engine DB *gorm.DB Config *ServiceConfig Logger *log.Logger GormLogger gormlogger.Interface } type ServiceConfig struct { Listen string Mysql *gomysql.Config } func New(logger *log.Logger, config *ServiceConfig) *Service { return &Service{ Gin: gin.New(), Config: config, Logger: logger, GormLogger: gormlogger.New( log.New(os.Stdout, "\r\n", log.LstdFlags), // io writer gormlogger.Config{ SlowThreshold: time.Second, // Slow SQL threshold LogLevel: gormlogger.Error, // Log level IgnoreRecordNotFoundError: true, // Ignore ErrRecordNotFound error for logger Colorful: true, // Disable color }, ), } } func (s *Service) SetupRoutes() { s.Gin.Use(gin.Logger()) s.Gin.Use(s.Recovery) s.Gin.NoRoute(func(c *gin.Context) { c.JSON(http.StatusNotFound, gin.H{ "error": "this route doesn't exists", }) }) } func (s *Service) Run() error { rand.Seed(time.Now().UnixNano()) s.SetupRoutes() s.SetupDB() srv := &http.Server{ Addr: s.Config.Listen, Handler: s.Gin, } quit := make(chan os.Signal, 1) var runError error go func() { // service connections if runError = srv.ListenAndServe(); runError != nil { quit <- os.Interrupt } }() // Wait for interrupt signal to gracefully shutdown the server with // a timeout of 5 seconds. signal.Notify(quit, os.Interrupt) <-quit s.Logger.Println("shutdown ...") ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() if err := srv.Shutdown(ctx); err != nil { return err } db, err := s.DB.DB() if err != nil { return err } s.Logger.Println("closing database ...") if err := db.Close(); err != nil { return err } s.Logger.Println("exiting") return runError }