Skip to content

Commit 3f4fe7e

Browse files
Merge pull request #1 from Demand-IQ/media-type-support
Media Type support
2 parents c4f8b2f + 7281eef commit 3f4fe7e

File tree

5 files changed

+90
-27
lines changed

5 files changed

+90
-27
lines changed

go.mod

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,14 @@
1-
module github.com/loopfz/gadgeto
1+
module github.com/demand-iq/gadgeto
22

33
require (
44
github.com/gin-gonic/gin v1.6.3
55
github.com/go-gorp/gorp v2.2.0+incompatible
66
github.com/go-playground/validator/v10 v10.2.0
7-
github.com/go-sql-driver/mysql v1.5.0 // indirect
8-
github.com/golang/protobuf v1.3.5 // indirect
97
github.com/google/uuid v1.1.1
108
github.com/juju/errors v0.0.0-20200330140219-3fe23663418f
11-
github.com/juju/testing v0.0.0-20210302031854-2c7ee8570c07 // indirect
12-
github.com/lib/pq v1.9.0 // indirect
9+
github.com/loopfz/gadgeto v0.11.2
1310
github.com/mattn/go-sqlite3 v2.0.3+incompatible
14-
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
15-
github.com/modern-go/reflect2 v1.0.1 // indirect
1611
github.com/pires/go-proxyproto v0.6.0
17-
github.com/poy/onpar v1.1.2 // indirect
18-
github.com/ziutek/mymysql v1.5.4 // indirect
1912
)
2013

2114
go 1.13

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,8 @@ github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
113113
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
114114
github.com/lib/pq v1.9.0 h1:L8nSXQQzAYByakOFMTwpjRoHsMJklur4Gi59b6VivR8=
115115
github.com/lib/pq v1.9.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
116+
github.com/loopfz/gadgeto v0.11.2 h1:kc7GoNcNgjQOZmA6nwS1jOC6yek9GoyDkxQ2vCwf63g=
117+
github.com/loopfz/gadgeto v0.11.2/go.mod h1:FFfb8QmTdEo+z9pvzTeTousO2ZoP81WInQg1aG42UOo=
116118
github.com/lunixbochs/vtclean v0.0.0-20160125035106-4fbf7632a2c6/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
117119
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
118120
github.com/masterzen/azure-sdk-for-go v3.2.0-beta.0.20161014135628-ee4f0065d00c+incompatible/go.mod h1:mf8fjOu33zCqxUjuiU3I8S1lJMyEAlH+0F2+M5xl3hE=

