Skip to content

Commit

Permalink
feat: add responder and error middleware
Browse files Browse the repository at this point in the history
  • Loading branch information
vicanso committed Apr 11, 2020
1 parent 34a43f4 commit 8f1f79c
Show file tree
Hide file tree
Showing 22 changed files with 1,476 additions and 261 deletions.
37 changes: 20 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,19 +58,19 @@ e.Method(path string, ...func(*elton.Context) error)
elton的路由使用[httprouter](https://github.com/julienschmidt/httprouter),下面是两个简单的示例,更多的使用方式可以参考httprouter。

```go
// 带参数的路由配置
e.GET("/books/{type}", func(c *elton.Context) error {
c.BodyBuffer = bytes.NewBufferString(c.Param("type"))
return nil
// 带参数路由
e.GET("/users/{type}", func(c *elton.Context) error {
c.BodyBuffer = bytes.NewBufferString(c.Param("type"))
return nil
})

// 带中间件的路由配置
e.GET("/users/me", func(c *elton.Context) error {
c.Set("account", "tree.xie")
return c.Next()
c.Set("account", "tree.xie")
return c.Next()
}, func(c *elton.Context) error {
c.BodyBuffer = bytes.NewBufferString(c.GetString("account"))
return nil
c.BodyBuffer = bytes.NewBufferString(c.GetString("account"))
return nil
})
```

Expand Down Expand Up @@ -116,7 +116,6 @@ func main() {
panic(err)
}
}

