Skip to content

Commit c59e263

Browse files
wwwxuwww-xu
authored andcommitted
tonic: bind keys from gin.Context
1 parent c4f8b2f commit c59e263

5 files changed

Lines changed: 65 additions & 0 deletions

File tree

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ require (
1616
github.com/pires/go-proxyproto v0.6.0
1717
github.com/poy/onpar v1.1.2 // indirect
1818
github.com/ziutek/mymysql v1.5.4 // indirect
19+
golang.org/x/sys v0.3.0 // indirect
1920
)
2021

2122
go 1.13

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,8 @@ golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7w
232232
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
233233
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw=
234234
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
235+
golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ=
236+
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
235237
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
236238
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
237239
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=

tonic/handler.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,11 @@ func Handler(h interface{}, status int, options ...func(*Route)) gin.HandlerFunc
9191
handleError(c, err)
9292
return
9393
}
94+
// Bind context-keys
95+
if err := bind(c, input, ContextTag, extractContext); err != nil {
96+
handleError(c, err)
97+
return
98+
}
9499
// validating query and path inputs if they have a validate tag
95100
initValidator()
96101
args = append(args, input)

tonic/tonic.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ const (
2525
QueryTag = "query"
2626
PathTag = "path"
2727
HeaderTag = "header"
28+
ContextTag = "context"
2829
EnumTag = "enum"
2930
RequiredTag = "required"
3031
DefaultTag = "default"
@@ -345,6 +346,22 @@ func extractHeader(c *gin.Context, tag string) (string, []string, error) {
345346
return name, []string{header}, nil
346347
}
347348

349+
// extractContext is an extractor that operates on the gin.Context
350+
// of a request.
351+
func extractContext(c *gin.Context, tag string) (string, []string, error) {
352+
name, _, _, err := parseTagKey(tag)
353+
if err != nil {
354+
return "", nil, err
355+
}
356+
context := c.GetString(name)
357+
358+
if len(context) > 0 {
359+
return name, []string{context}, nil
360+
}
361+
362+
return name, []string{}, nil
363+
}
364+
348365
// Public signature does not expose "required" and "default" because
349366
// they are deprecated in favor of the "validate" and "default" tags
350367
func parseTagKey(tag string) (string, bool, string, error) {

tonic/tonic_test.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,31 @@ func TestMain(m *testing.M) {
2828
tonic.SetErrorHook(errorHook)
2929

3030
g := gin.Default()
31+
32+
// for context test
33+
g.Use(func(c *gin.Context) {
34+
if c.FullPath() == "/context" {
35+
if val, ok := c.GetQuery("param"); ok {
36+
c.Set("param", val)
37+
}
38+
if val, ok := c.GetQuery("param-optional"); ok {
39+
c.Set("param-optional", val)
40+
}
41+
if val, ok := c.GetQuery("param-optional-validated"); ok {
42+
c.Set("param-optional-validated", val)
43+
}
44+
}
45+
c.Next()
46+
})
47+
3148
g.GET("/simple", tonic.Handler(simpleHandler, 200))
3249
g.GET("/scalar", tonic.Handler(scalarHandler, 200))
3350
g.GET("/error", tonic.Handler(errorHandler, 200))
3451
g.GET("/path/:param", tonic.Handler(pathHandler, 200))
3552
g.GET("/query", tonic.Handler(queryHandler, 200))
3653
g.GET("/query-old", tonic.Handler(queryHandlerOld, 200))
3754
g.POST("/body", tonic.Handler(bodyHandler, 200))
55+
g.GET("/context", tonic.Handler(contextHandler, 200))
3856

3957
r = g
4058

@@ -130,6 +148,17 @@ func TestBody(t *testing.T) {
130148
tester.Run()
131149
}
132150

151+
func TestContext(t *testing.T) {
152+
tester := iffy.NewTester(t, r)
153+
154+
tester.AddCall("context", "GET", "/context?param=foo", ``).Checkers(iffy.ExpectStatus(200), expectString("param", "foo"))
155+
tester.AddCall("context", "GET", "/context", ``).Checkers(iffy.ExpectStatus(400))
156+
tester.AddCall("context", "GET", "/context?param=foo&param-optional=bar", ``).Checkers(iffy.ExpectStatus(200), expectString("param-optional", "bar"))
157+
tester.AddCall("context", "GET", "/context?param=foo&param-optional-validated=foo", ``).Checkers(iffy.ExpectStatus(200), expectString("param-optional-validated", "foo"))
158+
159+
tester.Run()
160+
}
161+
133162
func errorHandler(c *gin.Context) error {
134163
return errors.New("error")
135164
}
@@ -199,6 +228,17 @@ func bodyHandler(c *gin.Context, in *bodyIn) (*bodyIn, error) {
199228
return in, nil
200229
}
201230

231+
type ContextIn struct {
232+
Param string `context:"param" json:"param" validate:"required"`
233+
ParamInt int `context:"param-int" json:"param-int"`
234+
ParamOptional string `context:"param-optional" json:"param-optional"`
235+
ValidatedParamOptional string `context:"param-optional-validated" json:"param-optional-validated" validate:"eq=|eq=foo|gt=10"`
236+
}
237+
238+
func contextHandler(c *gin.Context, in *ContextIn) (*ContextIn, error) {
239+
return in, nil
240+
}
241+
202242
func expectEmptyBody(r *http.Response, body string, obj interface{}) error {
203243
if len(body) != 0 {
204244
return fmt.Errorf("Body '%s' should be empty", body)

0 commit comments

Comments
 (0)