Skip to content

Commit

Permalink
Merge pull request #81 from hareekum/get-json-nodes-by-path
Browse files Browse the repository at this point in the history
Template helper to get json objects by path
  • Loading branch information
zhouzhuojie committed Jul 1, 2020
2 parents 68fadf5 + 9001084 commit 48f7b5d
Show file tree
Hide file tree
Showing 24 changed files with 4,645 additions and 7 deletions.
13 changes: 8 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -279,10 +279,12 @@ OpenMock leverages [https://golang.org/pkg/text/template/](https://golang.org/pk
```bash
# Supported functions defined in ./template_helper.go
- jsonPath # doc: https://github.com/antchfx/xpath
- xmlPath # doc: https://github.com/antchfx/xpath
- uuidv5 # uuid v5 sha1 hash
- redisDo # run redis commands. For example {{redisDo "RPUSH" "arr" "hi"}}
-
- jsonPath # doc: https://github.com/antchfx/xpath
- gJsonPath # doc: https://github.com/tidwall/gjson
- xmlPath # doc: https://github.com/antchfx/xpath
- uuidv5 # uuid v5 sha1 hash
- redisDo # run redis commands. For example {{redisDo "RPUSH" "arr" "hi"}}
- ...
# Supported functions inherited from
Expand All @@ -296,6 +298,7 @@ OpenMock leverages [https://golang.org/pkg/text/template/](https://golang.org/pk
# Examples
{{.HTTPHeader.Get "X-Token" | eq "t1234"}}
{{.HTTPBody | jsonPath "user/first_name" | replace "A" "a" | uuidv5 }}
{{.HTTPBody | gJsonPath "users.0.first_name" }}
{{.HTTPBody | xmlPath "node1/node2/node3"}}
```

Expand Down Expand Up @@ -602,7 +605,7 @@ with the `proto.MessageV2` method.

Please note that OpenMock expects the `payload` or `payload_from_file` for a reply_grpc action to be in the json
form of your `Response` protobuf message. The request should be in the `Request` protobuf message format
as it is parsed into json to support JSONPath operations.
as it is parsed into json to support `jsonPath` and `gJsonPath` operations.

Example configuration by directly importing the `github.com/checkr/openmock` package into a wrapper project.
```
Expand Down
12 changes: 12 additions & 0 deletions demo_templates/http.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,18 @@
status_code: 200
body: '{{ .HTTPBody | jsonPath "foo" }}'

- key: json-payload-from-http-body-gJsonPath-example
kind: Behavior
expect:
condition: '{{ .HTTPBody | gJsonPath "context.type" | toString | eq "foo" }}'
http:
method: POST
path: /json_from_body
actions:
- reply_http:
status_code: 200
body: '{{ .HTTPBody | gJsonPath "context.payload" }}'

- key: base64-basicauth-with-env
kind: Behavior
expect:
Expand Down
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ require (
github.com/streadway/amqp v0.0.0-20180806233856-70e15c650864
github.com/stretchr/testify v1.5.1
github.com/teamwork/reload v1.3.0
github.com/tidwall/gjson v1.6.0
github.com/tidwall/pretty v1.0.1 // indirect
github.com/yuin/gopher-lua v0.0.0-20180827083657-b942cacc89fe // indirect
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b
google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63 // indirect
Expand Down
6 changes: 6 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -270,8 +270,14 @@ github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/teamwork/reload v1.3.0 h1:ElBaBhtRwVRxsPRGK1wYugr2knciOXFMZT5ltPpEwAI=
github.com/teamwork/reload v1.3.0/go.mod h1:kHdVPdfdmA+ygkBbigWUeerpy6EK4Kcukx1TNyePXHA=
github.com/tidwall/gjson v1.6.0 h1:9VEQWz6LLMUsUl6PueE49ir4Ka6CzLymOAZDxpFsTDc=
github.com/tidwall/gjson v1.6.0/go.mod h1:P256ACg0Mn+j1RXIDXoss50DeIABTYK1PULOJHhxOls=
github.com/tidwall/match v1.0.1 h1:PnKP62LPNxHKTwvHHZZzdOAOCtsJTjo6dZLCwpKm5xc=
github.com/tidwall/match v1.0.1/go.mod h1:LujAq0jyVjBy028G1WhWfIzbpQfMO8bBZ6Tyb0+pL9E=
github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4=
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
github.com/tidwall/pretty v1.0.1 h1:WE4RBSZ1x6McVVC8S/Md+Qse8YUv6HRObAx6ke00NY8=
github.com/tidwall/pretty v1.0.1/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
Expand Down
33 changes: 33 additions & 0 deletions template_helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"errors"
"reflect"
"regexp"
"strings"
Expand All @@ -13,13 +14,15 @@ import (
"github.com/antchfx/xmlquery"
"github.com/google/uuid"
"github.com/sirupsen/logrus"
"github.com/tidwall/gjson"
)

func genLocalFuncMap(om *OpenMock) template.FuncMap {
return template.FuncMap{
"htmlEscapeString": template.HTMLEscapeString,
"isLastIndex": isLastIndex,
"jsonPath": jsonPath,
"gJsonPath": gJsonPath,
"redisDo": redisDo(om),
"regexFindAllSubmatch": regexFindAllSubmatch,
"regexFindFirstSubmatch": regexFindFirstSubmatch,
Expand Down Expand Up @@ -56,6 +59,36 @@ func jsonPath(expr string, tmpl string) (ret string, err error) {
return "", nil
}

func gJsonPath(expr string, tmpl string) (ret string, err error) {
defer func() {
if r := recover(); r != nil {
err = r.(error)
}
logrus.WithFields(logrus.Fields{
"err": err,
"tmpl": tmpl,
"expr": expr,
}).Debug("running gJsonPath")
}()

if tmpl == "" {
return "", nil
}

if !gjson.Valid(tmpl) {
return "", errors.New("Invalid json")
}

node := gjson.Parse(tmpl).Get(expr)
if node.Exists() {
if node.Type.String() == "String" {
return node.String(), nil
}
return node.Raw, nil
}
return "", nil
}

func xmlPath(expr string, tmpl string) (ret string, err error) {
defer func() {
if r := recover(); r != nil {
Expand Down
56 changes: 56 additions & 0 deletions template_helper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,62 @@ func TestJSONPath(t *testing.T) {
assert.Equal(t, "112879785776", ret)
}

func TestGJsonPath(t *testing.T) {
var tmpl string
var ret string
var err error

tmpl = `{"payload": {"user": {"username": "johnny", "first_name": "John", "valid": true, "id": 7, "profile": null}}}`

ret, err = gJsonPath("payload.user", tmpl)
assert.NoError(t, err)
assert.Equal(t, "{\"username\": \"johnny\", \"first_name\": \"John\", \"valid\": true, \"id\": 7, \"profile\": null}", ret)

ret, err = gJsonPath("payload.user.first_name", tmpl)
assert.NoError(t, err)
assert.Equal(t, "John", ret)

ret, err = gJsonPath("payload.user.valid", tmpl)
assert.NoError(t, err)
assert.Equal(t, "true", ret)

ret, err = gJsonPath("payload.user.id", tmpl)
assert.NoError(t, err)
assert.Equal(t, "7", ret)

ret, err = gJsonPath("payload.user.profile", tmpl)
assert.NoError(t, err)
assert.Equal(t, "null", ret)

tmpl = `{"payload": {"rivers": ["klamath", "merced", "american", "mississippi"]}}`

ret, err = gJsonPath("payload.rivers.#", tmpl)
assert.NoError(t, err)
assert.Equal(t, "4", ret)

ret, err = gJsonPath("payload.rivers.1", tmpl)
assert.NoError(t, err)
assert.Equal(t, "merced", ret)

ret, err = gJsonPath("payload.riv*.2", tmpl)
assert.NoError(t, err)
assert.Equal(t, "american", ret)

ret, err = gJsonPath("payload.r?vers.0", tmpl)
assert.NoError(t, err)
assert.Equal(t, "klamath", ret)

tmpl = `{"payload": {"rivers": [{"name": "klamath", "length": 257}, {"name": "merced", "length": 145}]}}`
ret, err = gJsonPath("payload.rivers.#.length", tmpl)
assert.NoError(t, err)
assert.Equal(t, "[257,145]", ret)

tmpl = `{"payload": {"rivers": [{"name": "klamath", "length": 257}, {"name": "merced", "length": 145}]}}`
ret, err = gJsonPath("payload.rivers.1.name", tmpl)
assert.NoError(t, err)
assert.Equal(t, "merced", ret)
}

func TestHelpers(t *testing.T) {
t.Run("uuid4 helpers", func(t *testing.T) {
raw := `{{ uuidv4 }}`
Expand Down
6 changes: 4 additions & 2 deletions template_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ func TestTemplateRender(t *testing.T) {
raw := `{
"transaction_id": "{{.KafkaPayload | jsonPath "transaction_id"}}",
"first_name": "{{.AMQPPayload | xmlPath "user/first_name"}}",
"middle_name": "{{.HTTPBody | jsonPath "user/middle_name"}}"
"middle_name": "{{.HTTPBody | jsonPath "user/middle_name"}}",
"user": {{.HTTPBody | gJsonPath "user"}}
}`
c := Context{
HTTPBody: `{"user": {"middle_name": "H"}}`,
Expand All @@ -49,7 +50,8 @@ func TestTemplateRender(t *testing.T) {
{
"transaction_id": "t1234",
"first_name": "John",
"middle_name": "H"
"middle_name": "H",
"user": {"middle_name": "H"}
}
`)
})
Expand Down
1 change: 1 addition & 0 deletions vendor/github.com/tidwall/gjson/.travis.yml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 20 additions & 0 deletions vendor/github.com/tidwall/gjson/LICENSE

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 48f7b5d

Please sign in to comment.