Skip to content

Commit 85810ac

Browse files
committed
switch from gorilla/mux to go-chi
Signed-off-by: Lize Cai <[email protected]>
1 parent 13328c6 commit 85810ac

File tree

8 files changed

+141
-41
lines changed

8 files changed

+141
-41
lines changed

Diff for: context/context.go

+22-6
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import (
1717
cloudevents "github.com/cloudevents/sdk-go/v2"
1818
dapr "github.com/dapr/go-sdk/client"
1919
"github.com/dapr/go-sdk/service/common"
20-
"github.com/gorilla/mux"
20+
"github.com/go-chi/chi/v5"
2121
"k8s.io/klog/v2"
2222
agentv3 "skywalking.apache.org/repo/goapi/collect/language/agent/v3"
2323
)
@@ -966,11 +966,9 @@ const (
966966
varsKey contextKey = iota
967967
)
968968

969-
// Vars returns the route variables for the current request, if any.
970-
var (
971-
Vars = mux.Vars
972-
)
973-
969+
// CtxWithVars is just for backward compatibility of VarsFromCtx to the previous implementation using gorilla/mux
970+
// CtxWithVars adds URL Parameters into Context and user can get them by VarsFromCtx
971+
// However, the recommended way to read URL Parameter in go-chi/chi is using URLParamFromCtx
974972
func CtxWithVars(ctx context.Context, vars map[string]string) context.Context {
975973
return context.WithValue(ctx, varsKey, vars)
976974
}
@@ -982,6 +980,24 @@ func VarsFromCtx(ctx context.Context) map[string]string {
982980
return nil
983981
}
984982

