Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
manucorporat committed Aug 20, 2014
2 parents c3abaf9 + a3a5753 commit 2d94e27
Show file tree
Hide file tree
Showing 14 changed files with 970 additions and 56 deletions.
22 changes: 16 additions & 6 deletions AUTHORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ List of all the awesome people working to make Gin the best Web Framework in Go!
##gin 0.x series authors

**Lead Developer:** Manu Martinez-Almeida (@manucorporat)
**Stuff:**
**Staff:**
Javier Provecho (@javierprovecho)

People and companies, who have contributed, in alphabetical order.
Expand All @@ -22,10 +22,13 @@ People and companies, who have contributed, in alphabetical order.
- Using template.Must to fix multiple return issue
- ★ Added support for OPTIONS verb
- ★ Setting response headers before calling WriteHeader
- Improved documentation for model binding
- ★ Added Content.Redirect()
- ★ Added tons of Unit tests


**@austinheap (Austin Heap)**
- Adds travis CI integration
- Added travis CI integration


**@bluele (Jun Kimura)**
Expand Down Expand Up @@ -67,20 +70,23 @@ People and companies, who have contributed, in alphabetical order.
**@mdigger (Dmitry Sedykh)**
- Fixes Form binding when content-type is x-www-form-urlencoded
- No repeat call c.Writer.Status() in gin.Logger
- Fixed Content-Type for json render
- Fixes Content-Type for json render


**@mopemope (Yutaka Matsubara)**
- ★ Adds Godep support (Dependencies Manager)
- Fix variadic parameter in the flexible render API
- Fix Corrupted plain render
- Fix variadic parameter in new flexible render API



**@msemenistyi (Mykyta Semenistyi)**
- update Readme.md. Add code to String method


**@msoedov (Sasha Myasoedov)**
- ★ Adds tons of unit tests.


**@ngerakines (Nick Gerakines)**
- ★ Improves API, c.GET() doesn't panic
- Adds MustGet() method
Expand All @@ -95,4 +101,8 @@ People and companies, who have contributed, in alphabetical order.


**@SkuliOskarsson (Skuli Oskarsson)**
- Fixes some texts in README II
- Fixes some texts in README II


**@yuyabee**
- Fixed README
10 changes: 8 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
##Changelog
#Changelog

###Gin 0.4 (??)
###Gin 0.4 (Aug 21, 2014)

- [NEW] Development mode
- [NEW] Unit tests
- [NEW] Add Content.Redirect()
- [FIX] Deferring WriteHeader()
- [FIX] Improved documentation for model binding


###Gin 0.3 (Jul 18, 2014)
Expand Down
63 changes: 48 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#Gin Web Framework

