mirror of
https://github.com/lukaszraczylo/go-simple-graphql.git
synced 2026-10-13 00:48:37 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a5c4643a5e
|
||
|
|
42e1afbf77
|
||
|
|
9e8df7e297
|
||
|
|
405d159eb9
|
||
|
|
b3e594fc4f
|
||
|
|
32d9e0bd80
|
||
|
|
e706b07488
|
||
|
|
32091fc8cd
|
||
|
|
edc695fe2b
|
||
|
|
bd0c5ec373
|
||
|
|
952749d7ff
|
||
|
|
277ef21263
|
||
|
|
4980aeb28a
|
||
|
|
91f65ebd46
|
||
|
|
d5655ae2fa
|
||
|
|
9b65ba069f
|
||
|
|
feed2f36c2
|
||
|
|
966d9ccd0a
|
||
|
|
3232498e94
|
||
|
|
3cda8e267b
|
||
|
|
1393f4d7cf
|
||
|
|
d4328fdbb7
|
||
|
|
4ac9f132a2
|
||
|
|
fb04e68b8d
|
||
|
|
40652c3fdd
|
||
|
|
f360a5cf7e
|
||
|
|
2b09da7685
|
||
|
|
aac6ca113d
|
||
|
|
c8ed2290b4
|
||
|
|
d1406eeac8
|
||
|
|
ea7ec683ef
|
+2
-1
@@ -1,3 +1,4 @@
|
|||||||
*.out
|
*.out
|
||||||
*.test
|
*.test
|
||||||
coverage.txt
|
coverage.txt
|
||||||
|
*.DS_Store
|
||||||
@@ -22,4 +22,11 @@ all: test-packages test
|
|||||||
|
|
||||||
.PHONY: update
|
.PHONY: update
|
||||||
update: ## update dependencies
|
update: ## update dependencies
|
||||||
@go get -u -v ./...
|
@go get -u -v ./...
|
||||||
|
|
||||||
|
sonar:
|
||||||
|
sonar-scanner \
|
||||||
|
-Dsonar.projectKey=golang-simple-graphql \
|
||||||
|
-Dsonar.sources=. \
|
||||||
|
-Dsonar.host.url=http://localhost:9000 \
|
||||||
|
-Dsonar.login=555ba78b315faa07b3231a3be0f3cbb24ab33814
|
||||||
@@ -9,13 +9,15 @@ Ps. It's Hasura friendly.
|
|||||||
- [Features](#features)
|
- [Features](#features)
|
||||||
- [Usage example](#usage-example)
|
- [Usage example](#usage-example)
|
||||||
- [Environment variables](#environment-variables)
|
- [Environment variables](#environment-variables)
|
||||||
|
- [Cache](#cache)
|
||||||
- [Example reader code](#example-reader-code)
|
- [Example reader code](#example-reader-code)
|
||||||
|
- [Tips](#tips)
|
||||||
- [Working with results](#working-with-results)
|
- [Working with results](#working-with-results)
|
||||||
|
|
||||||
## Reasoning
|
## Reasoning
|
||||||
|
|
||||||
I've tried to run few graphQL clients with hasura, all of them required conversion of the data into
|
I've tried to run a few GraphQL clients with Hasura, all of them required conversion of the data into
|
||||||
the appropriate structures, causing issues with non-existing types ( thanks to Hasura ), for example `bigint` which was difficult to export.
|
the appropriate structures, causing issues with non-existing types ( thanks to Hasura ), for example, `bigint` which was difficult to export.
|
||||||
Therefore, I present you the simple client to which you can copy & paste your graphQL query, variables and you are good to go.
|
Therefore, I present you the simple client to which you can copy & paste your graphQL query, variables and you are good to go.
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
@@ -33,6 +35,25 @@ Therefore, I present you the simple client to which you can copy & paste your gr
|
|||||||
* `GRAPHQL_CACHE` - Should the query cache be enabled? Default: `false`
|
* `GRAPHQL_CACHE` - Should the query cache be enabled? Default: `false`
|
||||||
* `GRAPHQL_CACHE_TTL` - Cache TTL in seconds for SELECT type of queries. Default: `5`
|
* `GRAPHQL_CACHE_TTL` - Cache TTL in seconds for SELECT type of queries. Default: `5`
|
||||||
* `LOG_LEVEL` - Logging level. Default: `info`
|
* `LOG_LEVEL` - Logging level. Default: `info`
|
||||||
|
* `RETRIES_ENABLE` - Should retries be enabled? Default: `false`
|
||||||
|
* `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
|
### Example reader code
|
||||||
|
|
||||||
@@ -40,35 +61,42 @@ Therefore, I present you the simple client to which you can copy & paste your gr
|
|||||||
```go
|
```go
|
||||||
import (
|
import (
|
||||||
fmt
|
fmt
|
||||||
gql "github.com/lukaszraczylo/go-simple-graphql"
|
graphql "github.com/lukaszraczylo/go-simple-graphql"
|
||||||
)
|
)
|
||||||
|
|
||||||
headers := map[string]interface{}{
|
func main() {
|
||||||
"x-hasura-user-id": 37,
|
headers := map[string]interface{}{
|
||||||
"x-hasura-user-uuid": "bde3262e-b42e-4151-ac10-d43f0bef44a5",
|
"x-hasura-user-id": 37,
|
||||||
}
|
"x-hasura-user-uuid": "bde1962e-b42e-1212-ac10-d43fa27f44a5",
|
||||||
|
|
||||||
variables := map[string]interface{}{
|
|
||||||
"fileHash": "123deadc0w321",
|
|
||||||
}
|
|
||||||
var query = `query searchFileKnown($fileHash: String) {
|
|
||||||
tbl_file_scans(where: {file_hash: {_eq: $fileHash}}) {
|
|
||||||
porn
|
|
||||||
racy
|
|
||||||
violence
|
|
||||||
virus
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
graphql := NewConnection()
|
variables := map[string]interface{}{
|
||||||
result, err := graphql.Query(query, variables, nil)
|
"fileHash": "123deadc0w321",
|
||||||
if err != nil {
|
}
|
||||||
fmt.Println("Query error", err)
|
|
||||||
return
|
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**
|
**Result**
|
||||||
|
|
||||||
```json
|
```json
|
||||||
@@ -77,10 +105,10 @@ fmt.Println(result)
|
|||||||
|
|
||||||
## Working with results
|
## Working with results
|
||||||
|
|
||||||
I'm using an amazing library [tidwall/gjson](https://github.com/tidwall/gjson) to parse the results and extract information required in further steps and I strongly recommend this approach as the easiest and close to painless.
|
I'm using an amazing library [tidwall/gjson](https://github.com/tidwall/gjson) to parse the results and extract the information required in further steps and I strongly recommend this approach as the easiest and close to painless, for example:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
result = gjson.Get(result, "tbl_user_group_admins.0.is_admin").Bool()
|
result := gjson.Get(result, "tbl_user_group_admins.0.is_admin").Bool()
|
||||||
if result {
|
if result {
|
||||||
fmt.Println("User is an admin")
|
fmt.Println("User is an admin")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,25 +1,32 @@
|
|||||||
module github.com/lukaszraczylo/go-simple-graphql
|
module github.com/lukaszraczylo/go-simple-graphql
|
||||||
|
|
||||||
go 1.17
|
go 1.20
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/allegro/bigcache/v3 v3.0.1
|
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/buger/jsonparser v1.1.1
|
||||||
github.com/json-iterator/go v1.1.12
|
github.com/json-iterator/go v1.1.12
|
||||||
github.com/lukaszraczylo/pandati v0.0.10
|
github.com/lukaszraczylo/pandati v0.0.20
|
||||||
github.com/rs/zerolog v1.26.0
|
github.com/rs/zerolog v1.29.0
|
||||||
github.com/stretchr/testify v1.7.0
|
github.com/sethvargo/go-retry v0.2.4
|
||||||
golang.org/x/net v0.0.0-20211201190559-0a0e4e1bb54c
|
github.com/stretchr/testify v1.7.1
|
||||||
|
golang.org/x/net v0.8.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/imdario/mergo v0.3.12 // indirect
|
github.com/imdario/mergo v0.3.15 // indirect
|
||||||
github.com/kr/pretty v0.1.0 // indirect
|
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||||
|
github.com/mattn/go-isatty v0.0.18 // indirect
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
golang.org/x/text v0.3.7 // indirect
|
github.com/tidwall/gjson v1.14.4 // indirect
|
||||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
|
github.com/tidwall/match v1.1.1 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect
|
github.com/tidwall/pretty v1.2.1 // indirect
|
||||||
|
github.com/wI2L/jsondiff v0.3.0 // indirect
|
||||||
|
golang.org/x/sys v0.6.0 // indirect
|
||||||
|
golang.org/x/text v0.8.0 // indirect
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,24 +1,30 @@
|
|||||||
github.com/allegro/bigcache/v3 v3.0.1 h1:Q4Xl3chywXuJNOw7NV+MeySd3zGQDj4KCpkCg0te8mc=
|
github.com/allegro/bigcache/v3 v3.1.0 h1:H2Vp8VOvxcrB91o86fUSVJFqeuz8kpyyB02eH3bSzwk=
|
||||||
github.com/allegro/bigcache/v3 v3.0.1/go.mod h1:aPyh7jEvrog9zAwx5N7+JUQX5dZTSGpxF1LAR4dr35I=
|
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 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs=
|
||||||
github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
|
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.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
|
github.com/imdario/mergo v0.3.15 h1:M8XP7IuFNsqUx6VPK2P9OSmsYsI/YFaGil0uD21V3dM=
|
||||||
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
|
github.com/imdario/mergo v0.3.15/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY=
|
||||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
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/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
github.com/lukaszraczylo/pandati v0.0.18 h1:6khtDY6QXkiyh4a3dzHtIzx/9UqUGfHjzKBCA0SIurI=
|
||||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
github.com/lukaszraczylo/pandati v0.0.18/go.mod h1:Aqlc0KH+ssvrscYYbEKMv7n5cFwe+0MjsJbikNz1h60=
|
||||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
github.com/lukaszraczylo/pandati v0.0.20 h1:LqF7CS3z9Zi04KwEY8wd/YUpfWKSwi0nc7pagKQLXHc=
|
||||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
github.com/lukaszraczylo/pandati v0.0.20/go.mod h1:ZegK9ll9UebKV1uNMF73qdLb43G/O4CSOdPglu6NniQ=
|
||||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
|
||||||
github.com/lukaszraczylo/pandati v0.0.10 h1:ZXmLjxb/UYRBVyAKwXmUcJgZ2FYNwGY4YDJsQQMYAXI=
|
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||||
github.com/lukaszraczylo/pandati v0.0.10/go.mod h1:1lE/x4X4LfO1yerAQoiR7AVb/wIabH/zITDGnqTdyH8=
|
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/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||||
|
github.com/mattn/go-isatty v0.0.18 h1:DOKFKCQ7FNG2L1rbrmstDN4QVRdS89Nkh85u68Uwp98=
|
||||||
|
github.com/mattn/go-isatty v0.0.18/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
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 h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
@@ -27,44 +33,35 @@ 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/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 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
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/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
||||||
github.com/rs/zerolog v1.26.0 h1:ORM4ibhEZeTeQlCojCK2kPz1ogAY4bGs4tD+SaAdGaE=
|
github.com/rs/zerolog v1.29.0 h1:Zes4hju04hjbvkVkOhdl2HpZa+0PmVwigmo8XoORE5w=
|
||||||
github.com/rs/zerolog v1.26.0/go.mod h1:yBiM87lvSqX8h0Ww4sdzNSkVYZ8dL2xjZJG1lAuGZEo=
|
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/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.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
|
||||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
github.com/tidwall/gjson v1.14.4 h1:uo0p8EbA09J7RQaflQ1aBRffTR7xedD2bcIVSYxLnkM=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
github.com/tidwall/gjson v1.14.4/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
|
||||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
|
||||||
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
||||||
golang.org/x/net v0.0.0-20211201190559-0a0e4e1bb54c h1:WtYZ93XtWSO5KlOMgPZu7hXY9WhMZpprvlm5VwvAl8c=
|
github.com/wI2L/jsondiff v0.3.0 h1:iTzQ9u/d86GE9RsBzVHX88f2EA1vQUboHwLhSQFc1s4=
|
||||||
golang.org/x/net v0.0.0-20211201190559-0a0e4e1bb54c/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
github.com/wI2L/jsondiff v0.3.0/go.mod h1:y1IMzNNjlSsk3IUoJdRJO7VRBtzMvRgyo4Vu0LdHpTc=
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
|
||||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
|
||||||
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
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=
|
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
|
||||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
|
||||||
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
|
|
||||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
|||||||
@@ -15,15 +15,16 @@ package gql
|
|||||||
import (
|
import (
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/allegro/bigcache/v3"
|
bigcache "github.com/allegro/bigcache/v3"
|
||||||
jsoniter "github.com/json-iterator/go"
|
jsoniter "github.com/json-iterator/go"
|
||||||
"github.com/lukaszraczylo/go-simple-graphql/pkg/logging"
|
"github.com/lukaszraczylo/go-simple-graphql/pkg/logging"
|
||||||
|
retry "github.com/sethvargo/go-retry"
|
||||||
"golang.org/x/net/http2"
|
"golang.org/x/net/http2"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -32,11 +33,15 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type GraphQL struct {
|
type GraphQL struct {
|
||||||
Endpoint string
|
BackoffSetup retry.Backoff
|
||||||
HttpClient *http.Client
|
HttpClient *http.Client
|
||||||
Log *logging.LogConfig
|
Log *logging.LogConfig
|
||||||
Cache bool // Enable caching for read queries
|
CacheStore *bigcache.BigCache
|
||||||
CacheStore *bigcache.BigCache
|
Endpoint string
|
||||||
|
RetriesNumber int
|
||||||
|
RetriesDelay time.Duration
|
||||||
|
Cache bool
|
||||||
|
RetriesEnable bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func pickGraphqlEndpoint() (graphqlEndpoint string) {
|
func pickGraphqlEndpoint() (graphqlEndpoint string) {
|
||||||
@@ -77,22 +82,65 @@ func setCacheEnabled() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewConnection() *GraphQL {
|
func NewConnection() *GraphQL {
|
||||||
return &GraphQL{
|
|
||||||
Endpoint: pickGraphqlEndpoint(),
|
endpoint := pickGraphqlEndpoint()
|
||||||
HttpClient: &http.Client{
|
var httpClient *http.Client
|
||||||
Transport: &http2.Transport{
|
if strings.HasPrefix(endpoint, "http://") {
|
||||||
DisableCompression: false,
|
// HTTP/1.1 client
|
||||||
AllowHTTP: true,
|
httpClient = &http.Client{}
|
||||||
PingTimeout: 5 * time.Second,
|
} else {
|
||||||
DialTLS: func(network, addr string, cfg *tls.Config) (net.Conn, error) {
|
// HTTP/2 or HTTPS client
|
||||||
return net.Dial(network, addr)
|
http2Transport := &http2.Transport{
|
||||||
},
|
AllowHTTP: true,
|
||||||
},
|
}
|
||||||
},
|
if strings.HasPrefix(endpoint, "https://") {
|
||||||
Log: logging.NewLogger(),
|
http2Transport.TLSClientConfig = &tls.Config{
|
||||||
Cache: setCacheEnabled(),
|
InsecureSkipVerify: true,
|
||||||
CacheStore: setupCache(),
|
}
|
||||||
|
}
|
||||||
|
httpClient = &http.Client{
|
||||||
|
Transport: http2Transport,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
g := GraphQL{
|
||||||
|
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")
|
||||||
|
if retriesEnableExists {
|
||||||
|
g.RetriesEnable, err = strconv.ParseBool(retriesEnable)
|
||||||
|
if err != nil {
|
||||||
|
panic("Invalid value for RETRIES_ENABLE")
|
||||||
|
}
|
||||||
|
retriesNumber, retriesNumberExists := os.LookupEnv("RETRIES_NUMBER")
|
||||||
|
if retriesNumberExists {
|
||||||
|
g.RetriesNumber, err = strconv.Atoi(retriesNumber)
|
||||||
|
if err != nil {
|
||||||
|
panic("Invalid value for RETRIES_NUMBER")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
retriesDelay, retriesDelayExists := os.LookupEnv("RETRIES_DELAY")
|
||||||
|
if retriesDelayExists {
|
||||||
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
func setupCache() *bigcache.BigCache {
|
func setupCache() *bigcache.BigCache {
|
||||||
|
|||||||
+1
-1
@@ -35,9 +35,9 @@ func (suite *TestSuite) TestNewConnection() {
|
|||||||
endpoint string
|
endpoint string
|
||||||
}
|
}
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
|
want *GraphQL
|
||||||
name string
|
name string
|
||||||
args args
|
args args
|
||||||
want *GraphQL
|
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "New connection: Env variable endpoint",
|
name: "New connection: Env variable endpoint",
|
||||||
|
|||||||
@@ -82,9 +82,9 @@ func (suite *LoggingTestSuite) TestLogConfig_AllHandlers() {
|
|||||||
wantLevel string
|
wantLevel string
|
||||||
wantMessage string
|
wantMessage string
|
||||||
envMinLogLevel string
|
envMinLogLevel string
|
||||||
|
loggerType string
|
||||||
stdOutExpect bool
|
stdOutExpect bool
|
||||||
stdErrExpect bool
|
stdErrExpect bool
|
||||||
loggerType string
|
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "Test log: Error",
|
name: "Test log: Error",
|
||||||
@@ -232,21 +232,21 @@ func (suite *LoggingTestSuite) TestLogConfig_AllHandlers() {
|
|||||||
|
|
||||||
func (suite *LoggingTestSuite) TestFullMessage() {
|
func (suite *LoggingTestSuite) TestFullMessage() {
|
||||||
type args struct {
|
type args struct {
|
||||||
message string
|
|
||||||
extraFields map[string]interface{}
|
extraFields map[string]interface{}
|
||||||
|
message string
|
||||||
}
|
}
|
||||||
extraFields := make(map[string]interface{})
|
extraFields := make(map[string]interface{})
|
||||||
extraFields["_full_message"] = "full message"
|
extraFields["_full_message"] = "full message"
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
|
||||||
args args
|
args args
|
||||||
|
name string
|
||||||
wantLevel string
|
wantLevel string
|
||||||
wantMessage string
|
wantMessage string
|
||||||
envMinLogLevel string
|
envMinLogLevel string
|
||||||
|
loggerType string
|
||||||
stdOutExpect bool
|
stdOutExpect bool
|
||||||
stdErrExpect bool
|
stdErrExpect bool
|
||||||
loggerType string
|
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "Test log: Error",
|
name: "Test log: Error",
|
||||||
|
|||||||
@@ -5,16 +5,16 @@ import (
|
|||||||
"crypto/md5"
|
"crypto/md5"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
retry "github.com/avast/retry-go"
|
||||||
"github.com/lukaszraczylo/pandati"
|
"github.com/lukaszraczylo/pandati"
|
||||||
)
|
)
|
||||||
|
|
||||||
type requestBase struct {
|
type requestBase struct {
|
||||||
Query string `json:"query"`
|
|
||||||
Variables interface{} `json:"variables"`
|
Variables interface{} `json:"variables"`
|
||||||
|
Query string `json:"query"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type queryResults struct {
|
type queryResults struct {
|
||||||
@@ -50,55 +50,80 @@ func (g *GraphQL) Query(queryContent string, queryVariables interface{}, queryHe
|
|||||||
var queryResult *queryResults
|
var queryResult *queryResults
|
||||||
queryHash := fmt.Sprintf("%x", md5.Sum(query))
|
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 {
|
if g.Cache {
|
||||||
g.Log.Debug("Checking the cache for the query", map[string]interface{}{"_query": queryHash})
|
g.Log.Debug("Checking the cache for the query", map[string]interface{}{"_query": queryHash})
|
||||||
if entry, err := g.CacheStore.Get(queryHash); err == nil {
|
if entry, entryInfo, err := g.CacheStore.GetWithInfo(queryHash); err == nil {
|
||||||
g.Log.Debug("Found the query in the cache", map[string]interface{}{"_query": queryHash})
|
g.Log.Debug("Found the query in the cache", map[string]interface{}{"_query": queryHash})
|
||||||
return string(entry), nil
|
if pandati.IsZero(entryInfo.EntryStatus) {
|
||||||
|
return string(entry), nil
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
g.Log.Debug("Unable to find the query in the cache", map[string]interface{}{"_query": queryHash, "_error": err.Error()})
|
g.Log.Debug("Unable to find the query in the cache", map[string]interface{}{"_query": queryHash, "_error": err.Error()})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
httpRequest, err := http.NewRequest("POST", g.Endpoint, bytes.NewBuffer(query))
|
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 {
|
for header, value := range queryHeaders {
|
||||||
httpRequest.Header.Add(fmt.Sprintf("%v", header), fmt.Sprintf("%v", value))
|
httpRequest.Header.Add(fmt.Sprintf("%v", header), fmt.Sprintf("%v", value))
|
||||||
}
|
}
|
||||||
|
|
||||||
httpResponse, err := g.HttpClient.Do(httpRequest)
|
var httpResponse *http.Response
|
||||||
if err != nil {
|
|
||||||
g.Log.Error("Unable to send the query", map[string]interface{}{"_error": err.Error()})
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
defer io.Copy(ioutil.Discard, httpResponse.Body)
|
|
||||||
defer httpResponse.Body.Close()
|
|
||||||
|
|
||||||
body, err = ioutil.ReadAll(httpResponse.Body)
|
err = retry.Do(
|
||||||
if err != nil {
|
func() error {
|
||||||
g.Log.Critical("Unable to read the response", map[string]interface{}{"_error": err.Error()})
|
g.Log.Debug("Sending the query")
|
||||||
return "", err
|
httpResponse, err = g.HttpClient.Do(httpRequest)
|
||||||
}
|
|
||||||
|
|
||||||
err = json.Unmarshal(body, &queryResult)
|
if err != nil {
|
||||||
if err != nil {
|
g.Log.Debug("Unable to send the query RETRY", map[string]interface{}{"_error": err.Error()})
|
||||||
g.Log.Error("Unable to unmarshal the query", map[string]interface{}{"_error": err.Error()})
|
return err
|
||||||
return "", err
|
}
|
||||||
}
|
defer httpResponse.Body.Close()
|
||||||
|
|
||||||
|
if httpResponse.StatusCode <= 200 && httpResponse.StatusCode >= 204 {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
body, err = ioutil.ReadAll(httpResponse.Body)
|
||||||
|
if err != nil {
|
||||||
|
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.Debug("Unable to unmarshal the query", map[string]interface{}{"_error": err.Error()})
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
if !pandati.IsZero(queryResult.Errors) {
|
if !pandati.IsZero(queryResult.Errors) {
|
||||||
g.Log.Error("Query returned error", map[string]interface{}{"_query": queryContent, "_variables": queryVariables, "_error": fmt.Sprintf("%v", 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) {
|
if pandati.IsZero(queryResult.Data) {
|
||||||
g.Log.Error("Query returned no data", map[string]interface{}{"_query": queryContent, "_variables": queryVariables})
|
g.Log.Error("Query returned no data", map[string]interface{}{"_query": queryContent, "_variables": queryVariables, "_response_code": httpResponse.StatusCode})
|
||||||
return "", errors.New("Query returned no data")
|
return "", errors.New("Query returned no data")
|
||||||
}
|
}
|
||||||
|
|
||||||
responseContent, err = json.MarshalToString(queryResult.Data)
|
responseContent, err = json.MarshalToString(queryResult.Data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
g.Log.Error("Invalid data result", map[string]interface{}{"_query": queryContent, "_variables": queryVariables, "_result": responseContent})
|
g.Log.Error("Invalid data result", map[string]interface{}{"_query": queryContent, "_variables": queryVariables, "_result": responseContent, "_response_code": httpResponse.StatusCode})
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+158
-27
@@ -2,6 +2,7 @@ package gql
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
@@ -10,8 +11,8 @@ import (
|
|||||||
func (suite *TestSuite) Test_GraphQL_queryBuilder() {
|
func (suite *TestSuite) Test_GraphQL_queryBuilder() {
|
||||||
|
|
||||||
type args struct {
|
type args struct {
|
||||||
queryContent string
|
|
||||||
queryVariables interface{}
|
queryVariables interface{}
|
||||||
|
queryContent string
|
||||||
}
|
}
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
@@ -25,7 +26,7 @@ func (suite *TestSuite) Test_GraphQL_queryBuilder() {
|
|||||||
queryContent: `query listUserBots { tbl_bots { bot_name } }`,
|
queryContent: `query listUserBots { tbl_bots { bot_name } }`,
|
||||||
queryVariables: nil,
|
queryVariables: nil,
|
||||||
},
|
},
|
||||||
want: []byte(`{"query":"query listUserBots { tbl_bots { bot_name } }","variables":null}`),
|
want: []byte(`{"variables":null,"query":"query listUserBots { tbl_bots { bot_name } }"}`),
|
||||||
wantErr: false,
|
wantErr: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -34,7 +35,7 @@ func (suite *TestSuite) Test_GraphQL_queryBuilder() {
|
|||||||
queryContent: `query listUserBots { tbl_bots { bot_name } }`,
|
queryContent: `query listUserBots { tbl_bots { bot_name } }`,
|
||||||
queryVariables: map[string]interface{}{"user_id": 1},
|
queryVariables: map[string]interface{}{"user_id": 1},
|
||||||
},
|
},
|
||||||
want: []byte(`{"query":"query listUserBots { tbl_bots { bot_name } }","variables":{"user_id":1}}`),
|
want: []byte(`{"variables":{"user_id":1},"query":"query listUserBots { tbl_bots { bot_name } }"}`),
|
||||||
wantErr: false,
|
wantErr: false,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -57,74 +58,163 @@ func (suite *TestSuite) Test_GraphQL_Query() {
|
|||||||
g := NewConnection()
|
g := NewConnection()
|
||||||
|
|
||||||
type args struct {
|
type args struct {
|
||||||
queryContent string
|
|
||||||
queryVariables interface{}
|
queryVariables interface{}
|
||||||
|
queryHeaders map[string]interface{}
|
||||||
|
queryContent string
|
||||||
}
|
}
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
|
args args
|
||||||
name string
|
name string
|
||||||
endpoint string
|
endpoint string
|
||||||
|
wantResult string
|
||||||
isLocal bool
|
isLocal bool
|
||||||
cache_enabled bool
|
cache_enabled bool
|
||||||
args args
|
|
||||||
wantResult string
|
|
||||||
wantErr bool
|
wantErr bool
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "Valid query, no cache",
|
name: "Valid query, no cache",
|
||||||
endpoint: "http://hasura.local/v1/graphql",
|
endpoint: "https://telegram-bot.app/v1/graphql",
|
||||||
isLocal: true,
|
isLocal: true,
|
||||||
cache_enabled: false,
|
cache_enabled: false,
|
||||||
args: args{
|
args: args{
|
||||||
queryContent: `query listUserBots {
|
queryContent: `query packages_prices {
|
||||||
tbl_bots(limit: 1) {
|
sub_group_packages_aggregate(where: {enabled: {_eq: true}}) {
|
||||||
bot_name
|
aggregate {
|
||||||
|
count
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}`,
|
}`,
|
||||||
queryVariables: nil,
|
queryVariables: nil,
|
||||||
},
|
},
|
||||||
wantResult: `{"tbl_bots":[{"bot_name":"littleMentionBot"}]}`,
|
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{
|
||||||
|
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,
|
wantErr: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Valid query, with cache empty",
|
name: "Valid query, with cache empty",
|
||||||
endpoint: "http://hasura.local/v1/graphql",
|
endpoint: "https://telegram-bot.app/v1/graphql",
|
||||||
isLocal: true,
|
isLocal: true,
|
||||||
cache_enabled: true,
|
cache_enabled: true,
|
||||||
args: args{
|
args: args{
|
||||||
queryContent: `query listUserBots {
|
queryContent: `query packages_prices {
|
||||||
tbl_bots(limit: 1) {
|
sub_group_packages_aggregate(where: {enabled: {_eq: true}}) {
|
||||||
bot_name
|
aggregate {
|
||||||
|
count
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}`,
|
}`,
|
||||||
queryVariables: nil,
|
queryVariables: nil,
|
||||||
},
|
},
|
||||||
wantResult: `{"tbl_bots":[{"bot_name":"littleMentionBot"}]}`,
|
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,
|
wantErr: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Valid query, with cache filled",
|
name: "Valid query, with cache filled",
|
||||||
endpoint: "http://hasura.local/v1/graphql",
|
endpoint: "https://telegram-bot.app/v1/graphql",
|
||||||
isLocal: true,
|
isLocal: true,
|
||||||
cache_enabled: true,
|
cache_enabled: true,
|
||||||
args: args{
|
args: args{
|
||||||
queryContent: `query listUserBots {
|
queryContent: `query packages_prices {
|
||||||
tbl_bots(limit: 1) {
|
sub_group_packages_aggregate(where: {enabled: {_eq: true}}) {
|
||||||
bot_name
|
aggregate {
|
||||||
|
count
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}`,
|
}`,
|
||||||
queryVariables: nil,
|
queryVariables: nil,
|
||||||
},
|
},
|
||||||
wantResult: `{"tbl_bots":[{"bot_name":"littleMentionBot"}]}`,
|
wantResult: `{"sub_group_packages_aggregate":{"aggregate":{"count":4}}}`,
|
||||||
wantErr: false,
|
wantErr: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Invalid query",
|
name: "Invalid query",
|
||||||
endpoint: "http://hasura.local/v1/graphql",
|
endpoint: "https://telegram-bot.app/v1/graphql",
|
||||||
isLocal: true,
|
isLocal: true,
|
||||||
args: args{
|
args: args{
|
||||||
queryContent: `query listUserBots {
|
queryContent: `query packages_pricez {
|
||||||
tbl_botz(limit: 1) {
|
sub_group_packages_aggregate(where: {enabled: {_eq: true}}) {
|
||||||
bot_name
|
aggregate {
|
||||||
|
count
|
||||||
}
|
}
|
||||||
}`,
|
}`,
|
||||||
queryVariables: nil,
|
queryVariables: nil,
|
||||||
@@ -132,6 +222,47 @@ func (suite *TestSuite) Test_GraphQL_Query() {
|
|||||||
wantResult: ``,
|
wantResult: ``,
|
||||||
wantErr: true,
|
wantErr: true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "Valid query to https endpoint",
|
||||||
|
endpoint: "https://telegram-bot.app/v1/graphql",
|
||||||
|
isLocal: 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 to github endpoint",
|
||||||
|
endpoint: "https://api.github.com/graphql",
|
||||||
|
isLocal: false,
|
||||||
|
args: args{
|
||||||
|
queryContent: `query {
|
||||||
|
repository(name: "semver-generator", owner: "lukaszraczylo", followRenames: true) {
|
||||||
|
releases(last: 2) {
|
||||||
|
nodes {
|
||||||
|
tag {
|
||||||
|
name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}`,
|
||||||
|
queryVariables: nil,
|
||||||
|
queryHeaders: map[string]interface{}{
|
||||||
|
"Authorization": "Bearer " + os.Getenv("GITHUB_TOKEN"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wantResult: `{"repository":{"releases":{"nodes":[`,
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
suite.T().Run(tt.name, func(t *testing.T) {
|
suite.T().Run(tt.name, func(t *testing.T) {
|
||||||
@@ -140,11 +271,11 @@ func (suite *TestSuite) Test_GraphQL_Query() {
|
|||||||
// }
|
// }
|
||||||
g.Endpoint = tt.endpoint
|
g.Endpoint = tt.endpoint
|
||||||
g.Cache = tt.cache_enabled
|
g.Cache = tt.cache_enabled
|
||||||
gotResult, gotErr := g.Query(tt.args.queryContent, tt.args.queryVariables, nil)
|
gotResult, gotErr := g.Query(tt.args.queryContent, tt.args.queryVariables, tt.args.queryHeaders)
|
||||||
if tt.wantErr {
|
if tt.wantErr {
|
||||||
assert.Error(t, gotErr)
|
assert.Error(t, gotErr)
|
||||||
}
|
}
|
||||||
assert.Equal(t, tt.wantResult, gotResult)
|
assert.Contains(t, gotResult, tt.wantResult)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
fmt.Println(g.CacheStore.Capacity())
|
fmt.Println(g.CacheStore.Capacity())
|
||||||
|
|||||||
Reference in New Issue
Block a user