983+
// URLParamFromCtx returns the url parameter from a http.Request Context.
984+
func URLParamFromCtx(ctx context.Context, key string) string {
985+
return chi.URLParamFromCtx(ctx, key)
986+
}
987+
988+
// URLParamsFromCtx returns all the url parameters from a http.Request Context.
989+
func URLParamsFromCtx(ctx context.Context) map[string]string {
990+
res := map[string]string{}
991+
if rctx := chi.RouteContext(ctx); rctx != nil {
992+
for k := 0; k < len(rctx.URLParams.Keys); k++ {
993+
key := rctx.URLParams.Keys[k]
994+
val := rctx.URLParams.Values[k]
995+
res[key] = val
996+
}
997+
}
998+
return res
999+
}
1000+
9851001
func IsTracingProviderSkyWalking(ctx RuntimeContext) bool {
9861002
if ctx.HasPluginsTracingCfg() && ctx.GetPluginsTracingCfg().IsEnabled() &&
9871003
ctx.GetPluginsTracingCfg().ProviderName() == TracingProviderSkywalking {

Diff for: context/context_test.go

+9-10
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
package context
22

33
import (
4+
"net/http"
45
"os"
6+
"reflect"
57
"strings"
68
"testing"
7-
"net/http"
8-
"reflect"
99
)
1010

1111
var (
@@ -108,8 +108,8 @@ var (
108108
// TestParseFunctionContext tests and verifies the function that parses the function FunctionContext
109109
func TestParseFunctionContext(t *testing.T) {
110110
_, err := GetRuntimeContext()
111-
if !strings.Contains(err.Error(), "env FUNC_CONTEXT not found") {
112-
t.Fatal("Error parse function context")
111+
if err != nil && !strings.Contains(err.Error(), "env FUNC_CONTEXT not found") {
112+
t.Fatalf("Error parse function context: %s", err.Error())
113113
}
114114

115115
// test `podName`, `podNamespace` field
@@ -295,7 +295,6 @@ func TestParseFunctionContext(t *testing.T) {
295295
}
296296
}
297297

298-
299298
func TestGetVarsFromContext(t *testing.T) {
300299

301300
tests := []struct {
@@ -304,14 +303,14 @@ func TestGetVarsFromContext(t *testing.T) {
304303
vars map[string]string
305304
}{
306305
{
307-
name: "single variable",
306+
name: "single variable",
308307
request: &http.Request{},
309-
vars: map[string]string{"key1": "val1"},
308+
vars: map[string]string{"key1": "val1"},
310309
},
311310
{
312-
name: "multi variables",
311+
name: "multi variables",
313312
request: &http.Request{},
314-
vars: map[string]string{"key1": "val1", "key2": "val2"},
313+
vars: map[string]string{"key1": "val1", "key2": "val2"},
315314
},
316315
}
317316
for _, tt := range tests {
@@ -326,4 +325,4 @@ func TestGetVarsFromContext(t *testing.T) {
326325
})
327326
}
328327

329-
}
328+
}

Diff for: go.mod

+2-1
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ require (
88
github.com/dapr/dapr v1.8.3
99
github.com/dapr/go-sdk v1.5.0
1010
github.com/fatih/structs v1.1.0
11+
github.com/go-chi/chi/v5 v5.0.8
1112
github.com/golang/protobuf v1.5.2
1213
github.com/google/uuid v1.3.0
13-
github.com/gorilla/mux v1.8.0
1414
github.com/pkg/errors v0.9.1
1515
github.com/stretchr/testify v1.7.4
1616
google.golang.org/grpc v1.47.0
@@ -21,6 +21,7 @@ require (
2121
require (
2222
github.com/davecgh/go-spew v1.1.1 // indirect
2323
github.com/go-logr/logr v1.2.3 // indirect
24+
github.com/gorilla/mux v1.8.0 // indirect
2425
github.com/json-iterator/go v1.1.12 // indirect
2526
github.com/kr/pretty v0.3.0 // indirect
2627
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect

Diff for: go.sum

+3
Original file line numberDiff line numberDiff line change
@@ -646,8 +646,11 @@ github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm
646646
github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
647647
github.com/gin-gonic/gin v1.7.7/go.mod h1:axIBovoeJpVj8S3BwE0uPMTeReE4+AfFtqpqaZ1qq1U=
648648
github.com/go-asn1-ber/asn1-ber v1.3.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
649+
github.com/go-chi/chi v4.0.2+incompatible h1:maB6vn6FqCxrpz4FqWdh4+lwpyZIQS7YEAUcHlgXVRs=
649650
github.com/go-chi/chi v4.0.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ=
650651
github.com/go-chi/chi/v5 v5.0.0/go.mod h1:BBug9lr0cqtdAhsu6R4AAdvufI0/XBzAQSsUqJpoZOs=
652+
github.com/go-chi/chi/v5 v5.0.8 h1:lD+NLqFcAi1ovnVZpsnObHGW4xb4J8lNmoYVfECH1Y0=
653+
github.com/go-chi/chi/v5 v5.0.8/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
651654
github.com/go-co-op/gocron v1.9.0/go.mod h1:DbJm9kdgr1sEvWpHCA7dFFs/PGHPMil9/97EXCRPr4k=
652655
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
653656
github.com/go-errors/errors v1.4.0/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=

Diff for: runtime/knative/knative.go

+24-16
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import (
1010

1111
cloudevents "github.com/cloudevents/sdk-go/v2"
1212

13-
"github.com/gorilla/mux"
13+
"github.com/go-chi/chi/v5"
1414
"k8s.io/klog/v2"
1515

1616
ofctx "github.com/OpenFunction/functions-framework-go/context"
@@ -30,7 +30,7 @@ const (
3030
type Runtime struct {
3131
port string
3232
pattern string
33-
handler *mux.Router
33+
handler *chi.Mux
3434
}
3535

3636
func NewKnativeRuntime(port string, pattern string) *Runtime {
@@ -40,7 +40,7 @@ func NewKnativeRuntime(port string, pattern string) *Runtime {
4040
return &Runtime{
4141
port: port,
4242
pattern: pattern,
43-
handler: mux.NewRouter(),
43+
handler: chi.NewRouter(),
4444
}
4545
}
4646

@@ -61,11 +61,10 @@ func (r *Runtime) RegisterOpenFunction(
6161
ctx.InitDaprClientIfNil()
6262
}
6363

64-
// Register the synchronous function (based on Knaitve runtime)
65-
route := r.handler.HandleFunc(rf.GetPath(), func(w http.ResponseWriter, r *http.Request) {
64+
fn := func(w http.ResponseWriter, r *http.Request) {
6665
rm := runtime.NewRuntimeManager(ctx, prePlugins, postPlugins)
6766
// save the Vars into the context
68-
_ctx := ofctx.CtxWithVars(r.Context(), ofctx.Vars(r))
67+
_ctx := ofctx.CtxWithVars(r.Context(), ofctx.URLParamsFromCtx(r.Context()))
6968
rm.FuncContext.SetNativeContext(_ctx)
7069
rm.FuncContext.SetSyncRequest(w, r.WithContext(_ctx))
7170
defer RecoverPanicHTTP(w, "Function panic")
@@ -84,12 +83,17 @@ func (r *Runtime) RegisterOpenFunction(
8483
default:
8584
return
8685
}
87-
})
86+
}
8887

89-
// add methods matcher if provided
9088
methods := rf.GetFunctionMethods()
89+
// Register the synchronous function (based on Knaitve runtime)
9190
if len(methods) > 0 {
92-
route.Methods(methods...)
91+
// add methods matcher if provided
92+
for _, method := range methods {
93+
r.handler.MethodFunc(method, rf.GetPath(), fn)
94+
}
95+
} else {
96+
r.handler.HandleFunc(rf.GetPath(), fn)
9397
}
9498

9599
return nil
@@ -101,20 +105,24 @@ func (r *Runtime) RegisterHTTPFunction(
101105
postPlugins []plugin.Plugin,
102106
rf *functions.RegisteredFunction,
103107
) error {
104-
route := r.handler.HandleFunc(rf.GetPath(), func(w http.ResponseWriter, r *http.Request) {
108+
fn := func(w http.ResponseWriter, r *http.Request) {
105109
rm := runtime.NewRuntimeManager(ctx, prePlugins, postPlugins)
106110
// save the Vars into the context
107-
_ctx := ofctx.CtxWithVars(r.Context(), ofctx.Vars(r))
111+
_ctx := ofctx.CtxWithVars(r.Context(), ofctx.URLParamsFromCtx(r.Context()))
108112
rm.FuncContext.SetNativeContext(_ctx)
109113
rm.FuncContext.SetSyncRequest(w, r.WithContext(_ctx))
110114
defer RecoverPanicHTTP(w, "Function panic")
111115
rm.FunctionRunWrapperWithHooks(rf.GetHTTPFunction())
112-
})
116+
}
113117

114-
// add methods matcher if any
115118
methods := rf.GetFunctionMethods()
116119
if len(methods) > 0 {
117-
route.Methods(methods...)
120+
// add methods matcher if provided
121+
for _, method := range methods {
122+
r.handler.MethodFunc(method, rf.GetPath(), fn)
123+
}
124+
} else {
125+
r.handler.HandleFunc(rf.GetPath(), fn)
118126
}
119127

120128
return nil
@@ -150,8 +158,8 @@ func (r *Runtime) RegisterCloudEventFunction(
150158
// function to extract Vars and add into ctx
151159
withVars := func(next http.Handler) http.Handler {
152160
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
153-
ctx := ofctx.CtxWithVars(r.Context(), ofctx.Vars(r))
154-
next.ServeHTTP(w, r.WithContext(ctx))
161+
_ctx := ofctx.CtxWithVars(r.Context(), ofctx.URLParamsFromCtx(r.Context()))
162+
next.ServeHTTP(w, r.WithContext(_ctx))
155163
})
156164
}
157165
r.handler.Handle(rf.GetPath(), withVars(handleFn))

Diff for: test/declarative/sync-http-variables/README.md

+72
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
# Sync-HTTP-Variables
2+
3+
To run test cases locally
4+
5+
## Run locally
6+
7+
```sh
8+
$ cd test/declarative/sync-http-variables
9+
$ go run main.go http.go
10+
```
11+
12+
## Send request
13+
14+
### HTTP
15+
16+
```sh
17+
$ curl -X POST "http://localhost:8080/hello/openfunction?key1=value1" -d 'hello'
18+
19+
{"hello":"openfunction"}%
20+
```
21+
22+
### CloudEvent
23+
24+
```sh
25+
# binary
26+
$ curl "http://localhost:8080/foo/openfunction" \
27+
-H "Ce-Specversion: 1.0" \
28+
-H "Ce-Type: io.openfunction.samples.helloworld" \
29+
-H "Ce-Source: io.openfunction.samples/helloworldsource" \
30+
-H "Ce-Id: 536808d3-88be-4077-9d7a-a3f162705f79" \
31+
-H "Content-Type: application/json" \
32+
-d '{"data":"hello"}'
33+
34+
I0605 01:38:57.481196 81001 http.go:87] cloudevent - Data: {"hello":"openfunction"}
35+
I0605 01:38:57.481310 81001 plugin-example.go:88] plugin - Result: {"sum":2}
36+
37+
# structured
38+
$ curl "http://localhost:8080/foo/openfunction" \
39+
-H "Content-Type: application/cloudevents+json" \
40+
-d '{"specversion":"1.0","type":"io.openfunction.samples.helloworld","source":"io.openfunction.samples/helloworldsource","id":"536808d3-88be-4077-9d7a-a3f162705f79","data":{"data":"hello"}}'
41+
42+
I0605 01:46:52.336317 81001 http.go:87] cloudevent - Data: {"hello":"openfunction"}
43+
I0605 01:46:52.336342 81001 plugin-example.go:88] plugin - Result: {"sum":2}
44+
```
45+
46+
### OpenFunction
47+
48+
```sh
49+
# HTTP
50+
$ curl -X GET "http://localhost:8080/bar/openfunction?key1=value1" -d '{"data":"hello"}'
51+
52+
{"hello":"openfunction"}%
53+
54+
# CloudEvent
55+
## binary
56+
$ curl "http://localhost:8080/bar/openfunction" \
57+
-H "Ce-Specversion: 1.0" \
58+
-H "Ce-Type: io.openfunction.samples.helloworld" \
59+
-H "Ce-Source: io.openfunction.samples/helloworldsource" \
60+
-H "Ce-Id: 536808d3-88be-4077-9d7a-a3f162705f79" \
61+
-H "Content-Type: application/json" \
62+
-d '{"data":"hello"}'
63+
64+
{"hello":"openfunction"}
65+
66+
## structured
67+
$ curl "http://localhost:8080/bar/openfunction" \
68+
-H "Content-Type: application/cloudevents+json" \
69+
-d '{"specversion":"1.0","type":"io.openfunction.samples.helloworld","source":"io.openfunction.samples/helloworldsource","id":"536808d3-88be-4077-9d7a-a3f162705f79","data":{"data":"hello"}}'
70+
71+
{"hello":"openfunction"}%
72+
```

Diff for: test/declarative/sync-http-variables/http.go

+8-7
Original file line numberDiff line numberDiff line change
@@ -46,16 +46,18 @@ type Message struct {
4646
}
4747

4848
func hello(w http.ResponseWriter, r *http.Request) {
49-
vars := ofctx.VarsFromCtx(r.Context())
49+
name := ofctx.URLParamFromCtx(r.Context(), "name")
5050
response := map[string]string{
51-
"hello": vars["name"],
51+
"hello": name,
5252
}
5353
responseBytes, _ := json.Marshal(response)
5454
w.Header().Set("Content-type", "application/json")
5555
w.Write(responseBytes)
5656
}
5757

5858
func hellov2(w http.ResponseWriter, r *http.Request) {
59+
// keep for backward compatibility, same for example below
60+
// suggest to use ofctx.URLParamFromCtx(...) to get vars
5961
vars := ofctx.VarsFromCtx(r.Context())
6062
response := map[string]string{
6163
"hello": vars["name"],
@@ -66,16 +68,15 @@ func hellov2(w http.ResponseWriter, r *http.Request) {
6668
}
6769

6870
func foo(ctx context.Context, ce cloudevents.Event) error {
69-
vars := ofctx.VarsFromCtx(ctx)
70-
7171
msg := &Message{}
7272
err := json.Unmarshal(ce.Data(), msg)
7373
if err != nil {
7474
return err
7575
}
7676

77+
name := ofctx.URLParamFromCtx(ctx, "name")
7778
response := map[string]string{
78-
msg.Data: vars["name"],
79+
msg.Data: name,
7980
}
8081
responseBytes, _ := json.Marshal(response)
8182
klog.Infof("cloudevent - Data: %s", string(responseBytes))
@@ -100,15 +101,15 @@ func foov2(ctx context.Context, ce cloudevents.Event) error {
100101
}
101102

102103
func bar(ctx ofctx.Context, in []byte) (ofctx.Out, error) {
103-
vars := ofctx.VarsFromCtx(ctx.GetNativeContext())
104104
msg := &Message{}
105105
err := json.Unmarshal(in, msg)
106106
if err != nil {
107107
return ctx.ReturnOnInternalError(), err
108108
}
109109

110+
name := ofctx.URLParamFromCtx(ctx.GetNativeContext(), "name")
110111
response := map[string]string{
111-
msg.Data: vars["name"],
112+
msg.Data: name,
112113
}
113114
responseBytes, _ := json.Marshal(response)
114115
return ctx.ReturnOnSuccess().WithData(responseBytes), nil

Diff for: test/declarative/sync-http-variables/verify-cloudevent-structured.sh

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
url=http://$1
44
while true; do
5-
st=$(curl -s -o /dev/null -w "%{http_code}" "$url" -H "Content-Type: application/cloudevents+json" -d '{"specversion":"1.0","type":"dev.knative.samples.helloworld","source":"dev.knative.samples/helloworldsource","id":"536808d3-88be-4077-9d7a-a3f162705f79","data":{"data":"hello"}}')
5+
st=$(curl -s -o /dev/null -w "%{http_code}" "$url" -H "Content-Type: application/cloudevents+json" -d '{"specversion":"1.0","type":"io.openfunction.samples.helloworld","source":"io.openfunction.samples/helloworldsource","id":"536808d3-88be-4077-9d7a-a3f162705f79","data":{"data":"hello"}}')
66
if [ "$st" -eq 200 ]; then
77
data_result=$(KUBECONFIG=/tmp/e2e-k8s.config kubectl logs --tail=2 -l app="sync-http-variables" -c http | grep Data | awk '{ print $8 }' | yq -P '.' -)
88
plugin_result=$(KUBECONFIG=/tmp/e2e-k8s.config kubectl logs --tail=2 -l app="sync-http-variables" -c http | grep plugin | awk '{ print $8 }' | yq -P '.' -)

0 commit comments

Comments
 (0)