mirror of https://github.com/gin-gonic/gin.git
Merge branch 'master' into master
This commit is contained in:
commit
84a97ef73e
|
@ -3,8 +3,6 @@ language: go
|
|||
matrix:
|
||||
fast_finish: true
|
||||
include:
|
||||
- go: 1.12.x
|
||||
env: GO111MODULE=on
|
||||
- go: 1.13.x
|
||||
- go: 1.13.x
|
||||
env:
|
||||
|
@ -17,6 +15,10 @@ matrix:
|
|||
- go: 1.15.x
|
||||
env:
|
||||
- TESTTAGS=nomsgpack
|
||||
- go: 1.16.x
|
||||
- go: 1.16.x
|
||||
env:
|
||||
- TESTTAGS=nomsgpack
|
||||
- go: master
|
||||
|
||||
git:
|
||||
|
|
27
README.md
27
README.md
|
@ -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)
|
||||
|
@ -84,7 +85,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.12+ is required**), then you can use the below Go command to install Gin.
|
||||
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.
|
||||
|
||||
```sh
|
||||
$ go get -u github.com/gin-gonic/gin
|
||||
|
@ -182,13 +183,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
|
||||
|
||||
|
@ -925,7 +941,7 @@ 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(400, gin.H{"msg": err.Error()})
|
||||
return
|
||||
}
|
||||
c.JSON(200, gin.H{"name": person.Name, "uuid": person.ID})
|
||||
|
@ -2215,3 +2231,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.
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ package binding
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"errors"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
|
@ -32,7 +32,7 @@ func (jsonBinding) Name() string {
|
|||
|
||||
func (jsonBinding) Bind(req *http.Request, obj interface{}) error {
|
||||
if req == nil || req.Body == nil {
|
||||
return fmt.Errorf("invalid request")
|
||||
return errors.New("invalid request")
|
||||
}
|
||||
return decodeJSON(req.Body, obj)
|
||||
}
|
||||
|
|
|
@ -1018,7 +1018,9 @@ func TestContextRenderFile(t *testing.T) {
|
|||
|
||||
assert.Equal(t, http.StatusOK, w.Code)
|
||||
assert.Contains(t, w.Body.String(), "func New() *Engine {")
|
||||
assert.Equal(t, "text/plain; charset=utf-8", w.Header().Get("Content-Type"))
|
||||
// Content-Type='text/plain; charset=utf-8' when go version <= 1.16,
|
||||
// else, Content-Type='text/x-go; charset=utf-8'
|
||||
assert.NotEqual(t, "", w.Header().Get("Content-Type"))
|
||||
}
|
||||
|
||||
func TestContextRenderFileFromFS(t *testing.T) {
|
||||
|
@ -1030,7 +1032,9 @@ func TestContextRenderFileFromFS(t *testing.T) {
|
|||
|
||||
assert.Equal(t, http.StatusOK, w.Code)
|
||||
assert.Contains(t, w.Body.String(), "func New() *Engine {")
|
||||
assert.Equal(t, "text/plain; charset=utf-8", w.Header().Get("Content-Type"))
|
||||
// Content-Type='text/plain; charset=utf-8' when go version <= 1.16,
|
||||
// else, Content-Type='text/x-go; charset=utf-8'
|
||||
assert.NotEqual(t, "", w.Header().Get("Content-Type"))
|
||||
assert.Equal(t, "/some/path", c.Request.URL.Path)
|
||||
}
|
||||
|
||||
|
@ -1044,7 +1048,7 @@ func TestContextRenderAttachment(t *testing.T) {
|
|||
|
||||
assert.Equal(t, 200, w.Code)
|
||||
assert.Contains(t, w.Body.String(), "func New() *Engine {")
|
||||
assert.Equal(t, fmt.Sprintf("attachment; filename=\"%s\"", newFilename), w.HeaderMap.Get("Content-Disposition"))
|
||||
assert.Equal(t, fmt.Sprintf("attachment; filename=\"%s\"", newFilename), w.Header().Get("Content-Disposition"))
|
||||
}
|
||||
|
||||
// TestContextRenderYAML tests that the response is serialized as YAML
|
||||
|
|
4
debug.go
4
debug.go
|
@ -12,7 +12,7 @@ import (
|
|||
"strings"
|
||||
)
|
||||
|
||||
const ginSupportMinGoVer = 12
|
||||
const ginSupportMinGoVer = 13
|
||||
|
||||
// IsDebugging returns true if the framework is running in debug mode.
|
||||
// Use SetMode(gin.ReleaseMode) to disable debug mode.
|
||||
|
@ -67,7 +67,7 @@ func getMinVer(v string) (uint64, error) {
|
|||
|
||||
func debugPrintWARNINGDefault() {
|
||||
if v, e := getMinVer(runtime.Version()); e == nil && v <= ginSupportMinGoVer {
|
||||
debugPrint(`[WARNING] Now Gin requires Go 1.12+.
|
||||
debugPrint(`[WARNING] Now Gin requires Go 1.13+.
|
||||
|
||||
`)
|
||||
}
|
||||
|
|
|
@ -104,7 +104,7 @@ func TestDebugPrintWARNINGDefault(t *testing.T) {
|
|||
})
|
||||
m, e := getMinVer(runtime.Version())
|
||||
if e == nil && m <= ginSupportMinGoVer {
|
||||
assert.Equal(t, "[GIN-debug] [WARNING] Now Gin requires Go 1.12+.\n\n[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.\n\n", re)
|
||||
assert.Equal(t, "[GIN-debug] [WARNING] Now Gin requires Go 1.13+.\n\n[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.\n\n", re)
|
||||
} else {
|
||||
assert.Equal(t, "[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.\n\n", re)
|
||||
}
|
||||
|
|
|
@ -1,34 +0,0 @@
|
|||
//go:build go1.13
|
||||
// +build go1.13
|
||||
|
||||
package gin
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
type TestErr string
|
||||
|
||||
func (e TestErr) Error() string { return string(e) }
|
||||
|
||||
// TestErrorUnwrap tests the behavior of gin.Error with "errors.Is()" and "errors.As()".
|
||||
// "errors.Is()" and "errors.As()" have been added to the standard library in go 1.13,
|
||||
// hence the "// +build go1.13" directive at the beginning of this file.
|
||||
func TestErrorUnwrap(t *testing.T) {
|
||||
innerErr := TestErr("somme error")
|
||||
|
||||
// 2 layers of wrapping : use 'fmt.Errorf("%w")' to wrap a gin.Error{}, which itself wraps innerErr
|
||||
err := fmt.Errorf("wrapped: %w", &Error{
|
||||
Err: innerErr,
|
||||
Type: ErrorTypeAny,
|
||||
})
|
||||
|
||||
// check that 'errors.Is()' and 'errors.As()' behave as expected :
|
||||
assert.True(t, errors.Is(err, innerErr))
|
||||
var testErr TestErr
|
||||
assert.True(t, errors.As(err, &testErr))
|
||||
}
|
|
@ -6,6 +6,7 @@ package gin
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/gin-gonic/gin/internal/json"
|
||||
|
@ -104,3 +105,24 @@ Error #03: third
|
|||
assert.Nil(t, errs.JSON())
|
||||
assert.Empty(t, errs.String())
|
||||
}
|
||||
|
||||
type TestErr string
|
||||
|
||||
func (e TestErr) Error() string { return string(e) }
|
||||
|
||||
// TestErrorUnwrap tests the behavior of gin.Error with "errors.Is()" and "errors.As()".
|
||||
// "errors.Is()" and "errors.As()" have been added to the standard library in go 1.13.
|
||||
func TestErrorUnwrap(t *testing.T) {
|
||||
innerErr := TestErr("somme error")
|
||||
|
||||
// 2 layers of wrapping : use 'fmt.Errorf("%w")' to wrap a gin.Error{}, which itself wraps innerErr
|
||||
err := fmt.Errorf("wrapped: %w", &Error{
|
||||
Err: innerErr,
|
||||
Type: ErrorTypeAny,
|
||||
})
|
||||
|
||||
// check that 'errors.Is()' and 'errors.As()' behave as expected :
|
||||
assert.True(t, errors.Is(err, innerErr))
|
||||
var testErr TestErr
|
||||
assert.True(t, errors.As(err, &testErr))
|
||||
}
|
||||
|
|
2
go.sum
2
go.sum
|
@ -11,6 +11,8 @@ github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD87
|
|||
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
|
||||
github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7aM3F26W0hOn+GE=
|
||||
github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
|
||||
github.com/goccy/go-json v0.4.11 h1:92nyX606ZN/cUFwctfxwDWm8YWSA38Zlv9s7taFeLyo=
|
||||
github.com/goccy/go-json v0.4.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||
github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I=
|
||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
// Copyright 2017 Bo-Yi Wu. All rights reserved.
|
||||
// Use of this source code is governed by a MIT style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build go_json
|
||||
// +build go_json
|
||||
|
||||
package json
|
||||
|
||||
import json "github.com/goccy/go-json"
|
||||
|
||||
var (
|
||||
// Marshal is exported by gin/json package.
|
||||
Marshal = json.Marshal
|
||||
// Unmarshal is exported by gin/json package.
|
||||
Unmarshal = json.Unmarshal
|
||||
// MarshalIndent is exported by gin/json package.
|
||||
MarshalIndent = json.MarshalIndent
|
||||
// NewDecoder is exported by gin/json package.
|
||||
NewDecoder = json.NewDecoder
|
||||
// NewEncoder is exported by gin/json package.
|
||||
NewEncoder = json.NewEncoder
|
||||
)
|
|
@ -2,8 +2,8 @@
|
|||
// Use of this source code is governed by a MIT style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build !jsoniter
|
||||
// +build !jsoniter
|
||||
//go:build !jsoniter && !go_json
|
||||
// +build !jsoniter,!go_json
|
||||
|
||||
package json
|
||||
|
||||
|
|
|
@ -11,6 +11,11 @@ import (
|
|||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
// reg match english letters for http method name
|
||||
regEnLetter = regexp.MustCompile("^[A-Z]+$")
|
||||
)
|
||||
|
||||
// IRouter defines all router handle interface includes single and group router.
|
||||
type IRouter interface {
|
||||
IRoutes
|
||||
|
@ -87,7 +92,7 @@ func (group *RouterGroup) handle(httpMethod, relativePath string, handlers Handl
|
|||
// frequently used, non-standardized or custom methods (e.g. for internal
|
||||
// communication with a proxy).
|
||||
func (group *RouterGroup) Handle(httpMethod, relativePath string, handlers ...HandlerFunc) IRoutes {
|
||||
if matches, err := regexp.MatchString("^[A-Z]+$", httpMethod); !matches || err != nil {
|
||||
if matched := regEnLetter.MatchString(httpMethod); !matched {
|
||||
panic("http method " + httpMethod + " is not valid")
|
||||
}
|
||||
return group.handle(httpMethod, relativePath, handlers)
|
||||
|
|
|
@ -360,7 +360,9 @@ func TestRouterMiddlewareAndStatic(t *testing.T) {
|
|||
|
||||
assert.Equal(t, http.StatusOK, w.Code)
|
||||
assert.Contains(t, w.Body.String(), "package gin")
|
||||
assert.Equal(t, "text/plain; charset=utf-8", w.Header().Get("Content-Type"))
|
||||
// Content-Type='text/plain; charset=utf-8' when go version <= 1.16,
|
||||
// else, Content-Type='text/x-go; charset=utf-8'
|
||||
assert.NotEqual(t, "", w.Header().Get("Content-Type"))
|
||||
assert.NotEqual(t, w.Header().Get("Last-Modified"), "Mon, 02 Jan 2006 15:04:05 MST")
|
||||
assert.Equal(t, "Mon, 02 Jan 2006 15:04:05 MST", w.Header().Get("Expires"))
|
||||
assert.Equal(t, "Gin Framework", w.Header().Get("x-GIN"))
|
||||
|
|
Loading…
Reference in New Issue