[![GoDoc](https://godoc.org/github.com/gin-gonic/gin?status.png)](https://godoc.org/github.com/gin-gonic/gin)
[![GoDoc](https://godoc.org/github.com/gin-gonic/gin?status.svg)](https://godoc.org/github.com/gin-gonic/gin)
[![Build Status](https://travis-ci.org/gin-gonic/gin.svg)](https://travis-ci.org/gin-gonic/gin)

Gin is a web framework written in Golang. It features a martini-like API with much better performance, up to 40 times faster. If you need performance and good productivity, you will love Gin.
Expand Down Expand Up @@ -196,39 +196,62 @@ func main() {
}
```

#### Model binding and validation

#### JSON parsing and validation
To bind a request body into a type, use model binding. We currently support binding of JSON, XML and standard form values (foo=bar&boo=baz).

Note that you need to set the corresponding binding tag on all fields you want to bind. For example, when binding from JSON, set `json:"fieldname"`.

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

You can also specify that specific fields are required. If a field is decorated with `binding:"required"` and has a empty value when binding, the current request will fail with an error.

```go
// Binding from JSON
type LoginJSON struct {
User string `json:"user" binding:"required"`
Password string `json:"password" binding:"required"`
}

// Binding from form values
type LoginForm struct {
User string `form:"user" binding:"required"`
Password string `form:"password" binding:"required"`
}

func main() {
r := gin.Default()

// Example for binding JSON ({"user": "manu", "password": "123"})
r.POST("/login", func(c *gin.Context) {
var json LoginJSON

// If EnsureBody returns false, it will write automatically the error
// in the HTTP stream and return a 400 error. If you want custom error
// handling you should use: c.ParseBody(interface{}) error
if c.EnsureBody(&json) {
if json.User == "manu" && json.Password == "123" {
c.JSON(200, gin.H{"status": "you are logged in"})
} else {
c.JSON(401, gin.H{"status": "unauthorized"})
}
}
c.Bind(&json) // This will infer what binder to use depending on the content-type header.
if json.User == "manu" && json.Password == "123" {
c.JSON(200, gin.H{"status": "you are logged in"})
} else {
c.JSON(401, gin.H{"status": "unauthorized"})
}
})

// Example for binding a HTLM form (user=manu&password=123)
r.POST("/login", func(c *gin.Context) {
var form LoginForm

c.BindWith(&form, binding.Form) // You can also specify which binder to use. We support binding.Form, binding.JSON and binding.XML.
if form.User == "manu" && form.Password == "123" {
c.JSON(200, gin.H{"status": "you are logged in"})
} else {
c.JSON(401, gin.H{"status": "unauthorized"})
}
})

// Listen and server on 0.0.0.0:8080
r.Run(":8080")
}
```

#### XML, and JSON rendering
#### XML and JSON rendering

```go
func main() {
Expand Down Expand Up @@ -297,6 +320,16 @@ func main() {
}
```

#### Redirects

Issuing a HTTP redirect is easy:

```r.GET("/test", func(c *gin.Context) {
c.Redirect(301, "https://www.google.com/")
})
Both internal and external locations are supported.
```

#### Custom Middlewares

Expand Down Expand Up @@ -392,7 +425,7 @@ func main() {
time.Sleep(5 * time.Second)

// note than you are using the copied context "c_cp", IMPORTANT
log.Println("Done! in path " + c_cp.Req.URL.Path)
log.Println("Done! in path " + c_cp.Request.URL.Path)
}()
})

Expand All @@ -402,7 +435,7 @@ func main() {
time.Sleep(5 * time.Second)

// since we are NOT using a goroutine, we do not have to copy the context
log.Println("Done! in path " + c.Req.URL.Path)
log.Println("Done! in path " + c.Request.URL.Path)
})

// Listen and server on 0.0.0.0:8080
Expand Down
57 changes: 57 additions & 0 deletions auth_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package gin

import (
"encoding/base64"
"net/http"
"net/http/httptest"
"testing"
)

func TestBasicAuthSucceed(t *testing.T) {
req, _ := http.NewRequest("GET", "/login", nil)
w := httptest.NewRecorder()

r := New()
accounts := Accounts{"admin": "password"}
r.Use(BasicAuth(accounts))

r.GET("/login", func(c *Context) {
c.String(200, "autorized")
})

req.Header.Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte("admin:password")))
r.ServeHTTP(w, req)

if w.Code != 200 {
t.Errorf("Response code should be Ok, was: %s", w.Code)
}
bodyAsString := w.Body.String()

if bodyAsString != "autorized" {
t.Errorf("Response body should be `autorized`, was %s", bodyAsString)
}
}

func TestBasicAuth401(t *testing.T) {
req, _ := http.NewRequest("GET", "/login", nil)
w := httptest.NewRecorder()

r := New()
accounts := Accounts{"foo": "bar"}
r.Use(BasicAuth(accounts))

r.GET("/login", func(c *Context) {
c.String(200, "autorized")
})

req.Header.Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte("admin:password")))
r.ServeHTTP(w, req)

if w.Code != 401 {
t.Errorf("Response code should be Not autorized, was: %s", w.Code)
}

if w.HeaderMap.Get("WWW-Authenticate") != "Basic realm=\"Authorization Required\"" {
t.Errorf("WWW-Authenticate header is incorrect: %s", w.HeaderMap.Get("Content-Type"))
}
}
9 changes: 9 additions & 0 deletions context.go
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,15 @@ func (c *Context) String(code int, format string, values ...interface{}) {
c.Render(code, render.Plain, format, values)
}

// Returns a HTTP redirect to the specific location.
func (c *Context) Redirect(code int, location string) {
if code >= 300 && code <= 308 {
c.Render(code, render.Redirect, location)
} else {
panic(fmt.Sprintf("Cannot send a redirect with status code %d", code))
}
}

// Writes some data into the body stream and updates the HTTP code.
func (c *Context) Data(code int, contentType string, data []byte) {
if len(contentType) > 0 {
Expand Down
Loading

0 comments on commit 2d94e27

Please sign in to comment.