```

### error-handler
Expand Down Expand Up @@ -159,12 +158,16 @@ func main() {
## bench

```
BenchmarkRoutes-8 2808996 417 ns/op 424 B/op 5 allocs/op
BenchmarkGetFunctionName-8 130826358 9.31 ns/op 0 B/op 0 allocs/op
BenchmarkContextGet-8 14899309 79.9 ns/op 16 B/op 1 allocs/op
BenchmarkContextNewMap-8 184250533 6.47 ns/op 0 B/op 0 allocs/op
BenchmarkConvertServerTiming-8 1421496 854 ns/op 360 B/op 11 allocs/op
BenchmarkGetStatus-8 1000000000 0.542 ns/op 0 B/op 0 allocs/op
BenchmarkRWMutexSignedKeys-8 33935337 33.8 ns/op
BenchmarkAtomicSignedKeys-8 1000000000 0.402 ns/op
BenchmarkRoutes-8 5626749 220 ns/op 152 B/op 3 allocs/op
BenchmarkGetFunctionName-8 121043851 9.61 ns/op 0 B/op 0 allocs/op
BenchmarkContextGet-8 14413359 82.3 ns/op 16 B/op 1 allocs/op
BenchmarkContextNewMap-8 182361898 6.60 ns/op 0 B/op 0 allocs/op
BenchmarkConvertServerTiming-8 1377422 878 ns/op 360 B/op 11 allocs/op
BenchmarkGetStatus-8 1000000000 0.275 ns/op 0 B/op 0 allocs/op
BenchmarkStatic-8 21412 55142 ns/op 25940 B/op 628 allocs/op
BenchmarkGitHubAPI-8 13143 91191 ns/op 33816 B/op 812 allocs/op
BenchmarkGplusAPI-8 271857 4359 ns/op 2144 B/op 52 allocs/op
BenchmarkParseAPI-8 136795 8806 ns/op 4287 B/op 104 allocs/op
BenchmarkRWMutexSignedKeys-8 34447268 33.8 ns/op
BenchmarkAtomicSignedKeys-8 1000000000 0.412 ns/op
```
2 changes: 1 addition & 1 deletion SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,4 @@

* [Custom compress](./docs/custom_compress.md)

* [Router param validate](./docs/router_param_validate.md)
* [Router params](./docs/router_params.md)
22 changes: 22 additions & 0 deletions bench_test.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,25 @@
// MIT License

// Copyright (c) 2020 Tree Xie

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

package elton

import (
Expand Down
22 changes: 7 additions & 15 deletions context.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,6 @@ type (
Context struct {
Request *http.Request
Response http.ResponseWriter
// Headers http response's header, it's equal to response's header
Headers http.Header
// Committed commit the data to response, when it's true, the response has been sent.
// If using custom response handler, please set it true.
Committed bool
Expand Down Expand Up @@ -105,20 +103,18 @@ const (
func (c *Context) Reset() {
c.Request = nil
c.Response = nil
c.Headers = nil
c.Committed = false
c.ID = ""
c.Route = ""
c.Next = nil
c.Params = nil
c.Params.Reset()
c.StatusCode = 0
c.Body = nil
c.BodyBuffer = nil
c.RequestBody = nil
c.m = nil
c.realIP = ""
c.clientIP = ""
c.elton = nil
c.reuseStatus = ReuseContextEnabled
c.cacheQuery = nil
}
Expand Down Expand Up @@ -367,7 +363,7 @@ func (c *Context) AddRequestHeader(key, value string) {

// Header get headers of http response
func (c *Context) Header() http.Header {
return c.Headers
return c.Response.Header()
}

// WriteHeader set the http status code
Expand All @@ -385,23 +381,23 @@ func (c *Context) Write(buf []byte) (int, error) {

// GetHeader get header from http response
func (c *Context) GetHeader(key string) string {
return c.Headers.Get(key)
return c.Header().Get(key)
}

// SetHeader set http header to response.
// It replaces any existing values of the key.
func (c *Context) SetHeader(key, value string) {
if value == "" {
c.Headers.Del(key)
c.Header().Del(key)
return
}
c.Headers.Set(key, value)
c.Header().Set(key, value)
}

// AddHeader add http header to response.
// It appends to any existing value of the key.
func (c *Context) AddHeader(key, value string) {
c.Headers.Add(key, value)
c.Header().Add(key, value)
}

// ResetHeader reset response header
Expand Down Expand Up @@ -569,8 +565,7 @@ func (c *Context) DisableReuse() {
}

func (c *Context) isReuse() bool {
v := atomic.LoadInt32(&c.reuseStatus)
return v == ReuseContextEnabled
return atomic.LoadInt32(&c.reuseStatus) == ReuseContextEnabled
}

// Push http server push
Expand Down Expand Up @@ -630,8 +625,5 @@ func NewContext(resp http.ResponseWriter, req *http.Request) *Context {
c := &Context{}
c.Request = req
c.Response = resp
if resp != nil {
c.Headers = resp.Header()
}
return c
}
39 changes: 30 additions & 9 deletions context_test.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,25 @@
// MIT License

// Copyright (c) 2020 Tree Xie

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

package elton

import (
Expand All @@ -13,44 +35,43 @@ import (

func TestReset(t *testing.T) {
assert := assert.New(t)
params := new(RouteParams)
params.Add("key", "value")
c := Context{
Request: httptest.NewRequest("GET", "https://aslant.site/", nil),
Response: httptest.NewRecorder(),
Headers: make(http.Header),
Committed: true,
ID: "abcd",
Route: "/users/me",
Next: func() error {
return nil
},
Params: new(RouteParams),
Params: params,
StatusCode: 200,
Body: make(map[string]string),
BodyBuffer: bytes.NewBufferString("abcd"),
RequestBody: []byte("abcd"),
m: make(map[interface{}]interface{}),
realIP: "abcd",
clientIP: "abcd",
elton: &Elton{},
reuseStatus: ReuseContextEnabled,
}
c.Reset()
assert.Nil(c.Request)
assert.Nil(c.Response)
assert.Nil(c.Headers)
assert.False(c.Committed)
assert.Equal("", c.ID)
assert.Equal("", c.Route)
assert.Nil(c.Next)
assert.Nil(c.Params)
assert.Empty(params.Keys)
assert.Empty(params.Values)
assert.Equal(0, c.StatusCode)
assert.Nil(c.Body)
assert.Nil(c.BodyBuffer)
assert.Nil(c.RequestBody)
assert.Nil(c.m)
assert.Equal("", c.realIP)
assert.Equal("", c.clientIP)
assert.Nil(c.elton)
assert.Equal(int32(ReuseContextEnabled), c.reuseStatus)
}

Expand Down Expand Up @@ -356,7 +377,7 @@ func TestSignedCookie(t *testing.T) {
}
err := c.AddSignedCookie(cookie)
assert.Nil(err)
assert.Equal("a=b; Path=/; Max-Age=300; HttpOnly; Secure,a.sig=9yv2rWFijew8K8a5Uw9jxRJE53s; Path=/; Max-Age=300; HttpOnly; Secure", strings.Join(c.Headers[HeaderSetCookie], ","))
assert.Equal("a=b; Path=/; Max-Age=300; HttpOnly; Secure,a.sig=9yv2rWFijew8K8a5Uw9jxRJE53s; Path=/; Max-Age=300; HttpOnly; Secure", strings.Join(c.Header()[HeaderSetCookie], ","))
})

t.Run("get signed cookie", func(t *testing.T) {
Expand Down Expand Up @@ -448,8 +469,8 @@ func TestNotModified(t *testing.T) {
c := NewContext(resp, nil)
c.Body = map[string]string{}
c.BodyBuffer = bytes.NewBufferString("abc")
c.Headers.Set(HeaderContentEncoding, "gzip")
c.Headers.Set(HeaderContentType, "text/html")
c.SetHeader(HeaderContentEncoding, "gzip")
c.SetHeader(HeaderContentType, "text/html")
c.NotModified()
assert.Equal(http.StatusNotModified, c.StatusCode)
assert.Nil(c.Body)
Expand Down
Loading

0 comments on commit 8f1f79c

Please sign in to comment.