diff options
Diffstat (limited to 'vendor/github.com/gin-gonic/gin/README.md')
-rw-r--r-- | vendor/github.com/gin-gonic/gin/README.md | 186 |
1 files changed, 141 insertions, 45 deletions
diff --git a/vendor/github.com/gin-gonic/gin/README.md b/vendor/github.com/gin-gonic/gin/README.md index 9bf459b09..5cc8321b6 100644 --- a/vendor/github.com/gin-gonic/gin/README.md +++ b/vendor/github.com/gin-gonic/gin/README.md @@ -2,7 +2,7 @@ <img align="right" width="159px" src="https://raw.githubusercontent.com/gin-gonic/logo/master/color.png"> -[](https://travis-ci.org/gin-gonic/gin) +[](https://github.com/gin-gonic/gin/actions?query=branch%3Amaster) [](https://codecov.io/gh/gin-gonic/gin) [](https://goreportcard.com/report/github.com/gin-gonic/gin) [](https://pkg.go.dev/github.com/gin-gonic/gin?tab=doc) @@ -23,7 +23,8 @@ Gin is a web framework written in Go (Golang). It features a martini-like API wi - [Quick start](#quick-start) - [Benchmarks](#benchmarks) - [Gin v1. stable](#gin-v1-stable) - - [Build with jsoniter](#build-with-jsoniter) + - [Build with jsoniter/go-json](#build-with-json-replacement) + - [Build without `MsgPack` rendering feature](#build-without-msgpack-rendering-feature) - [API Examples](#api-examples) - [Using GET, POST, PUT, PATCH, DELETE and OPTIONS](#using-get-post-put-patch-delete-and-options) - [Parameters in path](#parameters-in-path) @@ -77,7 +78,7 @@ Gin is a web framework written in Go (Golang). It features a martini-like API wi - [http2 server push](#http2-server-push) - [Define format for the log of routes](#define-format-for-the-log-of-routes) - [Set and get a cookie](#set-and-get-a-cookie) - - [Don't trust all proxies](#don't-trust-all-proxies) + - [Don't trust all proxies](#dont-trust-all-proxies) - [Testing](#testing) - [Users](#users) @@ -85,7 +86,7 @@ Gin is a web framework written in Go (Golang). It features a martini-like API wi To install Gin package, you need to install Go and set your Go workspace first. -1. The first need [Go](https://golang.org/) installed (**version 1.13+ is required**), then you can use the below Go command to install Gin. +1. You first need [Go](https://golang.org/) installed (**version 1.14+ is required**), then you can use the below Go command to install Gin. ```sh $ go get -u github.com/gin-gonic/gin @@ -113,12 +114,16 @@ $ cat example.go ```go package main -import "github.com/gin-gonic/gin" +import ( + "net/http" + + "github.com/gin-gonic/gin" +) func main() { r := gin.Default() r.GET("/ping", func(c *gin.Context) { - c.JSON(200, gin.H{ + c.JSON(http.StatusOK, gin.H{ "message": "pong", }) }) @@ -183,13 +188,28 @@ Gin uses a custom version of [HttpRouter](https://github.com/julienschmidt/httpr - [x] Battle tested. - [x] API frozen, new releases will not break your code. -## Build with [jsoniter](https://github.com/json-iterator/go) +## Build with json replacement -Gin uses `encoding/json` as default json package but you can change to [jsoniter](https://github.com/json-iterator/go) by build from other tags. +Gin uses `encoding/json` as default json package but you can change it by build from other tags. +[jsoniter](https://github.com/json-iterator/go) ```sh $ go build -tags=jsoniter . ``` +[go-json](https://github.com/goccy/go-json) +```sh +$ go build -tags=go_json . +``` + +## Build without `MsgPack` rendering feature + +Gin enables `MsgPack` rendering feature by default. But you can disable this feature by specifying `nomsgpack` build tag. + +```sh +$ go build -tags=nomsgpack . +``` + +This is useful to reduce the binary size of executable files. See the [detail information](https://github.com/gin-gonic/gin/pull/1852). ## API Examples @@ -241,14 +261,15 @@ func main() { // For each matched request Context will hold the route definition router.POST("/user/:name/*action", func(c *gin.Context) { - c.FullPath() == "/user/:name/*action" // true + b := c.FullPath() == "/user/:name/*action" // true + c.String(http.StatusOK, "%t", b) }) // This handler will add a new router for /user/groups. // Exact routes are resolved before param routes, regardless of the order they were defined. // Routes starting with /user/groups are never interpreted as /user/:name/... routes router.GET("/user/groups", func(c *gin.Context) { - c.String(http.StatusOK, "The available groups are [...]", name) + c.String(http.StatusOK, "The available groups are [...]") }) router.Run(":8080") @@ -283,7 +304,7 @@ func main() { message := c.PostForm("message") nick := c.DefaultPostForm("nick", "anonymous") - c.JSON(200, gin.H{ + c.JSON(http.StatusOK, gin.H{ "status": "posted", "message": message, "nick": nick, @@ -367,7 +388,7 @@ func main() { // Set a lower memory limit for multipart forms (default is 32 MiB) router.MaxMultipartMemory = 8 << 20 // 8 MiB router.POST("/upload", func(c *gin.Context) { - // single file + // Single file file, _ := c.FormFile("file") log.Println(file.Filename) @@ -496,6 +517,7 @@ func main() { // nested group testing := authorized.Group("testing") + // visit 0.0.0.0:8080/testing/analytics testing.GET("/analytics", analyticsEndpoint) } @@ -552,7 +574,7 @@ func main() { router := gin.Default() router.GET("/ping", func(c *gin.Context) { - c.String(200, "pong") + c.String(http.StatusOK, "pong") }) router.Run(":8080") @@ -584,7 +606,7 @@ func main() { router.Use(gin.Recovery()) router.GET("/ping", func(c *gin.Context) { - c.String(200, "pong") + c.String(http.StatusOK, "pong") }) router.Run(":8080") @@ -612,7 +634,7 @@ func main() { router := gin.Default() router.GET("/ping", func(c *gin.Context) { - c.String(200, "pong") + c.String(http.StatusOK, "pong") }) router.Run(":8080") @@ -631,7 +653,7 @@ func main() { router := gin.Default() router.GET("/ping", func(c *gin.Context) { - c.String(200, "pong") + c.String(http.StatusOK, "pong") }) router.Run(":8080") @@ -640,7 +662,7 @@ func main() { ### Model binding and validation -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). +To bind a request body into a type, use model binding. We currently support binding of JSON, XML, YAML, TOML and standard form values (foo=bar&boo=baz). 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). @@ -648,10 +670,10 @@ Note that you need to set the corresponding binding tag on all fields you want t Also, Gin provides two sets of methods for binding: - **Type** - Must bind - - **Methods** - `Bind`, `BindJSON`, `BindXML`, `BindQuery`, `BindYAML`, `BindHeader` + - **Methods** - `Bind`, `BindJSON`, `BindXML`, `BindQuery`, `BindYAML`, `BindHeader`, `BindTOML` - **Behavior** - These methods use `MustBindWith` under the hood. If there is a binding error, the request is aborted with `c.AbortWithError(400, err).SetType(ErrorTypeBind)`. This sets the response status code to 400 and the `Content-Type` header is set to `text/plain; charset=utf-8`. Note that if you try to set the response code after this, it will result in a warning `[GIN-debug] [WARNING] Headers were already written. Wanted to override status code 400 with 422`. If you wish to have greater control over the behavior, consider using the `ShouldBind` equivalent method. - **Type** - Should bind - - **Methods** - `ShouldBind`, `ShouldBindJSON`, `ShouldBindXML`, `ShouldBindQuery`, `ShouldBindYAML`, `ShouldBindHeader` + - **Methods** - `ShouldBind`, `ShouldBindJSON`, `ShouldBindXML`, `ShouldBindQuery`, `ShouldBindYAML`, `ShouldBindHeader`, `ShouldBindTOML`, - **Behavior** - These methods use `ShouldBindWith` under the hood. If there is a binding error, the error is returned and it is the developer's responsibility to handle the request and error appropriately. When using the Bind-method, Gin tries to infer the binder depending on the Content-Type header. If you are sure what you are binding, you can use `MustBindWith` or `ShouldBindWith`. @@ -687,7 +709,7 @@ func main() { // Example for binding XML ( // <?xml version="1.0" encoding="UTF-8"?> // <root> - // <user>user</user> + // <user>manu</user> // <password>123</password> // </root>) router.POST("/loginXML", func(c *gin.Context) { @@ -830,6 +852,7 @@ package main import ( "log" + "net/http" "github.com/gin-gonic/gin" ) @@ -852,7 +875,7 @@ func startPage(c *gin.Context) { log.Println(person.Name) log.Println(person.Address) } - c.String(200, "Success") + c.String(http.StatusOK, "Success") } ``` @@ -866,6 +889,7 @@ package main import ( "log" + "net/http" "time" "github.com/gin-gonic/gin" @@ -889,7 +913,7 @@ func startPage(c *gin.Context) { var person Person // If `GET`, only `Form` binding engine (`query`) used. // If `POST`, first checks the `content-type` for `JSON` or `XML`, then uses `Form` (`form-data`). - // See more at https://github.com/gin-gonic/gin/blob/master/binding/binding.go#L48 + // See more at https://github.com/gin-gonic/gin/blob/master/binding/binding.go#L88 if c.ShouldBind(&person) == nil { log.Println(person.Name) log.Println(person.Address) @@ -898,7 +922,7 @@ func startPage(c *gin.Context) { log.Println(person.UnixTime) } - c.String(200, "Success") + c.String(http.StatusOK, "Success") } ``` @@ -914,7 +938,11 @@ See the [detail information](https://github.com/gin-gonic/gin/issues/846). ```go package main -import "github.com/gin-gonic/gin" +import ( + "net/http" + + "github.com/gin-gonic/gin" +) type Person struct { ID string `uri:"id" binding:"required,uuid"` @@ -926,10 +954,10 @@ func main() { route.GET("/:name/:id", func(c *gin.Context) { var person Person if err := c.ShouldBindUri(&person); err != nil { - c.JSON(400, gin.H{"msg": err}) + c.JSON(http.StatusBadRequest, gin.H{"msg": err.Error()}) return } - c.JSON(200, gin.H{"name": person.Name, "uuid": person.ID}) + c.JSON(http.StatusOK, gin.H{"name": person.Name, "uuid": person.ID}) }) route.Run(":8088") } @@ -948,6 +976,8 @@ package main import ( "fmt" + "net/http" + "github.com/gin-gonic/gin" ) @@ -962,11 +992,11 @@ func main() { h := testHeader{} if err := c.ShouldBindHeader(&h); err != nil { - c.JSON(200, err) + c.JSON(http.StatusOK, err) } fmt.Printf("%#v\n", h) - c.JSON(200, gin.H{"Rate": h.Rate, "Domain": h.Domain}) + c.JSON(http.StatusOK, gin.H{"Rate": h.Rate, "Domain": h.Domain}) }) r.Run() @@ -996,7 +1026,7 @@ type myForm struct { func formHandler(c *gin.Context) { var fakeForm myForm c.ShouldBind(&fakeForm) - c.JSON(200, gin.H{"color": fakeForm.Colors}) + c.JSON(http.StatusOK, gin.H{"color": fakeForm.Colors}) } ... @@ -1201,14 +1231,14 @@ func main() { // Serves unicode entities r.GET("/json", func(c *gin.Context) { - c.JSON(200, gin.H{ + c.JSON(http.StatusOK, gin.H{ "html": "<b>Hello, world!</b>", }) }) // Serves literal characters r.GET("/purejson", func(c *gin.Context) { - c.PureJSON(200, gin.H{ + c.PureJSON(http.StatusOK, gin.H{ "html": "<b>Hello, world!</b>", }) }) @@ -1226,7 +1256,8 @@ func main() { router.Static("/assets", "./assets") router.StaticFS("/more_static", http.Dir("my_file_system")) router.StaticFile("/favicon.ico", "./resources/favicon.ico") - + router.StaticFileFS("/more_favicon.ico", "more_favicon.ico", http.Dir("my_file_system")) + // Listen and serve on 0.0.0.0:8080 router.Run(":8080") } @@ -1392,7 +1423,7 @@ import ( func formatAsDate(t time.Time) string { year, month, day := t.Date() - return fmt.Sprintf("%d%02d/%02d", year, month, day) + return fmt.Sprintf("%d/%02d/%02d", year, month, day) } func main() { @@ -1454,7 +1485,7 @@ r.GET("/test", func(c *gin.Context) { r.HandleContext(c) }) r.GET("/test2", func(c *gin.Context) { - c.JSON(200, gin.H{"hello": "world"}) + c.JSON(http.StatusOK, gin.H{"hello": "world"}) }) ``` @@ -1607,6 +1638,7 @@ package main import ( "log" + "net/http" "github.com/gin-gonic/autotls" "github.com/gin-gonic/gin" @@ -1617,7 +1649,7 @@ func main() { // Ping handler r.GET("/ping", func(c *gin.Context) { - c.String(200, "pong") + c.String(http.StatusOK, "pong") }) log.Fatal(autotls.Run(r, "example1.com", "example2.com")) @@ -1631,6 +1663,7 @@ package main import ( "log" + "net/http" "github.com/gin-gonic/autotls" "github.com/gin-gonic/gin" @@ -1642,7 +1675,7 @@ func main() { // Ping handler r.GET("/ping", func(c *gin.Context) { - c.String(200, "pong") + c.String(http.StatusOK, "pong") }) m := autocert.Manager{ @@ -1811,7 +1844,7 @@ func main() { quit := make(chan os.Signal) // kill (no param) default send syscall.SIGTERM // kill -2 is syscall.SIGINT - // kill -9 is syscall.SIGKILL but can't be catch, so don't need add it + // kill -9 is syscall.SIGKILL but can't be caught, so don't need to add it signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) <-quit log.Println("Shutting down server...") @@ -1903,7 +1936,7 @@ type StructD struct { func GetDataB(c *gin.Context) { var b StructB c.Bind(&b) - c.JSON(200, gin.H{ + c.JSON(http.StatusOK, gin.H{ "a": b.NestedStruct, "b": b.FieldB, }) @@ -1912,7 +1945,7 @@ func GetDataB(c *gin.Context) { func GetDataC(c *gin.Context) { var b StructC c.Bind(&b) - c.JSON(200, gin.H{ + c.JSON(http.StatusOK, gin.H{ "a": b.NestedStructPointer, "c": b.FieldC, }) @@ -1921,7 +1954,7 @@ func GetDataC(c *gin.Context) { func GetDataD(c *gin.Context) { var b StructD c.Bind(&b) - c.JSON(200, gin.H{ + c.JSON(http.StatusOK, gin.H{ "x": b.NestedAnonyStruct, "d": b.FieldD, }) @@ -1984,7 +2017,7 @@ func SomeHandler(c *gin.Context) { objA := formA{} objB := formB{} // This reads c.Request.Body and stores the result into the context. - if errA := c.ShouldBindBodyWith(&objA, binding.JSON); errA == nil { + if errA := c.ShouldBindBodyWith(&objA, binding.Form); errA == nil { c.String(http.StatusOK, `the body should be formA`) // At this time, it reuses body stored in the context. } else if errB := c.ShouldBindBodyWith(&objB, binding.JSON); errB == nil { @@ -2006,6 +2039,61 @@ enough to call binding at once. can be called by `c.ShouldBind()` multiple times without any damage to performance (See [#1341](https://github.com/gin-gonic/gin/pull/1341)). +### Bind form-data request with custom struct and custom tag + +```go +const ( + customerTag = "url" + defaultMemory = 32 << 20 +) + +type customerBinding struct {} + +func (customerBinding) Name() string { + return "form" +} + +func (customerBinding) Bind(req *http.Request, obj interface{}) error { + if err := req.ParseForm(); err != nil { + return err + } + if err := req.ParseMultipartForm(defaultMemory); err != nil { + if err != http.ErrNotMultipart { + return err + } + } + if err := binding.MapFormWithTag(obj, req.Form, customerTag); err != nil { + return err + } + return validate(obj) +} + +func validate(obj interface{}) error { + if binding.Validator == nil { + return nil + } + return binding.Validator.ValidateStruct(obj) +} + +// Now we can do this!!! +// FormA is a external type that we can't modify it's tag +type FormA struct { + FieldA string `url:"field_a"` +} + +func ListHandler(s *Service) func(ctx *gin.Context) { + return func(ctx *gin.Context) { + var urlBinding = customerBinding{} + var opt FormA + err := ctx.MustBindWith(&opt, urlBinding) + if err != nil { + ... + } + ... + } +} +``` + ### http2 server push http.Pusher is supported only **go1.8+**. See the [golang blog](https://blog.golang.org/h2push) for detail information. @@ -2016,6 +2104,7 @@ package main import ( "html/template" "log" + "net/http" "github.com/gin-gonic/gin" ) @@ -2044,7 +2133,7 @@ func main() { log.Printf("Failed to push: %v", err) } } - c.HTML(200, "https", gin.H{ + c.HTML(http.StatusOK, "https", gin.H{ "status": "success", }) }) @@ -2200,10 +2289,16 @@ The `net/http/httptest` package is preferable way for HTTP testing. ```go package main +import ( + "net/http" + + "github.com/gin-gonic/gin" +) + func setupRouter() *gin.Engine { r := gin.Default() r.GET("/ping", func(c *gin.Context) { - c.String(200, "pong") + c.String(http.StatusOK, "pong") }) return r } @@ -2231,10 +2326,10 @@ func TestPingRoute(t *testing.T) { router := setupRouter() w := httptest.NewRecorder() - req, _ := http.NewRequest("GET", "/ping", nil) + req, _ := http.NewRequest(http.MethodGet, "/ping", nil) router.ServeHTTP(w, req) - assert.Equal(t, 200, w.Code) + assert.Equal(t, http.StatusOK, w.Code) assert.Equal(t, "pong", w.Body.String()) } ``` @@ -2250,3 +2345,4 @@ Awesome project lists using [Gin](https://github.com/gin-gonic/gin) web framewor * [picfit](https://github.com/thoas/picfit): An image resizing server written in Go. * [brigade](https://github.com/brigadecore/brigade): Event-based Scripting for Kubernetes. * [dkron](https://github.com/distribworks/dkron): Distributed, fault tolerant job scheduling system. + |