Compare commits

...
16 Commits
6 changed files with 232 additions and 127 deletions
+46 -21
View File
@@ -9,7 +9,9 @@ Ps. It's Hasura friendly.
- [Features](#features)
- [Usage example](#usage-example)
- [Environment variables](#environment-variables)
- [Cache](#cache)
- [Example reader code](#example-reader-code)
- [Tips](#tips)
- [Working with results](#working-with-results)
## Reasoning
@@ -37,6 +39,22 @@ Therefore, I present you the simple client to which you can copy & paste your gr
* `RETRIES_NUMBER` - Number of retries: Default: `1`
* `RETRIES_DELAY` - Delay in retries in milliseconds. Default: `250`
### Cache
You have two options to enable the cache:
* Use `GRAPHQL_CACHE` environment variable which will enable the cache globally. It may be desired if you want to use the cache for all queries.
* Add `gqlcache: true` header for your query which will enable the cache for this query only with `GRAPHQL_CACHE_TTL` TTL.
Example:
```go
headers := map[string]interface{}{
...
"gqlcache": true,
}
```
### Example reader code
@@ -46,32 +64,39 @@ import (
graphql "github.com/lukaszraczylo/go-simple-graphql"
)
headers := map[string]interface{}{
"x-hasura-user-id": 37,
"x-hasura-user-uuid": "bde1962e-b42e-1212-ac10-d43fa27f44a5",
}
variables := map[string]interface{}{
"fileHash": "123deadc0w321",
}
query := `query searchFileKnown($fileHash: String) {
tbl_file_scans(where: {file_hash: {_eq: $fileHash}}) {
racy
violence
virus
func main() {
headers := map[string]interface{}{
"x-hasura-user-id": 37,
"x-hasura-user-uuid": "bde1962e-b42e-1212-ac10-d43fa27f44a5",
}
}`
gql := graphql.NewConnection()
result, err := gql.Query(query, variables, headers)
if err != nil {
fmt.Println("Query error", err)
return
variables := map[string]interface{}{
"fileHash": "123deadc0w321",
}
query := `query searchFileKnown($fileHash: String) {
tbl_file_scans(where: {file_hash: {_eq: $fileHash}}) {
racy
violence
virus
}
}`
gql := graphql.NewConnection()
result, err := gql.Query(query, variables, headers)
if err != nil {
fmt.Println("Query error", err)
return
}
fmt.Println(result)
}
fmt.Println(result)
```
### Tips
* Connection handler ( `gql := graphql.NewConnection()` ) should be created once and reused in the application especially if you run dozens of queries per second. It will allow you also to use cache and http2 to its full potential.
**Result**
```json
+12 -11
View File
@@ -3,29 +3,30 @@ module github.com/lukaszraczylo/go-simple-graphql
go 1.18
require (
github.com/allegro/bigcache/v3 v3.0.2
github.com/allegro/bigcache/v3 v3.1.0
github.com/avast/retry-go v3.0.0+incompatible
github.com/buger/jsonparser v1.1.1
github.com/json-iterator/go v1.1.12
github.com/lukaszraczylo/pandati v0.0.15
github.com/rs/zerolog v1.27.0
github.com/lukaszraczylo/pandati v0.0.18
github.com/rs/zerolog v1.29.0
github.com/sethvargo/go-retry v0.2.4
github.com/stretchr/testify v1.7.1
golang.org/x/net v0.0.0-20220607020251-c690dde0001d
golang.org/x/net v0.7.0
)
require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/imdario/mergo v0.3.13 // indirect
github.com/mattn/go-colorable v0.1.12 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.17 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/tidwall/gjson v1.14.1 // indirect
github.com/tidwall/gjson v1.14.4 // indirect
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.0 // indirect
github.com/wI2L/jsondiff v0.2.0 // indirect
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect
golang.org/x/text v0.3.7 // indirect
github.com/tidwall/pretty v1.2.1 // indirect
github.com/wI2L/jsondiff v0.3.0 // indirect
golang.org/x/sys v0.5.0 // indirect
golang.org/x/text v0.7.0 // indirect
gopkg.in/yaml.v3 v3.0.0 // indirect
)
+27 -54
View File
@@ -1,10 +1,9 @@
github.com/allegro/bigcache/v3 v3.0.2 h1:AKZCw+5eAaVyNTBmI2fgyPVJhHkdWder3O9IrprcQfI=
github.com/allegro/bigcache/v3 v3.0.2/go.mod h1:aPyh7jEvrog9zAwx5N7+JUQX5dZTSGpxF1LAR4dr35I=
github.com/allegro/bigcache/v3 v3.1.0 h1:H2Vp8VOvxcrB91o86fUSVJFqeuz8kpyyB02eH3bSzwk=
github.com/allegro/bigcache/v3 v3.1.0/go.mod h1:aPyh7jEvrog9zAwx5N7+JUQX5dZTSGpxF1LAR4dr35I=
github.com/avast/retry-go v3.0.0+incompatible h1:4SOWQ7Qs+oroOTQOYnAHqelpCO0biHSxpiH9JdtuBj0=
github.com/avast/retry-go v3.0.0+incompatible/go.mod h1:XtSnn+n/sHqQIpZ10K1qAevBhOOCWBLXXy3hyiqqBrY=
github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs=
github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
@@ -15,13 +14,15 @@ github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk=
github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/lukaszraczylo/pandati v0.0.15 h1:1BNtbmhIQbKgs1Gm9WlH3CMms+TgkgxZcU7utHbjloY=
github.com/lukaszraczylo/pandati v0.0.15/go.mod h1:5E0mqlNgdOps6FW2X4tPilr+3B8s9JGWFgA6ZVFixyQ=
github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40=
github.com/lukaszraczylo/pandati v0.0.18 h1:6khtDY6QXkiyh4a3dzHtIzx/9UqUGfHjzKBCA0SIurI=
github.com/lukaszraczylo/pandati v0.0.18/go.mod h1:Aqlc0KH+ssvrscYYbEKMv7n5cFwe+0MjsJbikNz1h60=
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng=
github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@@ -30,61 +31,33 @@ github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjY
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/rs/zerolog v1.26.1 h1:/ihwxqH+4z8UxyI70wM1z9yCvkWcfz/a3mj48k/Zngc=
github.com/rs/zerolog v1.26.1/go.mod h1:/wSSJWX7lVrsOwlbyTRSOJvqRlc+WjWlfes+CiJ+tmc=
github.com/rs/zerolog v1.27.0 h1:1T7qCieN22GVc8S4Q2yuexzBb1EqjbgjSH9RohbMjKs=
github.com/rs/zerolog v1.27.0/go.mod h1:7frBqO0oezxmnO7GF86FY++uy8I0Tk/If5ni1G9Qc0U=
github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/rs/zerolog v1.29.0 h1:Zes4hju04hjbvkVkOhdl2HpZa+0PmVwigmo8XoORE5w=
github.com/rs/zerolog v1.29.0/go.mod h1:NILgTygv/Uej1ra5XxGf82ZFSLk58MFGAUS2o6usyD0=
github.com/sethvargo/go-retry v0.2.4 h1:T+jHEQy/zKJf5s95UkguisicE0zuF9y7+/vgz08Ocec=
github.com/sethvargo/go-retry v0.2.4/go.mod h1:1afjQuvh7s4gflMObvjLPaWgluLLyhA1wmVZ6KLpICw=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/tidwall/gjson v1.14.0 h1:6aeJ0bzojgWLa82gDQHcx3S0Lr/O51I9bJ5nv6JFx5w=
github.com/tidwall/gjson v1.14.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/gjson v1.14.1 h1:iymTbGkQBhveq21bEvAQ81I0LEBork8BFe1CUZXdyuo=
github.com/tidwall/gjson v1.14.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/gjson v1.14.4 h1:uo0p8EbA09J7RQaflQ1aBRffTR7xedD2bcIVSYxLnkM=
github.com/tidwall/gjson v1.14.4/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
github.com/wI2L/jsondiff v0.2.0 h1:dE00WemBa1uCjrzQUUTE/17I6m5qAaN0EMFOg2Ynr/k=
github.com/wI2L/jsondiff v0.2.0/go.mod h1:axTcwtBkY4TsKuV+RgoMhHyHKKFRI6nnjRLi8LLYQnA=
github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20211215165025-cf75a172585e/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220526153639-5463443f8c37 h1:lUkvobShwKsOesNfWWlCS5q7fnbG1MEliIzwu886fn8=
golang.org/x/net v0.0.0-20220526153639-5463443f8c37/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.0.0-20220607020251-c690dde0001d h1:4SFsTMi4UahlKoloni7L4eYzhFRifURQLw+yv0QDCx8=
golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
github.com/wI2L/jsondiff v0.3.0 h1:iTzQ9u/d86GE9RsBzVHX88f2EA1vQUboHwLhSQFc1s4=
github.com/wI2L/jsondiff v0.3.0/go.mod h1:y1IMzNNjlSsk3IUoJdRJO7VRBtzMvRgyo4Vu0LdHpTc=
golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+37 -15
View File
@@ -18,11 +18,13 @@ import (
"net/http"
"os"
"strconv"
"strings"
"time"
"github.com/allegro/bigcache/v3"
bigcache "github.com/allegro/bigcache/v3"
jsoniter "github.com/json-iterator/go"
"github.com/lukaszraczylo/go-simple-graphql/pkg/logging"
retry "github.com/sethvargo/go-retry"
"golang.org/x/net/http2"
)
@@ -38,7 +40,8 @@ type GraphQL struct {
CacheStore *bigcache.BigCache
RetriesEnable bool
RetriesNumber int
RetriesDelay int
RetriesDelay time.Duration
BackoffSetup retry.Backoff
}
func pickGraphqlEndpoint() (graphqlEndpoint string) {
@@ -79,25 +82,37 @@ func setCacheEnabled() bool {
}
func NewConnection() *GraphQL {
endpoint := pickGraphqlEndpoint()
var httpClient *http.Client
if strings.HasPrefix(endpoint, "http://") {
// HTTP/1.1 client
httpClient = &http.Client{}
} else {
// HTTP/2 or HTTPS client
http2Transport := &http2.Transport{
AllowHTTP: true,
}
if strings.HasPrefix(endpoint, "https://") {
http2Transport.TLSClientConfig = &tls.Config{
InsecureSkipVerify: true,
}
}
httpClient = &http.Client{
Transport: http2Transport,
}
}
g := GraphQL{
Endpoint: pickGraphqlEndpoint(),
HttpClient: &http.Client{
Transport: &http2.Transport{
ReadIdleTimeout: 30 * time.Second,
DisableCompression: false,
AllowHTTP: true,
PingTimeout: 10 * time.Second,
TLSClientConfig: &tls.Config{
InsecureSkipVerify: true,
},
},
},
Endpoint: endpoint,
HttpClient: httpClient,
Log: logging.NewLogger(),
Cache: setCacheEnabled(),
CacheStore: setupCache(),
RetriesEnable: false,
RetriesNumber: 1,
RetriesDelay: 250,
BackoffSetup: nil,
}
var err error
retriesEnable, retriesEnableExists := os.LookupEnv("RETRIES_ENABLE")
@@ -115,9 +130,16 @@ func NewConnection() *GraphQL {
}
retriesDelay, retriesDelayExists := os.LookupEnv("RETRIES_DELAY")
if retriesDelayExists {
g.RetriesDelay, err = strconv.Atoi(retriesDelay)
retDel, err := strconv.Atoi(retriesDelay)
if err != nil {
panic("Invalid value for RETRIES_DELAY")
}
g.RetriesDelay = time.Duration(retDel) * time.Millisecond
}
}
g.BackoffSetup = retry.NewExponential(g.RetriesDelay)
g.BackoffSetup = retry.WithMaxRetries(uint64(g.RetriesNumber), g.BackoffSetup)
return &g
}
+25 -22
View File
@@ -5,10 +5,8 @@ import (
"crypto/md5"
"errors"
"fmt"
"io"
"io/ioutil"
"net/http"
"time"
retry "github.com/avast/retry-go"
"github.com/lukaszraczylo/pandati"
@@ -52,6 +50,12 @@ func (g *GraphQL) Query(queryContent string, queryVariables interface{}, queryHe
var queryResult *queryResults
queryHash := fmt.Sprintf("%x", md5.Sum(query))
// If header 'gqlcache' is set to true, we will enforce the cache for the query
if !pandati.IsZero(queryHeaders) && !pandati.IsZero(queryHeaders["gqlcache"]) && queryHeaders["gqlcache"].(bool) {
g.Log.Debug("Forced cache for query", map[string]interface{}{"_query": queryContent, "_headers": queryHeaders})
g.Cache = true
}
if g.Cache {
g.Log.Debug("Checking the cache for the query", map[string]interface{}{"_query": queryHash})
if entry, entryInfo, err := g.CacheStore.GetWithInfo(queryHash); err == nil {
@@ -65,7 +69,12 @@ func (g *GraphQL) Query(queryContent string, queryVariables interface{}, queryHe
}
httpRequest, err := http.NewRequest("POST", g.Endpoint, bytes.NewBuffer(query))
//httpRequest.Header.Add("Content-Type", "application/json")
// httpRequest.Header.Set("Content-Type", "application/json")
if err != nil {
g.Log.Error("Unable to create the request", map[string]interface{}{"_error": err.Error()})
return "", err
}
for header, value := range queryHeaders {
httpRequest.Header.Add(fmt.Sprintf("%v", header), fmt.Sprintf("%v", value))
}
@@ -74,43 +83,37 @@ func (g *GraphQL) Query(queryContent string, queryVariables interface{}, queryHe
err = retry.Do(
func() error {
g.Log.Debug("Sending the query")
httpResponse, err = g.HttpClient.Do(httpRequest)
if err != nil {
g.Log.Error("Unable to send the query", map[string]interface{}{"_error": err.Error()})
g.Log.Debug("Unable to send the query RETRY", map[string]interface{}{"_error": err.Error()})
return err
}
if httpResponse.StatusCode <= 200 && httpResponse.StatusCode >= 204 {
return errors.New(fmt.Sprintf("%v", httpResponse.StatusCode))
}
defer io.Copy(ioutil.Discard, httpResponse.Body)
defer httpResponse.Body.Close()
if httpResponse.StatusCode <= 200 && httpResponse.StatusCode >= 204 {
return err
}
body, err = ioutil.ReadAll(httpResponse.Body)
if err != nil {
g.Log.Critical("Unable to read the response", map[string]interface{}{"_error": err.Error()})
return errors.New(fmt.Sprintf("body parsing %v", httpResponse.StatusCode))
g.Log.Debug("Unable to read the response", map[string]interface{}{"_error": err.Error()})
return err
}
err = json.Unmarshal(body, &queryResult)
if err != nil {
g.Log.Error("Unable to unmarshal the query", map[string]interface{}{"_error": err.Error()})
return errors.New(fmt.Sprintf("body unmarshal %v", httpResponse.StatusCode))
g.Log.Debug("Unable to unmarshal the query", map[string]interface{}{"_error": err.Error()})
return err
}
return nil
},
retry.Attempts(uint(g.RetriesNumber)),
retry.OnRetry(
func(n uint, err error) {
g.Log.Debug("Retrying the query", map[string]interface{}{"_attempt": n, "_error": err.Error()})
time.Sleep(time.Duration(g.RetriesDelay) * time.Millisecond)
},
),
)
if !pandati.IsZero(queryResult.Errors) || err != nil {
if !pandati.IsZero(queryResult.Errors) {
g.Log.Error("Query returned error", map[string]interface{}{"_query": queryContent, "_variables": queryVariables, "_error": fmt.Sprintf("%v", queryResult.Errors), "_response_code": httpResponse.StatusCode})
return "", fmt.Errorf("%v", queryResult.Errors[0].Message)
return "", fmt.Errorf("%v", queryResult.Errors)
}
if pandati.IsZero(queryResult.Data) {
+85 -4
View File
@@ -73,7 +73,25 @@ func (suite *TestSuite) Test_GraphQL_Query() {
}{
{
name: "Valid query, no cache",
endpoint: "https://hasura.local/v1/graphql",
endpoint: "https://telegram-bot.app/v1/graphql",
isLocal: true,
cache_enabled: false,
args: args{
queryContent: `query packages_prices {
sub_group_packages_aggregate(where: {enabled: {_eq: true}}) {
aggregate {
count
}
}
}`,
queryVariables: nil,
},
wantResult: `{"sub_group_packages_aggregate":{"aggregate":{"count":4}}}`,
wantErr: false,
},
{
name: "Valid query, no cache #2",
endpoint: "https://telegram-bot.app/v1/graphql",
isLocal: true,
cache_enabled: false,
args: args{
@@ -91,7 +109,7 @@ func (suite *TestSuite) Test_GraphQL_Query() {
},
{
name: "Valid query, with cache empty",
endpoint: "https://hasura.local/v1/graphql",
endpoint: "https://telegram-bot.app/v1/graphql",
isLocal: true,
cache_enabled: true,
args: args{
@@ -107,9 +125,72 @@ func (suite *TestSuite) Test_GraphQL_Query() {
wantResult: `{"sub_group_packages_aggregate":{"aggregate":{"count":4}}}`,
wantErr: false,
},
{
name: "Valid query, with cache per query empty",
endpoint: "https://telegram-bot.app/v1/graphql",
isLocal: true,
cache_enabled: false,
args: args{
queryContent: `query packages_prices_no_inlinecache {
sub_group_packages_aggregate(where: {enabled: {_eq: true}}) {
aggregate {
count
}
}
}`,
queryVariables: nil,
queryHeaders: map[string]interface{}{
"gqlcache": false,
},
},
wantResult: `{"sub_group_packages_aggregate":{"aggregate":{"count":4}}}`,
wantErr: false,
},
{
name: "Valid query, with cache per query",
endpoint: "https://telegram-bot.app/v1/graphql",
isLocal: true,
cache_enabled: false,
args: args{
queryContent: `query packages_prices_inlinecache {
sub_group_packages_aggregate(where: {enabled: {_eq: true}}) {
aggregate {
count
}
}
}`,
queryVariables: nil,
queryHeaders: map[string]interface{}{
"gqlcache": true,
},
},
wantResult: `{"sub_group_packages_aggregate":{"aggregate":{"count":4}}}`,
wantErr: false,
},
{
name: "Valid query, with cache per query [verify]",
endpoint: "https://telegram-bot.app/v1/graphql",
isLocal: true,
cache_enabled: false,
args: args{
queryContent: `query packages_prices_inlinecache {
sub_group_packages_aggregate(where: {enabled: {_eq: true}}) {
aggregate {
count
}
}
}`,
queryVariables: nil,
queryHeaders: map[string]interface{}{
"gqlcache": true,
},
},
wantResult: `{"sub_group_packages_aggregate":{"aggregate":{"count":4}}}`,
wantErr: false,
},
{
name: "Valid query, with cache filled",
endpoint: "https://hasura.local/v1/graphql",
endpoint: "https://telegram-bot.app/v1/graphql",
isLocal: true,
cache_enabled: true,
args: args{
@@ -127,7 +208,7 @@ func (suite *TestSuite) Test_GraphQL_Query() {
},
{
name: "Invalid query",
endpoint: "https://hasura.local/v1/graphql",
endpoint: "https://telegram-bot.app/v1/graphql",
isLocal: true,
args: args{
queryContent: `query packages_pricez {