diff --git a/cmd/secret-santa/main.go b/cmd/secret-santa/main.go index 38bd143..3689b7f 100644 --- a/cmd/secret-santa/main.go +++ b/cmd/secret-santa/main.go @@ -4,10 +4,8 @@ import ( "database/sql" "git.katuwoss.dev/JustScreaMy/secret-santa/internal/app" "git.katuwoss.dev/JustScreaMy/secret-santa/internal/config" - "log" - "net/http" - _ "github.com/mattn/go-sqlite3" + "log" ) func main() { @@ -18,14 +16,9 @@ func main() { log.Println("Database sucessfully connected") appConfig := config.NewAppConfig(nil, nil) - application := app.NewApp(dbConnection, &appConfig) + application := app.NewApp(dbConnection, &appConfig, nil) log.Printf("Listening on http://%s", appConfig.GenerateIP()) - log.Fatal( - http.ListenAndServe( - appConfig.GenerateIP(), - application.Router(), - ), - ) + log.Fatal(application.Start()) } diff --git a/internal/app/app.go b/internal/app/app.go index 6930dc2..6b8e833 100644 --- a/internal/app/app.go +++ b/internal/app/app.go @@ -3,24 +3,38 @@ package app import ( "database/sql" "git.katuwoss.dev/JustScreaMy/secret-santa/internal/config" + "git.katuwoss.dev/JustScreaMy/secret-santa/internal/middlewares" "net/http" ) type App struct { Config config.AppConfig DB *sql.DB + Server *http.Server } -func NewApp(db *sql.DB, appConfig *config.AppConfig) *App { - defaultConfig := config.NewAppConfig(nil, nil) +func NewApp(db *sql.DB, appConfig *config.AppConfig, server *http.Server) *App { if appConfig == nil { + defaultConfig := config.NewAppConfig(nil, nil) appConfig = &defaultConfig } - return &App{ + app := &App{ Config: *appConfig, DB: db, } + + if server == nil { + server = &http.Server{ + Addr: app.Config.GenerateIP(), + Handler: app.Middlewares(app.Router()), + } + } else { + server.Handler = app.Router() + } + + app.Server = server + return app } func (a *App) Router() http.Handler { @@ -30,3 +44,14 @@ func (a *App) Router() http.Handler { return router } + +func (a *App) Middlewares(handler http.Handler) http.Handler { + stack := middlewares.CreateMiddlewareStack( + middlewares.Logging, + ) + return stack(handler) +} + +func (a *App) Start() error { + return a.Server.ListenAndServe() +} diff --git a/internal/handlers/user_handler.go b/internal/handlers/user_handler.go index a5bff03..0eb1b99 100644 --- a/internal/handlers/user_handler.go +++ b/internal/handlers/user_handler.go @@ -5,7 +5,6 @@ import ( "database/sql" "errors" "git.katuwoss.dev/JustScreaMy/secret-santa/internal/queries" - "git.katuwoss.dev/JustScreaMy/secret-santa/internal/types" "net/http" ) @@ -16,7 +15,7 @@ func HandleGetUsers(db *sql.DB) http.HandlerFunc { users, err := query.GetUsers(ctx) if err != nil { - writeErrorResponse(w, 500, err.Error()) + writeErrorResponse(w, http.StatusInternalServerError, err.Error()) return } @@ -24,7 +23,7 @@ func HandleGetUsers(db *sql.DB) http.HandlerFunc { users = []queries.User{} } - writeJSONResponse(w, 200, types.JsonResponse[[]queries.User]{Data: users}) + writeJSONResponse(w, http.StatusOK, users) } } func HandleGetUsersByID(db *sql.DB) http.HandlerFunc { @@ -34,20 +33,20 @@ func HandleGetUsersByID(db *sql.DB) http.HandlerFunc { id, err := parseIDFromURL(r) if err != nil { - writeErrorResponse(w, 500, err.Error()) + writeErrorResponse(w, http.StatusInternalServerError, err.Error()) return } user, err := query.GetUserId(ctx, id) if err != nil { if errors.Is(err, sql.ErrNoRows) { - writeErrorResponse(w, 404, "User not found") + writeErrorResponse(w, http.StatusNotFound, "User not found") return } - writeErrorResponse(w, 500, err.Error()) + writeErrorResponse(w, http.StatusInternalServerError, err.Error()) return } - writeJSONResponse(w, 200, types.JsonResponse[queries.User]{Data: user}) + writeJSONResponse(w, http.StatusOK, user) } } @@ -59,16 +58,16 @@ func HandleCreateUser(db *sql.DB) http.HandlerFunc { var createUser queries.CreateUserParams err := readJSONRequest(r, &createUser) if err != nil { - writeErrorResponse(w, 500, err.Error()) + writeErrorResponse(w, http.StatusInternalServerError, err.Error()) return } user, err := query.CreateUser(ctx, createUser) if err != nil { - writeErrorResponse(w, 500, err.Error()) + writeErrorResponse(w, http.StatusInternalServerError, err.Error()) return } - writeJSONResponse(w, 201, types.JsonResponse[queries.User]{Data: user}) + writeJSONResponse(w, http.StatusCreated, user) } } @@ -79,15 +78,15 @@ func HandleDeleteUser(db *sql.DB) http.HandlerFunc { id, err := parseIDFromURL(r) if err != nil { - writeErrorResponse(w, 500, err.Error()) + writeErrorResponse(w, http.StatusInternalServerError, err.Error()) return } err = query.DeleteUser(ctx, id) if err != nil { - writeErrorResponse(w, 500, err.Error()) + writeErrorResponse(w, http.StatusInternalServerError, err.Error()) return } - writeJSONResponse(w, 204, nil) + writeJSONResponse(w, http.StatusNoContent, nil) } } diff --git a/internal/handlers/utils.go b/internal/handlers/utils.go index ff2c026..746cbf3 100644 --- a/internal/handlers/utils.go +++ b/internal/handlers/utils.go @@ -2,7 +2,6 @@ package handlers import ( "encoding/json" - "git.katuwoss.dev/JustScreaMy/secret-santa/internal/types" "log" "net/http" "strconv" @@ -18,7 +17,9 @@ func writeJSONResponse(w http.ResponseWriter, statusCode int, data interface{}) } func writeErrorResponse(w http.ResponseWriter, statusCode int, message string) { - writeJSONResponse(w, statusCode, types.ErrorResponse{Message: message}) + writeJSONResponse(w, statusCode, map[string]string{ + "error": message, + }) } func readJSONRequest(r *http.Request, data interface{}) error { diff --git a/internal/middlewares/logging.go b/internal/middlewares/logging.go new file mode 100644 index 0000000..6f3a631 --- /dev/null +++ b/internal/middlewares/logging.go @@ -0,0 +1,31 @@ +package middlewares + +import ( + "log" + "net/http" + "time" +) + +type wrappedWriter struct { + http.ResponseWriter + statusCode int +} + +func (w *wrappedWriter) WriteHeader(statusCode int) { + w.statusCode = statusCode + w.ResponseWriter.WriteHeader(statusCode) +} + +func Logging(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + startTime := time.Now() + + wrapped := wrappedWriter{ + ResponseWriter: w, + statusCode: http.StatusOK, + } + next.ServeHTTP(&wrapped, r) + elapsedTime := time.Since(startTime) + log.Println(r.Method, r.URL.Path, wrapped.statusCode, elapsedTime) + }) +} diff --git a/internal/middlewares/utils.go b/internal/middlewares/utils.go new file mode 100644 index 0000000..d3b4377 --- /dev/null +++ b/internal/middlewares/utils.go @@ -0,0 +1,14 @@ +package middlewares + +import "net/http" + +type Middleware func(http.Handler) http.Handler + +func CreateMiddlewareStack(middlewares ...Middleware) Middleware { + return func(next http.Handler) http.Handler { + for i := len(middlewares) - 1; i >= 0; i-- { + next = middlewares[i](next) + } + return next + } +} diff --git a/internal/types/response.go b/internal/types/response.go deleted file mode 100644 index 4de6b9b..0000000 --- a/internal/types/response.go +++ /dev/null @@ -1,9 +0,0 @@ -package types - -type JsonResponse[T any] struct { - Data T `json:"data"` -} - -type ErrorResponse struct { - Message string `json:"message"` -}