Skip to content

Commit

Permalink
Merge pull request #23 from opus-domini/feature/improve-examples
Browse files Browse the repository at this point in the history
Add middleware support in example server
  • Loading branch information
hugo-andrade authored Aug 19, 2024
2 parents 7c1096a + 2db4573 commit 65d711b
Show file tree
Hide file tree
Showing 6 changed files with 88 additions and 21 deletions.
6 changes: 5 additions & 1 deletion examples/custom_headers_and_cookies/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@ import (

func main() {
// Start the test server
ts := server.NewManager().NewServer()
ts := server.NewManager().
NewServerBuilder().
EnableHeaderDebug().
Build()
// Close the server when the function ends.
defer ts.Close()

// Create a custom client with the server URL.
Expand Down
2 changes: 1 addition & 1 deletion examples/load_balancing/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ func main() {
defer ts1.Close()

// Start Test Server #2
ts2 := serverManager.NewBusyServer()
ts2 := serverManager.NewServerBuilder().EnableBusy().Build()
defer ts2.Close()

// Start Test Server #3
Expand Down
6 changes: 5 additions & 1 deletion examples/retry_on_server_error/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,11 @@ import (

func main() {
// Start the test server
ts := server.NewManager().NewBusyServer()
ts := server.NewManager().
NewServerBuilder().
EnableBusy().
Build()
// Close the server when the function ends.
defer ts.Close()

// Create a default client with the server URL.
Expand Down
7 changes: 4 additions & 3 deletions examples/server/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ package config
type (
// Server represents a test server configuration.
Server struct {
ID int
URL string
IsBusy bool
ID int
URL string
EnableBusy bool
EnableHeaderDebug bool
}
)
51 changes: 43 additions & 8 deletions examples/server/handler/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ import (
)

type (
// Middleware is a function that wraps an HTTP handler.
Middleware func(http.Handler) http.Handler

// HealthCheckMessage is a simple struct for health check messages.
HealthCheckMessage struct {
ServerID string `json:"server_id"`
Expand All @@ -38,15 +41,36 @@ func NewMux(config *config.Server, repository *repository.Provider) http.Handler
mux.HandleFunc("GET /resources/{id}", GetByID(repository.Resource))
mux.HandleFunc("POST /resources", Create[*model.Resource](repository.Resource))

return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if config.IsBusy && shouldSimulateServerError() {
slog.Error("Server is busy!", "serverID", config.ID)
writeErrorResponse(w, ErrorMessage{Status: http.StatusInternalServerError, Message: "Internal Server Error"})
return
}
middlewares := []Middleware{
HeaderDebugMiddleware(config),
BusyMiddleware(config),
}

mux.ServeHTTP(w, r)
})
return handleWithMiddlewares(middlewares, mux)
}

func HeaderDebugMiddleware(config *config.Server) Middleware {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if config.EnableHeaderDebug {
slog.Info("Request Headers:", "headers", r.Header)
}
next.ServeHTTP(w, r)
})
}
}

func BusyMiddleware(config *config.Server) Middleware {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if config.EnableBusy && shouldSimulateServerError() {
slog.Error("Server is busy!", "serverID", config.ID)
writeErrorResponse(w, ErrorMessage{Status: http.StatusInternalServerError, Message: "Internal Server Error"})
return
}
next.ServeHTTP(w, r)
})
}
}

func HealthCheck(serverID int) func(w http.ResponseWriter, _ *http.Request) {
Expand Down Expand Up @@ -101,6 +125,17 @@ func Create[T model.Model](repository repository.Repository) func(w http.Respons
}
}

// handleWithMiddlewares applies a list of middlewares to an HTTP handler in reverse order.
// Middlewares are applied in reverse order because each middleware wraps the next one.
// The last middleware in the list is the first to be executed, and it calls the next middleware in the chain.
// This continues until the final handler is reached.
func handleWithMiddlewares(middlewares []Middleware, mux http.Handler) http.Handler {
for i := len(middlewares) - 1; i >= 0; i-- {
mux = middlewares[i](mux)
}
return mux
}

func writeErrorResponse(w http.ResponseWriter, errorMessage ErrorMessage) {
w.WriteHeader(errorMessage.Status)
_ = json.NewEncoder(w).Encode(errorMessage)
Expand Down
37 changes: 30 additions & 7 deletions examples/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@ type (
repository *repository.Provider
mutex sync.Mutex
}

// ServerBuilder helps in building a server with custom configurations.
ServerBuilder struct {
manager *Manager
config *config.Server
}
)

func NewManager() *Manager {
Expand All @@ -44,13 +50,30 @@ func (m *Manager) newServer(config *config.Server) *httptest.Server {
}

func (m *Manager) NewServer() *httptest.Server {
return m.newServer(&config.Server{
IsBusy: false,
})
return m.newServer(&config.Server{})
}

// NewServerBuilder creates a new instance of ServerBuilder.
func (m *Manager) NewServerBuilder() *ServerBuilder {
return &ServerBuilder{
manager: m,
config: &config.Server{},
}
}

// EnableBusy sets the EnableBusy flag.
func (b *ServerBuilder) EnableBusy() *ServerBuilder {
b.config.EnableBusy = true
return b
}

// EnableHeaderDebug sets the EnableHeaderDebug flag.
func (b *ServerBuilder) EnableHeaderDebug() *ServerBuilder {
b.config.EnableHeaderDebug = true
return b
}

func (m *Manager) NewBusyServer() *httptest.Server {
return m.newServer(&config.Server{
IsBusy: true,
})
// Build creates a new server with the specified configurations.
func (b *ServerBuilder) Build() *httptest.Server {
return b.manager.newServer(b.config)
}

0 comments on commit 65d711b

Please sign in to comment.