From e5002d818793e36eb72dde7fe676e1a555ff831b Mon Sep 17 00:00:00 2001 From: Tigor Hutasuhut Date: Tue, 9 Apr 2024 14:30:54 +0700 Subject: [PATCH] refactor: simplified code structure --- cli/serve.go | 20 ++++++------ main.go | 3 +- server/routes/api/api.go | 24 -------------- server/routes/api/health_check.go | 10 ------ server/routes/api/subreddits_list.go | 40 ------------------------ server/routes/health_check.go | 9 ++++++ server/routes/{www => }/hot_reload.go | 4 +-- server/routes/page_home.go | 17 ++++++++++ server/routes/routes.go | 45 +++++++++++++++++++++++++++ server/routes/subreddit_list.go | 41 ++++++++++++++++++++++++ server/routes/www/home.go | 12 ------- server/routes/www/www.go | 42 ------------------------- server/server.go | 21 ++++++++----- 13 files changed, 138 insertions(+), 150 deletions(-) delete mode 100644 server/routes/api/api.go delete mode 100644 server/routes/api/health_check.go delete mode 100644 server/routes/api/subreddits_list.go create mode 100644 server/routes/health_check.go rename server/routes/{www => }/hot_reload.go (95%) create mode 100644 server/routes/page_home.go create mode 100644 server/routes/routes.go create mode 100644 server/routes/subreddit_list.go delete mode 100644 server/routes/www/home.go delete mode 100644 server/routes/www/www.go diff --git a/cli/serve.go b/cli/serve.go index 21fc466..c562a50 100644 --- a/cli/serve.go +++ b/cli/serve.go @@ -1,18 +1,20 @@ package cli import ( + "io/fs" "os" "os/signal" "github.com/spf13/cobra" + "github.com/tigorlazuardi/redmage/api" "github.com/tigorlazuardi/redmage/db" - "github.com/tigorlazuardi/redmage/db/queries/subreddits" + "github.com/tigorlazuardi/redmage/db/queries" "github.com/tigorlazuardi/redmage/pkg/log" "github.com/tigorlazuardi/redmage/server" - "github.com/tigorlazuardi/redmage/server/routes/api" - "github.com/tigorlazuardi/redmage/server/routes/www" ) +var PublicDir fs.FS = os.DirFS("public") + var serveCmd = &cobra.Command{ Use: "serve", Short: "Starts the HTTP Server", @@ -24,18 +26,14 @@ var serveCmd = &cobra.Command{ os.Exit(1) } - subreddits := subreddits.New(db) + queries := queries.New(db) api := &api.API{ - Subreddits: subreddits, - Config: cfg, + Queries: queries, + DB: db, } - www := &www.WWW{ - Subreddits: subreddits, - Config: cfg, - } - server := server.New(cfg, api, www) + server := server.New(cfg, api, PublicDir) exit := make(chan struct{}, 1) diff --git a/main.go b/main.go index bd09360..27ae781 100644 --- a/main.go +++ b/main.go @@ -10,7 +10,6 @@ import ( "github.com/joho/godotenv" "github.com/tigorlazuardi/redmage/cli" "github.com/tigorlazuardi/redmage/db" - "github.com/tigorlazuardi/redmage/server/routes/www" ) //go:embed db/migrations/*.sql @@ -23,7 +22,7 @@ func main() { _ = godotenv.Load() db.Migrations = Migrations var err error - www.PublicFS, err = fs.Sub(PublicFS, "public") + cli.PublicDir, err = fs.Sub(PublicFS, "public") if err != nil { panic(errors.New("failed to create sub filesystem")) } diff --git a/server/routes/api/api.go b/server/routes/api/api.go deleted file mode 100644 index 66921a7..0000000 --- a/server/routes/api/api.go +++ /dev/null @@ -1,24 +0,0 @@ -package api - -import ( - "github.com/go-chi/chi/v5" - chimiddleware "github.com/go-chi/chi/v5/middleware" - "github.com/tigorlazuardi/redmage/config" - "github.com/tigorlazuardi/redmage/db/queries/subreddits" - "github.com/tigorlazuardi/redmage/server/routes/middleware" -) - -type API struct { - Subreddits *subreddits.Queries - Config *config.Config -} - -func (api *API) Register(router chi.Router) { - router.Use(chimiddleware.RequestID) - router.Get("/", HealthCheck) - router.Get("/health", HealthCheck) - router.Route("/subreddits", func(r chi.Router) { - r.Use(chimiddleware.RequestLogger(middleware.ChiLogger{})) - r.Get("/", api.ListSubreddits) - }) -} diff --git a/server/routes/api/health_check.go b/server/routes/api/health_check.go deleted file mode 100644 index f2c5195..0000000 --- a/server/routes/api/health_check.go +++ /dev/null @@ -1,10 +0,0 @@ -package api - -import ( - "net/http" -) - -func HealthCheck(rw http.ResponseWriter, r *http.Request) { - rw.Header().Add("Content-Type", "application/json") - _, _ = rw.Write([]byte(`{"status":"ok"}`)) -} diff --git a/server/routes/api/subreddits_list.go b/server/routes/api/subreddits_list.go deleted file mode 100644 index f84a960..0000000 --- a/server/routes/api/subreddits_list.go +++ /dev/null @@ -1,40 +0,0 @@ -package api - -import ( - "encoding/json" - "fmt" - "net/http" - "strconv" - - "github.com/tigorlazuardi/redmage/db/queries/subreddits" - "github.com/tigorlazuardi/redmage/pkg/log" -) - -func (api *API) ListSubreddits(rw http.ResponseWriter, r *http.Request) { - rw.Header().Add("Content-Type", "application/json") - subs, err := api.Subreddits.ListSubreddits(r.Context(), parseListSubredditsQuery(r)) - if err != nil { - rw.WriteHeader(http.StatusInternalServerError) - msg := fmt.Sprintf("failed to list subreddits: %s", err) - _ = json.NewEncoder(rw).Encode(map[string]string{"error": msg}) - return - } - - if err := json.NewEncoder(rw).Encode(subs); err != nil { - log.New(r.Context()).Err(err).Error("failed to list subreddits") - } -} - -func parseListSubredditsQuery(r *http.Request) subreddits.ListSubredditsParams { - params := subreddits.ListSubredditsParams{} - params.Limit, _ = strconv.ParseInt(r.URL.Query().Get("limit"), 10, 64) - params.Offset, _ = strconv.ParseInt(r.URL.Query().Get("offset"), 10, 64) - - if params.Limit < 1 { - params.Limit = 10 - } else if params.Limit > 100 { - params.Limit = 100 - } - - return params -} diff --git a/server/routes/health_check.go b/server/routes/health_check.go new file mode 100644 index 0000000..abb1b43 --- /dev/null +++ b/server/routes/health_check.go @@ -0,0 +1,9 @@ +package routes + +import ( + "net/http" +) + +func (routes *Routes) HealthCheck(rw http.ResponseWriter, req *http.Request) { + _, _ = rw.Write([]byte{}) +} diff --git a/server/routes/www/hot_reload.go b/server/routes/hot_reload.go similarity index 95% rename from server/routes/www/hot_reload.go rename to server/routes/hot_reload.go index c671c07..6e5809b 100644 --- a/server/routes/www/hot_reload.go +++ b/server/routes/hot_reload.go @@ -1,4 +1,4 @@ -package www +package routes import ( "errors" @@ -9,7 +9,7 @@ import ( "github.com/tigorlazuardi/redmage/pkg/log" ) -func (www *WWW) CreateHotReloadRoute() http.HandlerFunc { +func (routes *Routes) CreateHotReloadRoute() http.HandlerFunc { var mu sync.Mutex knownClients := make(map[string]chan struct{}) firstTime := make(chan struct{}, 1) diff --git a/server/routes/page_home.go b/server/routes/page_home.go new file mode 100644 index 0000000..ba6fe7b --- /dev/null +++ b/server/routes/page_home.go @@ -0,0 +1,17 @@ +package routes + +import ( + "net/http" + + "github.com/tigorlazuardi/redmage/pkg/log" + "github.com/tigorlazuardi/redmage/views" + "github.com/tigorlazuardi/redmage/views/homeview" +) + +func (routes *Routes) PageHome(rw http.ResponseWriter, r *http.Request) { + ctx := r.Context() + vc := views.NewContext(routes.Config, r) + if err := homeview.Home(vc).Render(ctx, rw); err != nil { + log.New(ctx).Err(err).Error("failed to render home view") + } +} diff --git a/server/routes/routes.go b/server/routes/routes.go new file mode 100644 index 0000000..c2822b5 --- /dev/null +++ b/server/routes/routes.go @@ -0,0 +1,45 @@ +package routes + +import ( + "io/fs" + "net/http" + + "github.com/go-chi/chi/v5" + chimiddleware "github.com/go-chi/chi/v5/middleware" + "github.com/tigorlazuardi/redmage/api" + "github.com/tigorlazuardi/redmage/config" + "github.com/tigorlazuardi/redmage/server/routes/middleware" +) + +type Routes struct { + API *api.API + Config *config.Config + PublicDir fs.FS +} + +func (routes *Routes) Register(router chi.Router) { + router.HandleFunc("/ping", routes.HealthCheck) + router.HandleFunc("/health", routes.HealthCheck) + if routes.Config.Bool("http.hotreload") { + router.Get("/hot_reload", routes.CreateHotReloadRoute()) + } + + router.Group(routes.registerWWWRoutes) + router.Route("/api/v1", routes.registerV1APIRoutes) +} + +func (routes *Routes) registerV1APIRoutes(router chi.Router) { + router.Use(chimiddleware.RequestLogger(middleware.ChiLogger{})) + router.Use(chimiddleware.SetHeader("Content-Type", "application/json")) + + router.Get("/subreddits", routes.SubredditsListAPI) +} + +func (routes *Routes) registerWWWRoutes(router chi.Router) { + router.Mount("/public", http.StripPrefix("/public", http.FileServer(http.FS(routes.PublicDir)))) + + router.Group(func(r chi.Router) { + r.Use(chimiddleware.RequestLogger(middleware.ChiLogger{})) + r.Get("/", routes.PageHome) + }) +} diff --git a/server/routes/subreddit_list.go b/server/routes/subreddit_list.go new file mode 100644 index 0000000..b8337fb --- /dev/null +++ b/server/routes/subreddit_list.go @@ -0,0 +1,41 @@ +package routes + +import ( + "encoding/json" + "net/http" + "strconv" + + "github.com/tigorlazuardi/redmage/api" + "github.com/tigorlazuardi/redmage/pkg/log" +) + +func (r *Routes) SubredditsListAPI(rw http.ResponseWriter, req *http.Request) { + ctx := req.Context() + params := parseSubredditListQuery(req) + + result, err := r.API.ListSubreddits(ctx, params) + if err != nil { + rw.WriteHeader(http.StatusInternalServerError) + _ = json.NewEncoder(rw).Encode(map[string]string{"error": err.Error()}) + return + } + + if err := json.NewEncoder(rw).Encode(result); err != nil { + log.New(ctx).Err(err).Error("failed to encode subreddits into json") + } +} + +func (r *Routes) SubredditsListPage(rw http.ResponseWriter, req *http.Request) { +} + +func parseSubredditListQuery(req *http.Request) (params api.ListSubredditsParams) { + params.Name = req.FormValue("name") + params.Limit, _ = strconv.ParseInt(req.FormValue("limit"), 10, 64) + if params.Limit < 1 { + params.Limit = 10 + } else if params.Limit > 100 { + params.Limit = 100 + } + params.Offset, _ = strconv.ParseInt(req.FormValue("offset"), 10, 64) + return params +} diff --git a/server/routes/www/home.go b/server/routes/www/home.go deleted file mode 100644 index d6379b3..0000000 --- a/server/routes/www/home.go +++ /dev/null @@ -1,12 +0,0 @@ -package www - -import ( - "net/http" - - "github.com/tigorlazuardi/redmage/views" - "github.com/tigorlazuardi/redmage/views/homeview" -) - -func (www *WWW) Home(rw http.ResponseWriter, r *http.Request) { - _ = homeview.Home(views.NewContext(www.Config, r)).Render(r.Context(), rw) -} diff --git a/server/routes/www/www.go b/server/routes/www/www.go deleted file mode 100644 index 0602ba2..0000000 --- a/server/routes/www/www.go +++ /dev/null @@ -1,42 +0,0 @@ -package www - -import ( - "context" - "net/http" - "os" - - "github.com/go-chi/chi/v5" - chimiddleware "github.com/go-chi/chi/v5/middleware" - "github.com/tigorlazuardi/redmage/config" - "github.com/tigorlazuardi/redmage/db/queries/subreddits" - "github.com/tigorlazuardi/redmage/pkg/log" - "github.com/tigorlazuardi/redmage/server/routes/middleware" -) - -var PublicFS = os.DirFS("public") - -type WWW struct { - Subreddits *subreddits.Queries - Config *config.Config -} - -func (www *WWW) Register(router chi.Router) { - router.Use(chimiddleware.RealIP) - router. - With(chimiddleware.RequestLogger(middleware.ChiSimpleLogger{})). - Mount("/public", http.StripPrefix("/public", http.FileServer(http.FS(PublicFS)))) - - if www.Config.Bool("http.hotreload") { - log.New(context.Background()).Debug("enabled hot reload") - router. - With(chimiddleware.RequestLogger(middleware.ChiSimpleLogger{})). - Get("/hot_reload", www.CreateHotReloadRoute()) - } - - router.Group(func(r chi.Router) { - r.Use(chimiddleware.RequestID) - r.Use(chimiddleware.RequestLogger(middleware.ChiLogger{})) - r.Use(chimiddleware.SetHeader("Content-Type", "text/html; utf-8")) - r.Get("/", www.Home) - }) -} diff --git a/server/server.go b/server/server.go index c8691cf..fbae7bf 100644 --- a/server/server.go +++ b/server/server.go @@ -3,20 +3,22 @@ package server import ( "context" "errors" + "io/fs" "net/http" "github.com/go-chi/chi/v5" + "github.com/tigorlazuardi/redmage/api" "github.com/tigorlazuardi/redmage/config" "github.com/tigorlazuardi/redmage/pkg/caller" "github.com/tigorlazuardi/redmage/pkg/errs" "github.com/tigorlazuardi/redmage/pkg/log" - "github.com/tigorlazuardi/redmage/server/routes/api" - "github.com/tigorlazuardi/redmage/server/routes/www" + "github.com/tigorlazuardi/redmage/server/routes" ) type Server struct { - server *http.Server - config *config.Config + server *http.Server + config *config.Config + PublicDir fs.FS } func (srv *Server) Start(exit <-chan struct{}) error { @@ -41,11 +43,16 @@ func (srv *Server) Start(exit <-chan struct{}) error { } } -func New(cfg *config.Config, api *api.API, www *www.WWW) *Server { +func New(cfg *config.Config, api *api.API, publicDir fs.FS) *Server { router := chi.NewRouter() - router.Route("/api", api.Register) - router.Route("/", www.Register) + routes := routes.Routes{ + API: api, + Config: cfg, + PublicDir: publicDir, + } + + routes.Register(router) server := &http.Server{ Handler: router,