tonic/handler.go

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,12 @@ var (
2222
// in parameters.
2323
// The handler may use the following signature:
2424
//
25-
// func(*gin.Context, [input object ptr]) ([output object], error)
25+
// func(*gin.Context, [input object ptr]) ([output object], error)
2626
//
2727
// Input and output objects are both optional.
2828
// As such, the minimal accepted signature is:
2929
//
30-
// func(*gin.Context) error
30+
// func(*gin.Context) error
3131
//
3232
// The wrapping gin-handler will bind the parameters from the query-string,
3333
// path, body and headers, and handle the errors.
@@ -49,16 +49,17 @@ func Handler(h interface{}, status int, options ...func(*Route)) gin.HandlerFunc
4949
// Wrap Gin handler.
5050
f := func(c *gin.Context) {
5151
_, ok := c.Get(tonicWantRouteInfos)
52+
r := &Route{}
53+
for _, opt := range options {
54+
opt(r)
55+
}
5256
if ok {
5357
r := &Route{}
5458
r.defaultStatusCode = status
5559
r.handler = hv
5660
r.handlerType = ht
5761
r.inputType = in
5862
r.outputType = out
59-
for _, opt := range options {
60-
opt(r)
61-
}
6263
c.Set(tonicRoutesInfos, r)
6364
c.Abort()
6465
return
@@ -71,8 +72,14 @@ func Handler(h interface{}, status int, options ...func(*Route)) gin.HandlerFunc
7172
// binding.
7273
if in != nil {
7374
input := reflect.New(in)
75+
routeBindHook := r.GetBindHook()
76+
if routeBindHook == nil {
77+
// use the default bindHook if the route
78+
// does not have a custom one
79+
routeBindHook = bindHook
80+
}
7481
// Bind the body with the hook.
75-
if err := bindHook(c, input.Interface()); err != nil {
82+
if err := routeBindHook(c, input.Interface()); err != nil {
7683
handleError(c, BindError{message: err.Error(), typ: in})
7784
return
7885
}
@@ -116,7 +123,11 @@ func Handler(h interface{}, status int, options ...func(*Route)) gin.HandlerFunc
116123
handleError(c, err.(error))
117124
return
118125
}
119-
renderHook(c, status, val)
126+
routeRenderHook := r.GetRenderHook()
127+
if routeRenderHook == nil {
128+
routeRenderHook = renderHook
129+
}
130+
routeRenderHook(c, status, val)
120131
}
121132
// Register route in tonic-enabled routes map
122133
route := &Route{
@@ -154,13 +165,13 @@ func RegisterValidation(tagName string, validationFunc validator.Func) error {
154165
//
155166
// eg. to use the names which have been specified for JSON representations of structs, rather than normal Go field names:
156167
//
157-
// validate.RegisterTagNameFunc(func(fld reflect.StructField) string {
158-
// name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0]
159-
// if name == "-" {
160-
// return ""
161-
// }
162-
// return name
163-
// }
168+
// validate.RegisterTagNameFunc(func(fld reflect.StructField) string {
169+
// name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0]
170+
// if name == "-" {
171+
// return ""
172+
// }
173+
// return name
174+
// }
164175
func RegisterTagNameFunc(registerTagFunc validator.TagNameFunc) {
165176
validatorObj.RegisterTagNameFunc(registerTagFunc)
166177
}

tonic/route.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,18 @@ type Route struct {
3232
// outputType is the type of the output object.
3333
// This can be nil if the handler use none.
3434
outputType reflect.Type
35+
36+
// the bindHook for this route
37+
bindHook BindHook
38+
39+
// the renderHook for this route
40+
renderHook RenderHook
41+
42+
// the request media type for this route
43+
requestMediaType string
44+
45+
// the response media type for this route
46+
responseMediaType string
3547
}
3648

3749
// GetVerb returns the HTTP verb of the route.
@@ -40,6 +52,30 @@ func (r *Route) GetVerb() string { return r.Method }
4052
// GetPath returns the path of the route.
4153
func (r *Route) GetPath() string { return r.Path }
4254

55+
// GetRequestMediaType returns the media type of the route.
56+
func (r *Route) GetRequestMediaType() string { return r.requestMediaType }
57+
58+
// GetResponseMediaType returns the media type of the route.
59+
func (r *Route) GetResponseMediaType() string { return r.responseMediaType }
60+
61+
// SetRequestMediaType returns the media type of the route.
62+
func (r *Route) SetRequestMediaType(mt string) { r.requestMediaType = mt }
63+
64+
// SetResponseMediaType returns the media type of the route.
65+
func (r *Route) SetResponseMediaType(mt string) { r.responseMediaType = mt }
66+
67+
// GetBindHook returns the bind hook of the route.
68+
func (r *Route) GetBindHook() BindHook { return r.bindHook }
69+
70+
// SetBindHook returns the bind hook of the route.
71+
func (r *Route) SetBindHook(h BindHook) { r.bindHook = h }
72+
73+
// GetRenderHook returns the bind hook of the route.
74+
func (r *Route) GetRenderHook() RenderHook { return r.renderHook }
75+
76+
// SetRenderHook returns the bind hook of the route.
77+
func (r *Route) SetRenderHook(h RenderHook) { r.renderHook = h }
78+
4379
// GetDescription returns the description of the route.
4480
func (r *Route) GetDescription() string { return r.description }
4581

tonic/tonic_test.go

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ import (
99
"testing"
1010
"time"
1111

12+
"github.com/demand-iq/gadgeto/tonic"
1213
"github.com/gin-gonic/gin"
1314
"github.com/loopfz/gadgeto/iffy"
14-
"github.com/loopfz/gadgeto/tonic"
1515
)
1616

1717
var r http.Handler
@@ -35,6 +35,18 @@ func TestMain(m *testing.M) {
3535
g.GET("/query", tonic.Handler(queryHandler, 200))
3636
g.GET("/query-old", tonic.Handler(queryHandlerOld, 200))
3737
g.POST("/body", tonic.Handler(bodyHandler, 200))
38+
g.POST("/bodyYAML", tonic.Handler(bodyHandler, 200, func(r *tonic.Route) {
39+
r.SetBindHook(func(c *gin.Context, i interface{}) error {
40+
if err := c.ShouldBindYAML(i); err != nil {
41+
return fmt.Errorf("error parsing request body: %s", err.Error())
42+
}
43+
return nil
44+
})
45+
r.SetRenderHook(func(c *gin.Context, statusCode int, payload interface{}) {
46+
c.YAML(statusCode, payload)
47+
})
48+
r.SetResponseMediaType("text/yaml")
49+
}))
3850

3951
r = g
4052

@@ -130,6 +142,15 @@ func TestBody(t *testing.T) {
130142
tester.Run()
131143
}
132144

145+
func TestBodyYAML(t *testing.T) {
146+
147+
tester := iffy.NewTester(t, r)
148+
149+
tester.AddCall("body", "POST", "/bodyYAML", `param: foo`).Checkers(iffy.ExpectStatus(200), expectStringInBody("param: foo"))
150+
151+
tester.Run()
152+
}
153+
133154
func errorHandler(c *gin.Context) error {
134155
return errors.New("error")
135156
}
@@ -190,9 +211,9 @@ func queryHandlerOld(c *gin.Context, in *queryInOld) (*queryInOld, error) {
190211
}
191212

192213
type bodyIn struct {
193-
Param string `json:"param" validate:"required"`
194-
ParamOptional string `json:"param-optional"`
195-
ValidatedParamOptional string `json:"param-optional-validated" validate:"eq=|eq=foo|gt=10"`
214+
Param string `json:"param" validate:"required" yaml:"param"`
215+
ParamOptional string `json:"param-optional" yaml:"param-optional"`
216+
ValidatedParamOptional string `json:"param-optional-validated" validate:"eq=|eq=foo|gt=10" yaml:"param-optional-validated"`
196217
}
197218

198219
func bodyHandler(c *gin.Context, in *bodyIn) (*bodyIn, error) {

0 commit comments

Comments
 (0)