middlewares

This commit is contained in:
Jakub Kropáček 2024-11-17 22:52:24 +01:00
parent c3610ac1e4
commit bc5e37c747
7 changed files with 91 additions and 37 deletions

View file

@ -4,10 +4,8 @@ import (
"database/sql" "database/sql"
"git.katuwoss.dev/JustScreaMy/secret-santa/internal/app" "git.katuwoss.dev/JustScreaMy/secret-santa/internal/app"
"git.katuwoss.dev/JustScreaMy/secret-santa/internal/config" "git.katuwoss.dev/JustScreaMy/secret-santa/internal/config"
"log"
"net/http"
_ "github.com/mattn/go-sqlite3" _ "github.com/mattn/go-sqlite3"
"log"
) )
func main() { func main() {
@ -18,14 +16,9 @@ func main() {
log.Println("Database sucessfully connected") log.Println("Database sucessfully connected")
appConfig := config.NewAppConfig(nil, nil) 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.Printf("Listening on http://%s", appConfig.GenerateIP())
log.Fatal( log.Fatal(application.Start())
http.ListenAndServe(
appConfig.GenerateIP(),
application.Router(),
),
)
} }

View file

@ -3,24 +3,38 @@ package app
import ( import (
"database/sql" "database/sql"
"git.katuwoss.dev/JustScreaMy/secret-santa/internal/config" "git.katuwoss.dev/JustScreaMy/secret-santa/internal/config"
"git.katuwoss.dev/JustScreaMy/secret-santa/internal/middlewares"
"net/http" "net/http"
) )
type App struct { type App struct {
Config config.AppConfig Config config.AppConfig
DB *sql.DB DB *sql.DB
Server *http.Server
} }
func NewApp(db *sql.DB, appConfig *config.AppConfig) *App { func NewApp(db *sql.DB, appConfig *config.AppConfig, server *http.Server) *App {
defaultConfig := config.NewAppConfig(nil, nil)
if appConfig == nil { if appConfig == nil {
defaultConfig := config.NewAppConfig(nil, nil)
appConfig = &defaultConfig appConfig = &defaultConfig
} }
return &App{ app := &App{
Config: *appConfig, Config: *appConfig,
DB: db, 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 { func (a *App) Router() http.Handler {
@ -30,3 +44,14 @@ func (a *App) Router() http.Handler {
return router 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()
}

View file

@ -5,7 +5,6 @@ import (
"database/sql" "database/sql"
"errors" "errors"
"git.katuwoss.dev/JustScreaMy/secret-santa/internal/queries" "git.katuwoss.dev/JustScreaMy/secret-santa/internal/queries"
"git.katuwoss.dev/JustScreaMy/secret-santa/internal/types"
"net/http" "net/http"
) )
@ -16,7 +15,7 @@ func HandleGetUsers(db *sql.DB) http.HandlerFunc {
users, err := query.GetUsers(ctx) users, err := query.GetUsers(ctx)
if err != nil { if err != nil {
writeErrorResponse(w, 500, err.Error()) writeErrorResponse(w, http.StatusInternalServerError, err.Error())
return return
} }
@ -24,7 +23,7 @@ func HandleGetUsers(db *sql.DB) http.HandlerFunc {
users = []queries.User{} users = []queries.User{}
} }
writeJSONResponse(w, 200, types.JsonResponse[[]queries.User]{Data: users}) writeJSONResponse(w, http.StatusOK, users)
} }
} }
func HandleGetUsersByID(db *sql.DB) http.HandlerFunc { func HandleGetUsersByID(db *sql.DB) http.HandlerFunc {
@ -34,20 +33,20 @@ func HandleGetUsersByID(db *sql.DB) http.HandlerFunc {
id, err := parseIDFromURL(r) id, err := parseIDFromURL(r)
if err != nil { if err != nil {
writeErrorResponse(w, 500, err.Error()) writeErrorResponse(w, http.StatusInternalServerError, err.Error())
return return
} }
user, err := query.GetUserId(ctx, id) user, err := query.GetUserId(ctx, id)
if err != nil { if err != nil {
if errors.Is(err, sql.ErrNoRows) { if errors.Is(err, sql.ErrNoRows) {
writeErrorResponse(w, 404, "User not found") writeErrorResponse(w, http.StatusNotFound, "User not found")
return return
} }
writeErrorResponse(w, 500, err.Error()) writeErrorResponse(w, http.StatusInternalServerError, err.Error())
return 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 var createUser queries.CreateUserParams
err := readJSONRequest(r, &createUser) err := readJSONRequest(r, &createUser)
if err != nil { if err != nil {
writeErrorResponse(w, 500, err.Error()) writeErrorResponse(w, http.StatusInternalServerError, err.Error())
return return
} }
user, err := query.CreateUser(ctx, createUser) user, err := query.CreateUser(ctx, createUser)
if err != nil { if err != nil {
writeErrorResponse(w, 500, err.Error()) writeErrorResponse(w, http.StatusInternalServerError, err.Error())
return 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) id, err := parseIDFromURL(r)
if err != nil { if err != nil {
writeErrorResponse(w, 500, err.Error()) writeErrorResponse(w, http.StatusInternalServerError, err.Error())
return return
} }
err = query.DeleteUser(ctx, id) err = query.DeleteUser(ctx, id)
if err != nil { if err != nil {
writeErrorResponse(w, 500, err.Error()) writeErrorResponse(w, http.StatusInternalServerError, err.Error())
return return
} }
writeJSONResponse(w, 204, nil) writeJSONResponse(w, http.StatusNoContent, nil)
} }
} }

View file

@ -2,7 +2,6 @@ package handlers
import ( import (
"encoding/json" "encoding/json"
"git.katuwoss.dev/JustScreaMy/secret-santa/internal/types"
"log" "log"
"net/http" "net/http"
"strconv" "strconv"
@ -18,7 +17,9 @@ func writeJSONResponse(w http.ResponseWriter, statusCode int, data interface{})
} }
func writeErrorResponse(w http.ResponseWriter, statusCode int, message string) { 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 { func readJSONRequest(r *http.Request, data interface{}) error {

View file

@ -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)
})
}

View file

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

View file

@ -1,9 +0,0 @@
package types
type JsonResponse[T any] struct {
Data T `json:"data"`
}
type ErrorResponse struct {
Message string `json:"message"`
}