Skip to content

Commit

Permalink
Refactor web router inspired by chi
Browse files Browse the repository at this point in the history
  • Loading branch information
limpo1989 committed Dec 15, 2023
1 parent 164ecd1 commit 7d70622
Show file tree
Hide file tree
Showing 30 changed files with 2,145 additions and 8,311 deletions.
20 changes: 0 additions & 20 deletions web/bind.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import (
"errors"
"fmt"
"net/http"
"path"
"reflect"

"go-spring.dev/spring/internal/utils"
Expand Down Expand Up @@ -249,22 +248,3 @@ func defaultJsonRender(ctx *Context, err error, result interface{}) {

ctx.JSON(http.StatusOK, response{Code: code, Message: message, Data: result})
}

func lastChar(str string) uint8 {
if str == "" {
panic("The length of the string can't be 0")
}
return str[len(str)-1]
}

func joinPaths(absolutePath, relativePath string) string {
if relativePath == "" {
return absolutePath
}

finalPath := path.Join(absolutePath, relativePath)
if lastChar(relativePath) == '/' && lastChar(finalPath) != '/' {
return finalPath + "/"
}
return finalPath
}
80 changes: 73 additions & 7 deletions web/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ import (
"unicode"

"go-spring.dev/spring/web/binding"
"go-spring.dev/spring/web/internal/mux"
"go-spring.dev/spring/web/render"
)

Expand All @@ -55,9 +54,33 @@ type Context struct {
// or to be sent by a client.
Request *http.Request

routes Routes

// SameSite allows a server to define a cookie attribute making it impossible for
// the browser to send this cookie along with cross-site requests.
sameSite http.SameSite

// URLParams are the stack of routeParams captured during the
// routing lifecycle across a stack of sub-routers.
urlParams RouteParams

// routeParams matched for the current sub-router. It is
// intentionally unexported so it can't be tampered.
routeParams RouteParams

// Routing path/method override used during the route search.
routePath string
routeMethod string

// The endpoint routing pattern that matched the request URI path
// or `RoutePath` of the current sub-router. This value will update
// during the lifecycle of a request passing through a stack of
// sub-routers.
routePattern string
routePatterns []string

methodNotAllowed bool
methodsAllowed []methodTyp
}

// Context returns the request's context.
Expand Down Expand Up @@ -93,12 +116,7 @@ func (c *Context) Cookie(name string) (string, bool) {

// PathParam returns the named variables in the request.
func (c *Context) PathParam(name string) (string, bool) {
if params := mux.Vars(c.Request); nil != params {
if value, ok := params[name]; ok {
return value, true
}
}
return "", false
return c.urlParams.Get(name)

Check warning on line 119 in web/context.go

View check run for this annotation

Codecov / codecov/patch

web/context.go#L119

Added line #L119 was not covered by tests
}

// QueryParam returns the named query in the request.
Expand Down Expand Up @@ -297,6 +315,44 @@ func (c *Context) ClientIP() string {
return remoteIP.String()
}

// Reset context to initial state
func (c *Context) Reset() {
c.Writer = nil
c.Request = nil
c.sameSite = 0
c.routes = nil
c.routePath = ""
c.routeMethod = ""
c.routePattern = ""
c.routePatterns = c.routePatterns[:0]
c.urlParams.Keys = c.urlParams.Keys[:0]
c.urlParams.Values = c.urlParams.Values[:0]
c.routeParams.Keys = c.routeParams.Keys[:0]
c.routeParams.Values = c.routeParams.Values[:0]
c.methodNotAllowed = false
c.methodsAllowed = c.methodsAllowed[:0]

Check warning on line 333 in web/context.go

View check run for this annotation

Codecov / codecov/patch

web/context.go#L319-L333

Added lines #L319 - L333 were not covered by tests
}

// RouteParams is a structure to track URL routing parameters efficiently.
type RouteParams struct {
Keys, Values []string
}

// Add will append a URL parameter to the end of the route param
func (s *RouteParams) Add(key, value string) {
s.Keys = append(s.Keys, key)
s.Values = append(s.Values, value)

Check warning on line 344 in web/context.go

View check run for this annotation

Codecov / codecov/patch

web/context.go#L342-L344

Added lines #L342 - L344 were not covered by tests
}

func (s *RouteParams) Get(key string) (value string, ok bool) {
for index, k := range s.Keys {
if key == k {
return s.Values[index], true
}

Check warning on line 351 in web/context.go

View check run for this annotation

Codecov / codecov/patch

web/context.go#L347-L351

Added lines #L347 - L351 were not covered by tests
}
return "", false

Check warning on line 353 in web/context.go

View check run for this annotation

Codecov / codecov/patch

web/context.go#L353

Added line #L353 was not covered by tests
}

// https://stackoverflow.com/questions/53069040/checking-a-string-contains-only-ascii-characters
func isASCII(s string) bool {
for i := 0; i < len(s); i++ {
Expand Down Expand Up @@ -325,3 +381,13 @@ func bodyAllowedForStatus(status int) bool {
}
return true
}

func notFound() http.Handler {
return http.NotFoundHandler()

Check warning on line 386 in web/context.go

View check run for this annotation

Codecov / codecov/patch

web/context.go#L385-L386

Added lines #L385 - L386 were not covered by tests
}

func notAllowed() http.Handler {
return http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
http.Error(writer, "405 method not allowed", http.StatusMethodNotAllowed)
})

Check warning on line 392 in web/context.go

View check run for this annotation

Codecov / codecov/patch

web/context.go#L389-L392

Added lines #L389 - L392 were not covered by tests
}
Loading

0 comments on commit 7d70622

Please sign in to comment.