Push branch develop into master

This commit is contained in:
Javier Provecho Fernandez 2016-04-10 23:54:45 +02:00
commit 7d0b329203
8 changed files with 109 additions and 28 deletions

View File

@ -2,7 +2,8 @@ language: go
sudo: false
go:
- 1.4
- 1.4.2
- 1.5
- 1.6
- tip
script:

View File

@ -6,7 +6,7 @@
[![GoDoc](https://godoc.org/github.com/gin-gonic/gin?status.svg)](https://godoc.org/github.com/gin-gonic/gin)
[![Join the chat at https://gitter.im/gin-gonic/gin](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/gin-gonic/gin?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
Gin is a web framework written in Golang. It features a martini-like API with much better performance, up to 40 times faster thanks to [httprouter](https://github.com/julienschmidt/httprouter). If you need performance and good productivity, you will love Gin.
Gin is a web framework written in Go (Golang). It features a martini-like API with much better performance, up to 40 times faster thanks to [httprouter](https://github.com/julienschmidt/httprouter). If you need performance and good productivity, you will love Gin.
@ -24,7 +24,7 @@ func main() {
r := gin.Default()
r.GET("/ping", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "hello world",
"message": "pong",
})
})
r.Run() // listen and server on 0.0.0.0:8080
@ -88,12 +88,19 @@ BenchmarkZeus_GithubAll | 2000 | 944234 | 300688 | 2648
```sh
$ go get github.com/gin-gonic/gin
```
2. Import it in your code:
```go
import "github.com/gin-gonic/gin"
```
3. (Optional) Import `net/http`. This is required for example if using constants such as `http.StatusOK`.
```go
import "net/http"
```
##API Examples
#### Using GET, POST, PUT, PATCH, DELETE and OPTIONS
@ -115,7 +122,7 @@ func main() {
// By default it serves on :8080 unless a
// PORT environment variable was defined.
router.Run()
// router.Run.Run(":3000") for a hard coded port
// router.Run(":3000") for a hard coded port
}
```
@ -211,6 +218,32 @@ func main() {
id: 1234; page: 1; name: manu; message: this_is_great
```
### Another example: upload file
References issue [#548](https://github.com/gin-gonic/gin/issues/548).
```go
func main() {
router := gin.Default()
router.POST("/upload", func(c *gin.Context) {
file, header , err := c.Request.FormFile("upload")
filename := header.Filename
fmt.Println(header.Filename)
out, err := os.Create("./tmp/"+filename+".png")
if err != nil {
log.Fatal(err)
}
defer out.Close()
_, err = io.Copy(out, file)
if err != nil {
log.Fatal(err)
}
})
router.Run(":8080")
}
```
#### Grouping routes
```go
@ -267,7 +300,7 @@ func main() {
// Authorization group
// authorized := r.Group("/", AuthRequired())
// exactly the same than:
// exactly the same as:
authorized := r.Group("/")
// per group middleware! in this case we use the custom created
// AuthRequired() middleware just in the "authorized" group.
@ -583,7 +616,7 @@ func main() {
// /admin/secrets endpoint
// hit "localhost:8080/admin/secrets
authorized.GET("/secrets", func(c *gin.Context) {
// get user, it was setted by the BasicAuth middleware
// get user, it was set by the BasicAuth middleware
user := c.MustGet(gin.AuthUserKey).(string)
if secret, ok := secrets[user]; ok {
c.JSON(http.StatusOK, gin.H{"user": user, "secret": secret})
@ -612,7 +645,7 @@ func main() {
// simulate a long task with time.Sleep(). 5 seconds
time.Sleep(5 * time.Second)
// note than you are using the copied context "c_cp", IMPORTANT
// note that you are using the copied context "cCp", IMPORTANT
log.Println("Done! in path " + cCp.Request.URL.Path)
}()
})
@ -660,18 +693,17 @@ func main() {
#### Graceful restart or stop
Do you want to graceful restart or stop your web server?
There be some ways.
There are some ways this can be done.
We can using fvbock/endless to replace the default ListenAndServe
Refer the issue for more details:
https://github.com/gin-gonic/gin/issues/296
We can use [fvbock/endless](https://github.com/fvbock/endless) to replace the default `ListenAndServe`. Refer issue [#296](https://github.com/gin-gonic/gin/issues/296) for more details.
```go
router := gin.Default()
router.GET("/", handler)
// [...]
endless.ListenAndServe(":4242", router)
```
An alternative to endless:
* [manners](https://github.com/braintree/manners): A polite Go HTTP server that shuts down gracefully.

View File

@ -139,6 +139,28 @@ func TestValidationDisabled(t *testing.T) {
assert.NoError(t, err)
}
func TestExistsSucceeds(t *testing.T) {
type HogeStruct struct {
Hoge *int `json:"hoge" binding:"exists"`
}
var obj HogeStruct
req := requestWithBody("POST", "/", `{"hoge": 0}`)
err := JSON.Bind(req, &obj)
assert.NoError(t, err)
}
func TestExistsFails(t *testing.T) {
type HogeStruct struct {
Hoge *int `json:"foo" binding:"exists"`
}
var obj HogeStruct
req := requestWithBody("POST", "/", `{"boen": 0}`)
err := JSON.Bind(req, &obj)
assert.Error(t, err)
}
func testFormBinding(t *testing.T, method, path, badPath, body, badBody string) {
b := Form
assert.Equal(t, b.Name(), "form")

View File

@ -77,7 +77,7 @@ func (c *Context) Copy() *Context {
return &cp
}
// HandlerName returns the main handle's name. For example if the handler is "handleGetUsers()", this
// HandlerName returns the main handler's name. For example if the handler is "handleGetUsers()", this
// function will return "main.handleGetUsers"
func (c *Context) HandlerName() string {
return nameOfFunction(c.handlers.Last())
@ -98,7 +98,7 @@ func (c *Context) Next() {
}
}
// IsAborted returns true if the currect context was aborted.
// IsAborted returns true if the current context was aborted.
func (c *Context) IsAborted() bool {
return c.index >= abortIndex
}
@ -279,7 +279,7 @@ func (c *Context) GetPostForm(key string) (string, bool) {
// "application/json" --> JSON binding
// "application/xml" --> XML binding
// otherwise --> returns an error
// If Parses the request's body as JSON if Content-Type == "application/json" using JSON or XML as a JSON input.
// It parses the request's body as JSON if Content-Type == "application/json" using JSON or XML as a JSON input.
// It decodes the json payload into the struct specified as a pointer.
// Like ParseBody() but this method also writes a 400 error if the json is not valid.
func (c *Context) Bind(obj interface{}) error {

View File

@ -1,8 +1,8 @@
package hello
import (
"net/http"
"github.com/gin-gonic/gin"
"net/http"
)
// This function's name is a must. App Engine uses it to drive the requests properly.

View File

@ -11,6 +11,7 @@ import (
"time"
"github.com/stretchr/testify/assert"
"net/http/httptest"
)
func testRequest(t *testing.T, url string) {
@ -103,3 +104,28 @@ func TestBadUnixSocket(t *testing.T) {
router := New()
assert.Error(t, router.RunUnix("#/tmp/unix_unit_test"))
}
func TestWithHttptestWithAutoSelectedPort(t *testing.T) {
router := New()
router.GET("/example", func(c *Context) { c.String(http.StatusOK, "it worked") })
ts := httptest.NewServer(router)
defer ts.Close()
testRequest(t, ts.URL+"/example")
}
func TestWithHttptestWithSpecifiedPort(t *testing.T) {
router := New()
router.GET("/example", func(c *Context) { c.String(http.StatusOK, "it worked") })
l, _ := net.Listen("tcp", ":8033")
ts := httptest.Server{
Listener: l,
Config: &http.Server{Handler: router},
}
ts.Start()
defer ts.Close()
testRequest(t, "http://localhost:8033/example")
}

View File

@ -244,7 +244,7 @@ func TestListOfRoutes(t *testing.T) {
func assertRoutePresent(t *testing.T, gotRoutes RoutesInfo, wantRoute RouteInfo) {
for _, gotRoute := range gotRoutes {
if gotRoute.Path == wantRoute.Path && gotRoute.Method == wantRoute.Method {
assert.Regexp(t, wantRoute.Path, gotRoute.Path)
assert.Regexp(t, wantRoute.Handler, gotRoute.Handler)
return
}
}