Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: path parsing issue 2 #379

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
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
19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ to develop APIs and web applications.
`log/slog`, `context` and `html/template`.
- **Routing**: Fuego router is based on Go 1.22 `net/http`, with grouping and
middleware support
- Optional trailing slash handling: Configure whether `/users` and `/users/` should be treated as the same route
- **Serialization/Deserialization**: Fuego automatically serializes and
deserializes JSON, XML and HTML Forms based on user-provided structs
(or not, if you want to do it yourself)
Expand All @@ -67,6 +68,24 @@ to develop APIs and web applications.
`templ` or `gomponents`
- **Adaptors**: [Experimental] Fuego can be used with Gin.

## Configuration

### Trailing Slashes

By default, Fuego treats URLs with and without trailing slashes as distinct routes. You can configure the server to automatically strip trailing slashes using the `WithStripTrailingSlash` option:

```go
s := fuego.NewServer(
fuego.WithStripTrailingSlash(),
)
```

When enabled:

- `/api/users` and `/api/users/` will route to the same handler
- Routes registered with trailing slashes are automatically converted to non-trailing slash versions
- Improves URL consistency across your API

## Examples

### Hello World
Expand Down
27 changes: 27 additions & 0 deletions option.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"fmt"
"net/http"
"strconv"
"strings"

"github.com/getkin/kin-openapi/openapi3"
)
Expand Down Expand Up @@ -438,3 +439,29 @@
*r.Operation.Security = append(*r.Operation.Security, securityRequirements...)
}
}

// OptionStripTrailingSlash removes trailing slashes from both the route path and incoming requests.
// This can be applied globally using WithStripTrailingSlash() or per-route.
// For example: "/users/" becomes "/users" for both route definition and request handling.
func OptionStripTrailingSlash() func(*BaseRoute) {
return func(r *BaseRoute) {
// Strip trailing slash from route path
if len(r.Path) > 1 {
r.Path = strings.TrimRight(r.Path, "/")
}

// Add middleware to strip trailing slash from requests
stripSlashMiddleware := func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if len(r.URL.Path) > 1 {
r.URL.Path = strings.TrimRight(r.URL.Path, "/")
}
next.ServeHTTP(w, r)
})
}
Comment on lines +453 to +461
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please do not re-define this middleware each time the option is called. Place the middleware elsewhere :) Also, I think the middleware should be placed in Server.globalMiddlewares, see the difference in the docs.


// Add the middleware to the route
r.Middlewares = append(r.Middlewares, stripSlashMiddleware)
}
}

Check failure on line 467 in option.go

View workflow job for this annotation

GitHub Actions / golangci-lint

File is not properly formatted (gci)
25 changes: 25 additions & 0 deletions server.go
Original file line number Diff line number Diff line change
Expand Up @@ -449,3 +449,28 @@
}
}
}

// WithStripTrailingSlash configures the server to automatically strip trailing slashes from URLs.
// When enabled, requests to paths ending with "/" will be treated the same as their non-trailing
// slash counterparts. For example, "/users/" and "/users" will route to the same handler.
//
// This option affects both route registration and incoming requests. When a request comes in with
// a trailing slash, it will be matched against the non-trailing slash route if one exists.

// Example usage:
//
// s := fuego.NewServer(
// fuego.WithStripTrailingSlash(),
// )

// After enabling:

Check failure on line 466 in server.go

View workflow job for this annotation

GitHub Actions / golangci-lint

exported: comment on exported function WithStripTrailingSlash should be of the form "WithStripTrailingSlash ..." (revive)
// - A route registered as "/api/users" will match both "/api/users" and "/api/users/"
// - A route registered as "/api/users/" will be automatically converted to "/api/users"
//
// Note: This option should be set during server initialization as it affects all routes.
func WithStripTrailingSlash() func(*Server) {
return func(s *Server) {
// Add OptionStripTrailingSlash to the default route options
s.routeOptions = append(s.routeOptions, OptionStripTrailingSlash())
}
}
Loading