Skip to content

Commit 36224c1

Browse files
committed
add contrib include session, response and template
1 parent 8c18568 commit 36224c1

File tree

14 files changed

+471
-121
lines changed

14 files changed

+471
-121
lines changed

binder/binder.go

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@ package binder
33
import (
44
"encoding/json"
55
"encoding/xml"
6-
"github.com/honmaple/forest/render"
6+
"errors"
77
"net/http"
88
"strings"
9+
10+
"github.com/honmaple/forest/render"
911
)
1012

1113
const defaultMemory = 32 << 20
@@ -91,15 +93,18 @@ func Bind(req *http.Request, dst interface{}) (err error) {
9193
if method != http.MethodPost && method != http.MethodPut && method != http.MethodPatch {
9294
return Query.Bind(req, dst)
9395
}
94-
ctype := req.Header.Get("Content-Type")
96+
ctype := req.Header.Get(render.ContentType)
9597
if strings.Contains(ctype, "/x-www-form-urlencoded") {
9698
return Form.Bind(req, dst)
9799
}
98-
if strings.HasPrefix(ctype, render.MIMEApplicationJSON) {
100+
if strings.Contains(ctype, "/form-data") {
101+
return MultipartForm.Bind(req, dst)
102+
}
103+
if strings.HasPrefix(ctype, render.ContentTypeJSON) {
99104
return JSON.Bind(req, dst)
100105
}
101-
if strings.HasPrefix(ctype, render.MIMEApplicationXML) {
106+
if strings.HasPrefix(ctype, render.ContentTypeXML) {
102107
return XML.Bind(req, dst)
103108
}
104-
return nil
109+
return errors.New("unknown content type: " + ctype)
105110
}

binder/mapping.go

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,24 @@ import (
88
)
99

1010
func bindData(value interface{}, dst map[string][]string, tagName string) error {
11-
v := reflect.ValueOf(value)
11+
val := reflect.ValueOf(value)
1212

13-
for v.Kind() == reflect.Ptr {
14-
v = v.Elem()
13+
for val.Kind() == reflect.Ptr {
14+
val = val.Elem()
1515
}
1616

17-
if v.Kind() != reflect.Struct {
17+
if val.Kind() == reflect.Map {
18+
for k, v := range dst {
19+
val.SetMapIndex(reflect.ValueOf(k), reflect.ValueOf(v[0]))
20+
}
21+
return nil
22+
}
23+
24+
if val.Kind() != reflect.Struct {
1825
return errors.New("not struct")
1926
}
2027

21-
t := v.Type()
28+
t := val.Type()
2229
for i := 0; i < t.NumField(); i++ {
2330
field := t.Field(i)
2431
tag := field.Tag.Get(tagName)
@@ -40,7 +47,7 @@ func bindData(value interface{}, dst map[string][]string, tagName string) error
4047
tag = opts[0]
4148
}
4249

43-
vfield := v.Field(i)
50+
vfield := val.Field(i)
4451
if omitempty && vfield.IsZero() {
4552
continue
4653
}

context.go

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -75,26 +75,23 @@ func (c *context) Get(key string) interface{} {
7575
return nil
7676
}
7777

78-
func (c *context) Param(key string) string {
78+
func (c *context) Param(name string) string {
7979
for i, p := range c.route.pnames {
80-
if i < len(c.pvalues) && p.key == key {
80+
if i < len(c.pvalues) && p.name == name {
8181
return c.pvalues[i]
8282
}
8383
}
8484
return ""
8585
}
8686

8787
func (c *context) Params() map[string]string {
88-
if c.route == nil {
88+
if c.route == nil || len(c.route.pnames) == 0 {
8989
return nil
9090
}
91-
if len(c.route.pnames) == 0 {
92-
return nil
93-
}
94-
params := make(Params)
91+
params := make(map[string]string)
9592
for i, p := range c.route.pnames {
9693
if i < len(c.pvalues) {
97-
params[p.key] = c.pvalues[i]
94+
params[p.name] = c.pvalues[i]
9895
}
9996
}
10097
return params

context_test.go

Lines changed: 56 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,24 @@
11
package forest
22

33
import (
4+
"encoding/json"
45
"net/http"
6+
"net/http/httptest"
7+
"strings"
58
"testing"
69

710
"github.com/honmaple/forest/render"
811
"github.com/stretchr/testify/assert"
9-
"net/http/httptest"
1012
)
1113

14+
type testStruct struct {
15+
Path string `json:"path"`
16+
Value int `json:"value"`
17+
}
18+
1219
var (
13-
testJSONString = "{\"path\":\"/json\",\"value\":1}"
1420
testString = "test ok"
21+
testJSONString = "{\"path\":\"/json\",\"value\":1}"
1522
)
1623

1724
func testJSON() H {
@@ -23,21 +30,59 @@ func TestContextRenderString(t *testing.T) {
2330
rec := httptest.NewRecorder()
2431
c := NewContext(req, rec)
2532
err := c.String(http.StatusOK, testString)
26-
if assert.NoError(t, err) {
27-
assert.Equal(t, http.StatusOK, rec.Code)
28-
assert.Equal(t, render.MIMETextPlainCharsetUTF8, rec.Header().Get("Content-Type"))
29-
assert.Equal(t, testString, rec.Body.String())
30-
}
33+
assert.NoError(t, err)
34+
assert.Equal(t, http.StatusOK, rec.Code)
35+
assert.Equal(t, render.ContentTypeTextCharsetUTF8, rec.Header().Get("Content-Type"))
36+
assert.Equal(t, testString, rec.Body.String())
3137
}
3238

3339
func TestContextRenderJSON(t *testing.T) {
3440
req := httptest.NewRequest(http.MethodGet, "/", nil)
3541
rec := httptest.NewRecorder()
3642
c := NewContext(req, rec)
3743
err := c.JSON(http.StatusCreated, testJSON())
38-
if assert.NoError(t, err) {
39-
assert.Equal(t, http.StatusCreated, rec.Code)
40-
assert.Equal(t, render.MIMEApplicationJSONCharsetUTF8, rec.Header().Get("Content-Type"))
41-
assert.Equal(t, testJSONString+"\n", rec.Body.String())
44+
assert.NoError(t, err)
45+
assert.Equal(t, http.StatusCreated, rec.Code)
46+
assert.Equal(t, render.ContentTypeJSONCharsetUTF8, rec.Header().Get("Content-Type"))
47+
assert.Equal(t, testJSONString+"\n", rec.Body.String())
48+
}
49+
50+
func TestContextBind(t *testing.T) {
51+
req := httptest.NewRequest(http.MethodPost, "/", strings.NewReader(testJSONString))
52+
c := NewContext(req, nil)
53+
u := new(testStruct)
54+
55+
req.Header.Add(render.ContentType, render.ContentTypeJSON)
56+
err := c.Bind(u)
57+
assert.NoError(t, err)
58+
assert.Equal(t, &testStruct{"/json", 1}, u)
59+
60+
testHeaders := map[string]string{
61+
render.ContentType: render.ContentTypeJSON,
62+
"Test-Header": "header",
63+
}
64+
for k, v := range testHeaders {
65+
req.Header.Add(k, v)
4266
}
67+
headers := make(map[string]string)
68+
err = c.BindHeader(headers)
69+
assert.Equal(t, testHeaders, headers)
70+
}
71+
72+
func TestContextBindParam(t *testing.T) {
73+
router := New()
74+
router.GET("/:var1/:var2/{var3:int}", func(c Context) error {
75+
return c.JSON(200, c.Params())
76+
})
77+
req := httptest.NewRequest(http.MethodGet, "/1/2/3", nil)
78+
rec := httptest.NewRecorder()
79+
router.ServeHTTP(rec, req)
80+
81+
assert.Equal(t, 200, rec.Code)
82+
dst := map[string]string{}
83+
err := json.NewDecoder(rec.Body).Decode(&dst)
84+
assert.NoError(t, err)
85+
assert.Equal(t, dst["var1"], "1")
86+
assert.Equal(t, dst["var2"], "2")
87+
assert.Equal(t, dst["var3"], "3")
4388
}

contrib/go.mod

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
module github.com/honmaple/forest/contrib
2+
3+
go 1.16
4+
5+
require (
6+
github.com/flosch/pongo2/v5 v5.0.0
7+
github.com/gorilla/context v1.1.1
8+
github.com/gorilla/sessions v1.2.1
9+
github.com/honmaple/forest v0.0.0-20220118110126-8c1856839f96
10+
)

contrib/go.sum

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
2+
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
3+
github.com/flosch/pongo2/v5 v5.0.0 h1:ZauMp+iPZzh2aI1QM2UwRb0lXD4BoFcvBuWqefkIuq0=
4+
github.com/flosch/pongo2/v5 v5.0.0/go.mod h1:6ysKu++8ANFXmc3x6uA6iVaS+PKUoDfdX3yPcv8TIzY=
5+
github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8=
6+
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
7+
github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ=
8+
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
9+
github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7FsgI=
10+
github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
11+
github.com/honmaple/forest v0.0.0-20220118110126-8c1856839f96 h1:y0dvh4aJtS7wbpze2IHkP1SW09eG7qnTZ7etaEBaQ0Y=
12+
github.com/honmaple/forest v0.0.0-20220118110126-8c1856839f96/go.mod h1:2AXWDFeeFtwv5jfmYrWq1k2w1uWqS40x8YBakMaDFm4=
13+
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
14+
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
15+
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
16+
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
17+
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
18+
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
19+
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
20+
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
21+
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
22+
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
23+
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
24+
github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
25+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
26+
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
27+
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
28+
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
29+
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

contrib/response/response.go

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
package response
2+
3+
import (
4+
"net/http"
5+
"sync"
6+
7+
"github.com/honmaple/forest"
8+
)
9+
10+
type PageInfo struct {
11+
Page int `json:"page" query:"page"`
12+
Limit int `json:"limit" query:"limit"`
13+
Total int64 `json:"total"`
14+
NotLimit bool `json:"-"`
15+
}
16+
17+
func (s *PageInfo) GetLimit() (int, int) {
18+
if s.Page < 1 {
19+
s.Page = 1
20+
}
21+
if s.Limit < 1 {
22+
s.Limit = 10
23+
}
24+
offset := (s.Page - 1) * s.Limit
25+
if offset < 0 {
26+
offset = 0
27+
}
28+
return offset, s.Limit
29+
}
30+
31+
type Response struct {
32+
Code int `json:"code"`
33+
Data interface{} `json:"data,omitempty"`
34+
Message string `json:"message"`
35+
}
36+
37+
type ListResponse struct {
38+
PageInfo
39+
List interface{} `json:"list,omitempty"`
40+
}
41+
42+
var respPool = sync.Pool{
43+
New: func() interface{} {
44+
return &Response{
45+
Code: http.StatusOK,
46+
Message: http.StatusText(http.StatusOK),
47+
}
48+
},
49+
}
50+
51+
func New(code int, data ...interface{}) *Response {
52+
resp := respPool.Get().(*Response)
53+
resp.Code = code
54+
55+
if len(data) == 0 {
56+
resp.Message = http.StatusText(code)
57+
} else {
58+
resp.Data = data
59+
}
60+
return resp
61+
}
62+
63+
func render(c forest.Context, code int, data ...interface{}) error {
64+
return c.JSON(code, New(code, data...))
65+
}
66+
67+
func OK(c forest.Context, message string, data interface{}) error {
68+
return render(c, http.StatusOK, message, data)
69+
}
70+
71+
func BadRequest(c forest.Context, data ...interface{}) error {
72+
return render(c, http.StatusBadRequest, data)
73+
}
74+
75+
func UnAuthorized(c forest.Context, message string, data interface{}) error {
76+
return render(c, http.StatusUnauthorized, message, data)
77+
}
78+
79+
func Forbidden(c forest.Context, message string, data interface{}) error {
80+
return render(c, http.StatusForbidden, message, data)
81+
}
82+
83+
func NotFound(c forest.Context, message string, data interface{}) error {
84+
return render(c, http.StatusNotFound, message, data)
85+
}
86+
87+
func ServerError(c forest.Context, message string, data interface{}) error {
88+
return render(c, http.StatusInternalServerError, message, data)
89+
}

0 commit comments

Comments
 (0)