Skip to content

Commit

Permalink
feat: adding global middleware support to Server
Browse files Browse the repository at this point in the history
- Added `globalMiddlewares` field to `Server` struct to allow middleware execution for all routes.
- Introduced `Use` method to register global middlewares.
- Refactored `Listen` method by extracting route registration logic into `registerRoutes` to handle both global and route-specific middlewares.
- Simplified middleware chaining through the new `registerMiddlewares` helper function.
  • Loading branch information
i9si authored Sep 18, 2024
2 parents 3c49a5b + 0b5af19 commit c052039
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 11 deletions.
50 changes: 39 additions & 11 deletions server.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,10 +91,10 @@ func (r *Response) SetHeader(key, value string) {
// It uses http.FileServer to handle requests for static files and returns a 404 error if the file is not found.
//
// Parameters:
// - path: An http.FileSystem representing the root directory from which static files will be served.
// - path: An http.FileSystem representing the root directory from which static files will be served.
//
// Returns:
// - A Handler function that takes a Request and Response, serving the files
// - A Handler function that takes a Request and Response, serving the files
func ServeFiles(path http.FileSystem) Handler {
staticFileSystem := http.FileServer(path)
return func(req *Request, res *Response) error {
Expand Down Expand Up @@ -152,9 +152,10 @@ func (r *Response) JSON(data JSON) error {
type Handler func(req *Request, res *Response) error

type Server struct {
mux *http.ServeMux
routes []Router
addr string
mux *http.ServeMux
routes []Router
globalMiddlewares []Handler
addr string
}

// NewServer creates a new `Server` instance bound to the specified port.
Expand All @@ -173,6 +174,25 @@ type Router struct {
middlewares []Handler
}

// Use adds a global middleware to the server's middleware stack.
//
// This method allows you to register middleware that will be executed for all
// routes on the server, regardless of path or HTTP method.
//
// server.Use(func(req *Request, res *Response) error {
// slog.Info("nine[router]:", "method", req.Method(), "path", req.Path())
// return nil
// })
//
// server.Get("/login/{name}", func(req *Request, res *Response) error {
// name := req.Param("name")
// loginMessage := fmt.Sprintf("Welcome %s", name)
// return res.JSON(JSON{"message": loginMessage})
// })
func (s *Server) Use(middleware Handler) {
s.globalMiddlewares = append(s.globalMiddlewares, middleware)
}

// Get registers a route for handling GET requests at the specified endpoint.
//
// server := nine.NewServer(5050)
Expand Down Expand Up @@ -231,16 +251,17 @@ func (s *Server) Delete(endpoint string, handlers ...Handler) error {
// }
// log.Fatal(server.Listen())
func (s *Server) Listen() error {
s.registerRoutes()
return http.ListenAndServe(s.addr, s.mux)
}

func (s *Server) registerRoutes() {
for _, route := range s.routes {
finalHandler := httpHandler(route.handler)

for i := len(route.middlewares) - 1; i >= 0; i-- {
finalHandler = httpMiddleware(route.middlewares[i], finalHandler)
}

finalHandler = registerMiddlewares(finalHandler, s.globalMiddlewares...)
finalHandler = registerMiddlewares(finalHandler, route.middlewares...)
s.mux.Handle(route.pattern, finalHandler)
}
return http.ListenAndServe(s.addr, s.mux)
}

func (s *Server) registerRoute(method, endpoint string, handlers ...Handler) error {
Expand All @@ -258,6 +279,13 @@ func (s *Server) registerRoute(method, endpoint string, handlers ...Handler) err
return nil
}

func registerMiddlewares(handler http.Handler, middlewares ...Handler) http.Handler {
for i := len(middlewares) - 1; i >= 0; i-- {
handler = httpMiddleware(middlewares[i], handler)
}
return handler
}

type ServerError struct {
StatusCode int
ContentType string
Expand Down
25 changes: 25 additions & 0 deletions server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ package nine
import (
"context"
"errors"
"fmt"
"io"
"log/slog"
"net/http"
"net/http/httptest"
"strings"
Expand Down Expand Up @@ -153,3 +155,26 @@ func TestMiddleware(t *testing.T) {
t.Errorf("expected body 'Hello', got '%s'", w.Body.String())
}
}

func TestUse(t *testing.T) {
server := NewServer(5050)
message := "INFO nine[router]: method=GET path=/login/gabrielluizsf"
server.Use(func(req *Request, res *Response) error {
slog.Info("nine[router]:", "method", req.Method(), "path", req.Path())
res.SetHeader("Message", message)
return nil
})
server.Get("/login/{name}", func(req *Request, res *Response) error {
name := req.Param("name")
loginMessage := fmt.Sprintf("Welcome %s", name)
return res.JSON(JSON{"message": loginMessage})
})
server.registerRoutes()
req := httptest.NewRequest(http.MethodGet, "/login/gabrielluizsf", nil)
w := httptest.NewRecorder()
server.mux.ServeHTTP(w, req)
result := w.Header().Get("Message")
if result != message {
t.Fatalf("result: %s, expected: %s", result, message)
}
}

0 comments on commit c052039

Please sign in to comment.