package api import ( "context" "fmt" "log/slog" "net/http" "net/http/pprof" "github.com/gorilla/mux" "github.com/prometheus/client_golang/prometheus/promhttp" "go.uber.org/fx" "payouts/internal/api/payout" "payouts/internal/api/user" "payouts/internal/api/version" appConfig "payouts/internal/config" "payouts/internal/service/monitoring" ) // Module is a fx module var Module = fx.Options( user.Module, payout.Module, version.Module, monitoring.Module, fx.Invoke(RegisterRoutes), ) const BaseRoute = "/api/v1" // Params represents the module input params type Params struct { fx.In Logger *slog.Logger AppConfig *appConfig.App PayoutHandler payout.Handler UserHandler user.Handler Version version.Handler Metrics monitoring.Metrics } // RegisterRoutes registers the api routes and starts the http server func RegisterRoutes(p Params, lc fx.Lifecycle) { router := mux.NewRouter() router.StrictSlash(true) router.HandleFunc(version.Route, p.Version.VersionHandler).Methods(http.MethodGet) if p.AppConfig.Server.EnablePProfEndpoints { router.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline) router.HandleFunc("/debug/pprof/profile", pprof.Profile) router.HandleFunc("/debug/pprof/symbol", pprof.Symbol) router.HandleFunc("/debug/pprof/trace", pprof.Trace) router.NewRoute().PathPrefix("/debug/pprof/").HandlerFunc(pprof.Index) } apiRouter := router.PathPrefix(BaseRoute).Subrouter() userRouter := apiRouter.PathPrefix(user.BaseRoute).Subrouter() userRouter.HandleFunc(user.RegisterRoute, p.UserHandler.UserRegister).Methods(http.MethodPost) userRouter.HandleFunc(user.LoginRoute, p.UserHandler.UserLogin).Methods(http.MethodPost) payoutRouter := apiRouter.PathPrefix(payout.BaseRoute).Subrouter() payoutRouter.HandleFunc(payout.CreateRoute, p.PayoutHandler.PayoutCreate).Methods(http.MethodPost) payoutRouter.HandleFunc(payout.CallbackRoute, p.PayoutHandler.PayoutCallback).Methods(http.MethodPost) // collect api metrics apiRouter.Use(p.Metrics.GetMiddleware()) router.Handle(p.AppConfig.Metrics.Endpoint, promhttp.Handler()) srv := http.Server{ Handler: router, Addr: p.AppConfig.Server.Port, WriteTimeout: p.AppConfig.Server.WriteTimeout, ReadTimeout: p.AppConfig.Server.ReadTimeout, } lc.Append(fx.Hook{ OnStart: func(c context.Context) error { go func() { var err error slog.Info(fmt.Sprintf("Starting server on port %s", p.AppConfig.Server.Port)) if p.AppConfig.Server.Tls.Enabled { err = srv.ListenAndServeTLS(p.AppConfig.Server.Tls.CertFile, p.AppConfig.Server.Tls.KeyFile) } else { err = srv.ListenAndServe() } if err != nil { panic(err) } }() return nil }, OnStop: func(ctx context.Context) error { return srv.Shutdown(ctx) }, }) }