From aee83e040b8f883ea98e3c1017d93db8ccc51c3d Mon Sep 17 00:00:00 2001 From: Lin Kao-Yuan Date: Wed, 18 Dec 2019 09:44:33 +0800 Subject: [PATCH 1/6] Fix "Custom Validators" example (#2186) * Update fixed error code from merged commit According to [this](https://github.com/gin-gonic/examples/commit/874dcfa6c457aa23996d67fa595a2acb8ea1f44b) merged commit. * Fixed incorrect testing date. Original testing date incompatible demo require, can't get expect result. check_in date need NOT AFTER check_out date. --- README.md | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index f8bc4239..7e3e6f41 100644 --- a/README.md +++ b/README.md @@ -704,25 +704,22 @@ package main import ( "net/http" - "reflect" "time" "github.com/gin-gonic/gin" "github.com/gin-gonic/gin/binding" - "gopkg.in/go-playground/validator.v8" + "gopkg.in/go-playground/validator.v9" ) // Booking contains binded and validated data. type Booking struct { - CheckIn time.Time `form:"check_in" binding:"required,bookabledate" time_format:"2006-01-02"` + CheckIn time.Time `form:"check_in" binding:"required" time_format:"2006-01-02"` CheckOut time.Time `form:"check_out" binding:"required,gtfield=CheckIn" time_format:"2006-01-02"` } -func bookableDate( - v *validator.Validate, topStruct reflect.Value, currentStructOrField reflect.Value, - field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string, -) bool { - if date, ok := field.Interface().(time.Time); ok { +var bookableDate validator.Func = func(fl validator.FieldLevel) bool { + date, ok := fl.Field().Interface().(time.Time) + if ok { today := time.Now() if today.After(date) { return false @@ -756,7 +753,7 @@ func getBookable(c *gin.Context) { $ curl "localhost:8085/bookable?check_in=2018-04-16&check_out=2018-04-17" {"message":"Booking dates are valid!"} -$ curl "localhost:8085/bookable?check_in=2018-03-08&check_out=2018-03-09" +$ curl "localhost:8085/bookable?check_in=2018-03-10&check_out=2018-03-09" {"error":"Key: 'Booking.CheckIn' Error:Field validation for 'CheckIn' failed on the 'bookabledate' tag"} ``` From d6143d8d7c0c63d9bedc84f70c5d719f9dbf599b Mon Sep 17 00:00:00 2001 From: thinkerou Date: Wed, 18 Dec 2019 16:58:38 +0800 Subject: [PATCH 2/6] tree: remove one else statement (#2177) --- tree.go | 207 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 103 insertions(+), 104 deletions(-) diff --git a/tree.go b/tree.go index b09d3f67..89f74deb 100644 --- a/tree.go +++ b/tree.go @@ -425,110 +425,7 @@ func (n *node) getValue(path string, po Params, unescape bool) (value nodeValue) walk: // Outer loop for walking the tree for { prefix := n.path - if len(path) > len(prefix) { - if path[:len(prefix)] == prefix { - path = path[len(prefix):] - // If this node does not have a wildcard (param or catchAll) - // child, we can just look up the next child node and continue - // to walk down the tree - if !n.wildChild { - c := path[0] - indices := n.indices - for i, max := 0, len(indices); i < max; i++ { - if c == indices[i] { - n = n.children[i] - prefix = n.path - continue walk - } - } - - // Nothing found. - // We can recommend to redirect to the same URL without a - // trailing slash if a leaf exists for that path. - value.tsr = path == "/" && n.handlers != nil - return - } - - // handle wildcard child - n = n.children[0] - switch n.nType { - case param: - // find param end (either '/' or path end) - end := 0 - for end < len(path) && path[end] != '/' { - end++ - } - - // save param value - if cap(value.params) < int(n.maxParams) { - value.params = make(Params, 0, n.maxParams) - } - i := len(value.params) - value.params = value.params[:i+1] // expand slice within preallocated capacity - value.params[i].Key = n.path[1:] - val := path[:end] - if unescape { - var err error - if value.params[i].Value, err = url.QueryUnescape(val); err != nil { - value.params[i].Value = val // fallback, in case of error - } - } else { - value.params[i].Value = val - } - - // we need to go deeper! - if end < len(path) { - if len(n.children) > 0 { - path = path[end:] - n = n.children[0] - prefix = n.path - continue walk - } - - // ... but we can't - value.tsr = len(path) == end+1 - return - } - - if value.handlers = n.handlers; value.handlers != nil { - value.fullPath = n.fullPath - return - } - if len(n.children) == 1 { - // No handle found. Check if a handle for this path + a - // trailing slash exists for TSR recommendation - n = n.children[0] - value.tsr = n.path == "/" && n.handlers != nil - } - - return - - case catchAll: - // save param value - if cap(value.params) < int(n.maxParams) { - value.params = make(Params, 0, n.maxParams) - } - i := len(value.params) - value.params = value.params[:i+1] // expand slice within preallocated capacity - value.params[i].Key = n.path[2:] - if unescape { - var err error - if value.params[i].Value, err = url.QueryUnescape(path); err != nil { - value.params[i].Value = path // fallback, in case of error - } - } else { - value.params[i].Value = path - } - - value.handlers = n.handlers - value.fullPath = n.fullPath - return - - default: - panic("invalid node type") - } - } - } else if path == prefix { + if path == prefix { // We should have reached the node containing the handle. // Check if this node has a handle registered. if value.handlers = n.handlers; value.handlers != nil { @@ -556,6 +453,108 @@ walk: // Outer loop for walking the tree return } + if len(path) > len(prefix) && path[:len(prefix)] == prefix { + path = path[len(prefix):] + // If this node does not have a wildcard (param or catchAll) + // child, we can just look up the next child node and continue + // to walk down the tree + if !n.wildChild { + c := path[0] + indices := n.indices + for i, max := 0, len(indices); i < max; i++ { + if c == indices[i] { + n = n.children[i] + prefix = n.path + continue walk + } + } + + // Nothing found. + // We can recommend to redirect to the same URL without a + // trailing slash if a leaf exists for that path. + value.tsr = path == "/" && n.handlers != nil + return + } + + // handle wildcard child + n = n.children[0] + switch n.nType { + case param: + // find param end (either '/' or path end) + end := 0 + for end < len(path) && path[end] != '/' { + end++ + } + + // save param value + if cap(value.params) < int(n.maxParams) { + value.params = make(Params, 0, n.maxParams) + } + i := len(value.params) + value.params = value.params[:i+1] // expand slice within preallocated capacity + value.params[i].Key = n.path[1:] + val := path[:end] + if unescape { + var err error + if value.params[i].Value, err = url.QueryUnescape(val); err != nil { + value.params[i].Value = val // fallback, in case of error + } + } else { + value.params[i].Value = val + } + + // we need to go deeper! + if end < len(path) { + if len(n.children) > 0 { + path = path[end:] + n = n.children[0] + prefix = n.path + continue walk + } + + // ... but we can't + value.tsr = len(path) == end+1 + return + } + + if value.handlers = n.handlers; value.handlers != nil { + value.fullPath = n.fullPath + return + } + if len(n.children) == 1 { + // No handle found. Check if a handle for this path + a + // trailing slash exists for TSR recommendation + n = n.children[0] + value.tsr = n.path == "/" && n.handlers != nil + } + return + + case catchAll: + // save param value + if cap(value.params) < int(n.maxParams) { + value.params = make(Params, 0, n.maxParams) + } + i := len(value.params) + value.params = value.params[:i+1] // expand slice within preallocated capacity + value.params[i].Key = n.path[2:] + if unescape { + var err error + if value.params[i].Value, err = url.QueryUnescape(path); err != nil { + value.params[i].Value = path // fallback, in case of error + } + } else { + value.params[i].Value = path + } + + value.handlers = n.handlers + value.fullPath = n.fullPath + return + + default: + panic("invalid node type") + } + } + // Nothing found. We can recommend to redirect to the same URL with an // extra trailing slash if a leaf exists for that path value.tsr = (path == "/") || From 1b480ed294cb6d8727e95534af6e668a40231dbd Mon Sep 17 00:00:00 2001 From: Lin Kao-Yuan Date: Wed, 18 Dec 2019 21:08:58 +0800 Subject: [PATCH 3/6] Update to currently output (#2188) Excuse me, I forgot change output in #2186 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7e3e6f41..01c4089a 100644 --- a/README.md +++ b/README.md @@ -754,7 +754,7 @@ $ curl "localhost:8085/bookable?check_in=2018-04-16&check_out=2018-04-17" {"message":"Booking dates are valid!"} $ curl "localhost:8085/bookable?check_in=2018-03-10&check_out=2018-03-09" -{"error":"Key: 'Booking.CheckIn' Error:Field validation for 'CheckIn' failed on the 'bookabledate' tag"} +{"error":"Key: 'Booking.CheckOut' Error:Field validation for 'CheckOut' failed on the 'gtfield' tag"} ``` [Struct level validations](https://github.com/go-playground/validator/releases/tag/v8.7) can also be registered this way. From cc14a770cd11fbd0d1aa1a0a895e69ce8cd1415a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=A3=9E=E9=9B=AA=E6=97=A0=E6=83=85?= Date: Thu, 19 Dec 2019 11:21:58 +0800 Subject: [PATCH 4/6] upgrade go-validator to v10 for README (#2189) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 01c4089a..092fedc8 100644 --- a/README.md +++ b/README.md @@ -584,7 +584,7 @@ func main() { To bind a request body into a type, use model binding. We currently support binding of JSON, XML, YAML and standard form values (foo=bar&boo=baz). -Gin uses [**go-playground/validator.v8**](https://github.com/go-playground/validator) for validation. Check the full docs on tags usage [here](http://godoc.org/gopkg.in/go-playground/validator.v8#hdr-Baked_In_Validators_and_Tags). +Gin uses [**go-playground/validator/v10**](https://github.com/go-playground/validator) for validation. Check the full docs on tags usage [here](https://godoc.org/github.com/go-playground/validator#hdr-Baked_In_Validators_and_Tags). Note that you need to set the corresponding binding tag on all fields you want to bind. For example, when binding from JSON, set `json:"fieldname"`. From 9b3477ef9d2c6a611c9c00cc18aba5a6ba6a7641 Mon Sep 17 00:00:00 2001 From: Lin Kao-Yuan Date: Fri, 20 Dec 2019 14:01:58 +0800 Subject: [PATCH 5/6] Update validator to v10 (#2190) Passed my manual test, output nothing different. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 092fedc8..5c77b282 100644 --- a/README.md +++ b/README.md @@ -708,7 +708,7 @@ import ( "github.com/gin-gonic/gin" "github.com/gin-gonic/gin/binding" - "gopkg.in/go-playground/validator.v9" + "gopkg.in/go-playground/validator.v10" ) // Booking contains binded and validated data. From 59ab588bf597f9f41faee4f217b5659893c2e925 Mon Sep 17 00:00:00 2001 From: John Bampton Date: Mon, 30 Dec 2019 23:55:08 +1000 Subject: [PATCH 6/6] Remove broken link from README. (#2198) --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 5c77b282..6e0ceb27 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,6 @@ Gin is a web framework written in Go (Golang). It features a martini-like API wi ## Contents - [Installation](#installation) -- [Prerequisite](#prerequisite) - [Quick start](#quick-start) - [Benchmarks](#benchmarks) - [Gin v1.stable](#gin-v1-stable)