Browse Source

Push branch develop into master

Javier Provecho Fernandez 9 years ago
parent
commit
7d0b329203
8 changed files with 109 additions and 28 deletions
  1. 2 1
      .travis.yml
  2. 51 19
      README.md
  3. 22 0
      binding/binding_test.go
  4. 3 3
      context.go
  5. 4 4
      examples/app-engine/hello.go
  6. 26 0
      gin_integration_test.go
  7. 1 1
      gin_test.go
  8. 0 0
      helpers_test.go

+ 2 - 1
.travis.yml

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

+ 51 - 19
README.md

@@ -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
@@ -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
 
@@ -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.

+ 22 - 0
binding/binding_test.go

@@ -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")

+ 3 - 3
context.go

@@ -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 {

+ 4 - 4
examples/app-engine/hello.go

@@ -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.
@@ -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 - 0
gin_integration_test.go

@@ -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")
+}

+ 1 - 1
gin_test.go

@@ -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
 		}
 	}

+ 0 - 0
test_helpers.go → helpers_test.go