Skip to content

Commit

Permalink
Push branch develop into master
Browse files Browse the repository at this point in the history
  • Loading branch information
javierprovecho committed Apr 10, 2016
2 parents 3d002e3 + 72ffff6 commit 7d0b329
Show file tree
Hide file tree
Showing 8 changed files with 109 additions and 28 deletions.
3 changes: 2 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ language: go
sudo: false
go:
- 1.4
- 1.4.2
- 1.5
- 1.6
- tip

script:
Expand Down
70 changes: 51 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.



Expand All @@ -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
Expand Down Expand Up @@ -85,14 +85,21 @@ BenchmarkZeus_GithubAll | 2000 | 944234 | 300688 | 2648
## Start using it
1. Download and install it:

```sh
$ go get github.com/gin-gonic/gin
```
```sh
$ go get github.com/gin-gonic/gin
```

2. Import it in your code:

```go
import "github.com/gin-gonic/gin"
```
```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

Expand All @@ -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
}
```

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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})
Expand Down Expand Up @@ -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)
}()
})
Expand Down Expand Up @@ -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.
22 changes: 22 additions & 0 deletions binding/binding_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
6 changes: 3 additions & 3 deletions context.go
Original file line number Diff line number Diff line change
Expand Up @@ -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())
Expand All @@ -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
}
Expand Down Expand Up @@ -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 {
Expand Down
8 changes: 4 additions & 4 deletions examples/app-engine/hello.go
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -11,13 +11,13 @@ func init() {
r := gin.New()

// Define your handlers
r.GET("/", func(c *gin.Context){
r.GET("/", func(c *gin.Context) {
c.String(200, "Hello World!")
})
r.GET("/ping", func(c *gin.Context){
r.GET("/ping", func(c *gin.Context) {
c.String(200, "pong")
})

// Handle all requests using net/http
http.Handle("/", r)
}
}
26 changes: 26 additions & 0 deletions gin_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"time"

"github.com/stretchr/testify/assert"
"net/http/httptest"
)

func testRequest(t *testing.T, url string) {
Expand Down Expand Up @@ -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")
}
2 changes: 1 addition & 1 deletion gin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}
Expand Down
File renamed without changes.

0 comments on commit 7d0b329

Please sign in to comment.