diff --git a/README.md b/README.md index c626298..f302bd0 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,29 @@ [![Build Status](https://travis-ci.org/bnkamalesh/webgo.svg?branch=master)](https://travis-ci.org/bnkamalesh/webgo) [![](https://goreportcard.com/badge/github.com/bnkamalesh/webgo)](https://goreportcard.com/report/github.com/bnkamalesh/webgo) -# WebGo v1.5.5 +# WebGo v2.0 + +1. Current implementation of logging middleware will be deprecated + - Logging middleware will be converted to wrapper + e.g. middlewares.Log(Handler) + This is a clean implementation, to avoid unnecessary complexity and + computation from ServeHTTP() + + +# WebGo v1.5.5 (current) A lightweight & simple web framework for Go. [GoDoc webgo](https://godoc.org/github.com/bnkamalesh/webgo) +### Update 18 March 2018 + - Added Trailing slash feature. Added a new option `TrailingSlash` boolean + to `Route` definition. If true, the provided URI pattern will be matched + with or without the trailing slash. Default is false. + +2. All middlewares will be moved to a nested folder `middlewares` rather than +being the methods of the type middlewares. + +These changes would cause backward incompatibility ### Requirements @@ -35,6 +53,16 @@ While using any of the default HTTP response function available, for any status status: } ``` +### URI patterns +While defining the path of an HTTP route; you can choose from the following +4 different options: + +1. Static path e.g. `/v1/api/users` +2. Path with named parameters e.g. `/v1/api/users/:userID/photos/:photoID` + - Here `userID` and `photoID` are the parameter names. +3. Path with wildcard e.g. `/v2/*` +4. Path with named wildcard parameter. e.g. `/v2/:param*` + ### [Middlewares](https://github.com/bnkamalesh/webgo/blob/master/middlewares.go) @@ -95,7 +123,6 @@ Following options can be provided in the JSON file "httpsPort": "", // Port on which the HTTPS server should listen to "certFile": "", // Certificate file path for HTTPS "keyFile": "", // Private key file path of the certificate - "templatePath": "" // Folder containing all the templates } ``` diff --git a/router.go b/router.go index a539869..0507cd2 100644 --- a/router.go +++ b/router.go @@ -18,6 +18,7 @@ import ( const ( urlchars = `([^/]+)` urlwildcard = `(.*)` + trailingSlash = `[\/]?` errMultiHeaderWrite = `http: multiple response.WriteHeader calls` errMultiWrite = `http: multiple response.Write calls` errDuplicateKey = `Error: Duplicate URI keys found` @@ -82,6 +83,9 @@ type Route struct { Method string // Pattern is the URI pattern to match Pattern string + // TrailingSlash if set to true, the URI will be matched with or without + // a trailing slash. Note: It does not *do* a redirect. + TrailingSlash bool // HideAccessLog if enabled will not print the basic access log to console HideAccessLog bool @@ -114,7 +118,8 @@ func (r *Route) init() error { patternString := r.Pattern if strings.Contains(r.Pattern, ":") { - // uriValues is a map of URI Key and it's respective value, this is calculated per request + // uriValues is a map of URI Key and it's respective value, + // this is calculated per request key := "" hasKey := false hasWildcard := false @@ -129,12 +134,18 @@ func (r *Route) init() error { } else if hasKey && char != "/" { key += char } else if hasKey && len(key) > 0 { + regexPattern := "" + patternKey := "" if hasWildcard { - patternString = strings.Replace(patternString, ":"+key+"*", urlwildcard, 1) + patternKey = ":" + key + "*" + regexPattern = urlwildcard } else { - patternString = strings.Replace(patternString, ":"+key, urlchars, 1) + patternKey = ":" + key + regexPattern = urlchars } + patternString = strings.Replace(patternString, patternKey, regexPattern, 1) + for idx, k := range r.uriKeys { if key == k { l.Fatal(errDuplicateKey, "\nURI: ", r.Pattern, "\nKey:", k, ", Position:", idx+1) @@ -149,12 +160,18 @@ func (r *Route) init() error { } if hasKey && len(key) > 0 { + regexPattern := "" + patternKey := "" if hasWildcard { - patternString = strings.Replace(patternString, ":"+key+"*", urlwildcard, 1) + patternKey = ":" + key + "*" + regexPattern = urlwildcard } else { - patternString = strings.Replace(patternString, ":"+key, urlchars, 1) + patternKey = ":" + key + regexPattern = urlchars } + patternString = strings.Replace(patternString, patternKey, regexPattern, 1) + for idx, k := range r.uriKeys { if key == k { l.Fatal(errDuplicateKey, "\nURI: ", r.Pattern, "\nKey:", k, ", Position:", idx+1) @@ -165,7 +182,12 @@ func (r *Route) init() error { } - patternString = "^" + patternString + "$" + if r.TrailingSlash { + patternString = "^" + patternString + trailingSlash + "$" + } else { + + patternString = "^" + patternString + "$" + } // compile the regex for the pattern string calculated reg, err := regexp.Compile(patternString) diff --git a/tests/main.go b/tests/main.go index b4bcc45..440afa0 100644 --- a/tests/main.go +++ b/tests/main.go @@ -78,11 +78,12 @@ func getRoutes(g *webgo.Globals) []*webgo.Route { G: g, }, &webgo.Route{ - Name: "hw-withparams", // A label for the API/URI, this is not used anywhere. - Method: http.MethodGet, // request type - Pattern: "/wparams/:p1/goblin/:p2", // Pattern for the route - Handler: []http.HandlerFunc{helloWorld}, // route handler - G: g, + Name: "hw-withparams", // A label for the API/URI, this is not used anywhere. + Method: http.MethodGet, + TrailingSlash: true, // request type + Pattern: "/wparams/:p1/goblin/:p2", // Pattern for the route + Handler: []http.HandlerFunc{helloWorld}, // route handler + G: g, }, &webgo.Route{ Name: "params-get", // A label for the API/URI, this is not used anywhere.