Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion amaro.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ type AppOption func(*App)
// New creates a new instance of the Amaro App with optional configuration.
func New(options ...AppOption) *App {
app := &App{
middlewares: make([]Middleware, 0),
middlewares: []Middleware{Recovery()}, // Add Recovery middleware by default
pool: &sync.Pool{
New: func() interface{} {
// We can't fully init here because we need w/r, but we create the struct
Expand Down
2 changes: 1 addition & 1 deletion middlewares/suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import (
func TestMiddlewares(t *testing.T) {
app := amaro.New(amaro.WithRouter(routers.NewTrieRouter()))

app.Use(middlewares.Recovery())
// app.Use(amaro.Recovery()) // Already added by default in amaro.New()
app.Use(middlewares.RequestID())
app.Use(middlewares.Secure())
app.Use(middlewares.CORS())
Expand Down
10 changes: 4 additions & 6 deletions middlewares/recovery.go → recovery.go
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
package middlewares
package amaro

import (
"fmt"
"net/http"
"runtime"

"github.com/buildwithgo/amaro"
)

// Recovery recovers from panics, logs the stack trace, and returns an Internal Server Error.
func Recovery() amaro.Middleware {
return func(next amaro.Handler) amaro.Handler {
return func(c *amaro.Context) error {
func Recovery() Middleware {
return func(next Handler) Handler {
return func(c *Context) error {
defer func() {
if err := recover(); err != nil {
stack := make([]byte, 4096)
Expand Down
41 changes: 41 additions & 0 deletions router.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,47 @@ type Route struct {
Middlewares []Middleware
}

// ParamParser defines a function that checks if a path segment is a parameter.
// It returns true and the parameter name if it is, false otherwise.
type ParamParser func(segment string) (bool, string)

// WildcardParser defines a function that checks if a path segment is a wildcard.
// It returns true and the wildcard name if it is, false otherwise.
type WildcardParser func(segment string) (bool, string)

// RouterConfig defines configuration for Router.
type RouterConfig struct {
ParamParser ParamParser
WildcardParser WildcardParser
}

// DefaultParamParser implements the standard :param and {param} syntax.
func DefaultParamParser(segment string) (bool, string) {
if len(segment) > 0 && segment[0] == ':' {
return true, segment[1:]
}
if len(segment) > 2 && segment[0] == '{' && segment[len(segment)-1] == '}' {
return true, segment[1 : len(segment)-1]
}
return false, ""
}

// DefaultWildcardParser implements the standard *wildcard syntax.
func DefaultWildcardParser(segment string) (bool, string) {
if len(segment) > 0 && segment[0] == '*' {
return true, segment[1:]
}
return false, ""
}

// DefaultRouterConfig returns the default configuration.
func DefaultRouterConfig() RouterConfig {
return RouterConfig{
ParamParser: DefaultParamParser,
WildcardParser: DefaultWildcardParser,
}
}

// Router is the interface that all router implementations must satisfy.
// It allows for swappable routing strategies.
type Router interface {
Expand Down
2 changes: 1 addition & 1 deletion routers/decoupled_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ func TestDecoupledParamSyntax(t *testing.T) {
return false, ""
}

config := DefaultTrieRouterConfig()
config := amaro.DefaultRouterConfig()
config.ParamParser = customParser

r := NewTrieRouter(WithConfig(config))
Expand Down
47 changes: 3 additions & 44 deletions routers/trie.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,60 +23,19 @@ type node struct {
amaro.Route
}

// ParamParser defines a function that checks if a path segment is a parameter.
// It returns true and the parameter name if it is, false otherwise.
type ParamParser func(segment string) (bool, string)

// WildcardParser defines a function that checks if a path segment is a wildcard.
// It returns true and the wildcard name if it is, false otherwise.
type WildcardParser func(segment string) (bool, string)

// TrieRouterConfig defines configuration for TrieRouter.
type TrieRouterConfig struct {
ParamParser ParamParser
WildcardParser WildcardParser
}

// DefaultParamParser implements the standard :param and {param} syntax.
func DefaultParamParser(segment string) (bool, string) {
if len(segment) > 0 && segment[0] == ':' {
return true, segment[1:]
}
if len(segment) > 2 && segment[0] == '{' && segment[len(segment)-1] == '}' {
return true, segment[1 : len(segment)-1]
}
return false, ""
}

// DefaultWildcardParser implements the standard *wildcard syntax.
func DefaultWildcardParser(segment string) (bool, string) {
if len(segment) > 0 && segment[0] == '*' {
return true, segment[1:]
}
return false, ""
}

// DefaultTrieRouterConfig returns the default configuration.
func DefaultTrieRouterConfig() TrieRouterConfig {
return TrieRouterConfig{
ParamParser: DefaultParamParser,
WildcardParser: DefaultWildcardParser,
}
}

// TrieRouter is a trie-based router using a map for children.
// It supports :param and *wildcard parameters.
type TrieRouter struct {
root map[string]*node // method -> root node
globalMiddlewares []amaro.Middleware
config TrieRouterConfig
config amaro.RouterConfig
}

// TrieRouterOption configures TrieRouter.
type TrieRouterOption func(*TrieRouter)

// WithConfig sets the router configuration.
func WithConfig(config TrieRouterConfig) TrieRouterOption {
func WithConfig(config amaro.RouterConfig) TrieRouterOption {
return func(r *TrieRouter) {
r.config = config
}
Expand All @@ -86,7 +45,7 @@ func WithConfig(config TrieRouterConfig) TrieRouterOption {
func NewTrieRouter(opts ...TrieRouterOption) *TrieRouter {
r := &TrieRouter{
root: make(map[string]*node),
config: DefaultTrieRouterConfig(),
config: amaro.DefaultRouterConfig(),
}
for _, opt := range opts {
opt(r)
Expand Down