Compare commits

...
5 Commits
8 changed files with 250 additions and 112 deletions
+6 -2
View File
@@ -11,11 +11,15 @@ help: ## display this help
.PHONY: test .PHONY: test
test: ## run tests on library test: ## run tests on library
@go test $(ADDITIONAL_BUILD_FLAGS) -v -cover ./... @LOG_LEVEL=debug go test $(ADDITIONAL_BUILD_FLAGS) -v -cover ./...
.PHONY: test-packages .PHONY: test-packages
test-packages: ## run tests on packages test-packages: ## run tests on packages
@go test -v -cover ./pkg/... @go test -v -cover ./pkg/...
.PHONY: all .PHONY: all
all: test-packages test all: test-packages test
.PHONY: update
update: ## update dependencies
@go get -u -v ./...
+4 -1
View File
@@ -23,12 +23,15 @@ Therefore, I present you the simple client to which you can copy & paste your gr
* Executing GraphQL queries as they are, without types declaration * Executing GraphQL queries as they are, without types declaration
* HTTP2 support! * HTTP2 support!
* Support for additional headers * Support for additional headers
* Query cache
## Usage example ## Usage example
### Environment variables ### Environment variables
* `GRAPHQL_ENDPOINT` - Your GraphQL endpoint. Default: `http://127.0.0.1:9090/v1/graphql` * `GRAPHQL_ENDPOINT` - Your GraphQL endpoint. Default: `http://127.0.0.1:9090/v1/graphql`
* `GRAPHQL_CACHE` - Should the query cache be enabled? Default: `false`
* `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`
### Example reader code ### Example reader code
@@ -37,7 +40,7 @@ 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/simple-gql-client" gql "github.com/lukaszraczylo/go-simple-graphql"
) )
headers := map[string]interface{}{ headers := map[string]interface{}{
+7 -4
View File
@@ -3,20 +3,23 @@ module github.com/lukaszraczylo/go-simple-graphql
go 1.17 go 1.17
require ( require (
github.com/allegro/bigcache/v3 v3.0.1
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.10
github.com/rs/zerolog v1.25.0 github.com/rs/zerolog v1.26.0
github.com/stretchr/testify v1.7.0 github.com/stretchr/testify v1.7.0
golang.org/x/net v0.0.0-20210929193557-e81a3d93ecf6 golang.org/x/net v0.0.0-20211201190559-0a0e4e1bb54c
) )
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.12 // indirect
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect github.com/kr/pretty v0.1.0 // 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.6 // indirect golang.org/x/text v0.3.7 // indirect
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect
) )
+21 -13
View File
@@ -1,3 +1,5 @@
github.com/allegro/bigcache/v3 v3.0.1 h1:Q4Xl3chywXuJNOw7NV+MeySd3zGQDj4KCpkCg0te8mc=
github.com/allegro/bigcache/v3 v3.0.1/go.mod h1:aPyh7jEvrog9zAwx5N7+JUQX5dZTSGpxF1LAR4dr35I=
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.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
@@ -10,52 +12,58 @@ github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
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/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/lukaszraczylo/pandati v0.0.10 h1:ZXmLjxb/UYRBVyAKwXmUcJgZ2FYNwGY4YDJsQQMYAXI= github.com/lukaszraczylo/pandati v0.0.10 h1:ZXmLjxb/UYRBVyAKwXmUcJgZ2FYNwGY4YDJsQQMYAXI=
github.com/lukaszraczylo/pandati v0.0.10/go.mod h1:1lE/x4X4LfO1yerAQoiR7AVb/wIabH/zITDGnqTdyH8= github.com/lukaszraczylo/pandati v0.0.10/go.mod h1:1lE/x4X4LfO1yerAQoiR7AVb/wIabH/zITDGnqTdyH8=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
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/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
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.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/rs/zerolog v1.25.0 h1:Rj7XygbUHKUlDPcVdoLyR91fJBsduXj5fRxyqIQj/II= github.com/rs/zerolog v1.26.0 h1:ORM4ibhEZeTeQlCojCK2kPz1ogAY4bGs4tD+SaAdGaE=
github.com/rs/zerolog v1.25.0/go.mod h1:7KHcEGe0QZPOm2IE4Kpb5rTh6n1h2hIgS5OOnu1rUaI= github.com/rs/zerolog v1.26.0/go.mod h1:yBiM87lvSqX8h0Ww4sdzNSkVYZ8dL2xjZJG1lAuGZEo=
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.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= 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-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-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 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-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-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210929193557-e81a3d93ecf6 h1:Z04ewVs7JhXaYkmDhBERPi41gnltfQpMWDnTnQbaCqk= golang.org/x/net v0.0.0-20211201190559-0a0e4e1bb54c h1:WtYZ93XtWSO5KlOMgPZu7hXY9WhMZpprvlm5VwvAl8c=
golang.org/x/net v0.0.0-20210929193557-e81a3d93ecf6/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211201190559-0a0e4e1bb54c/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 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/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-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-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-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 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.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 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
golang.org/x/text v0.3.6/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-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.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= 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-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-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/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 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
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 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 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 h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
+46 -6
View File
@@ -15,11 +15,12 @@ package gql
import ( import (
"crypto/tls" "crypto/tls"
"fmt" "fmt"
"net"
"net/http" "net/http"
"os" "os"
"strconv"
"time" "time"
"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"
"golang.org/x/net/http2" "golang.org/x/net/http2"
@@ -33,6 +34,8 @@ type GraphQL struct {
Endpoint string Endpoint string
HttpClient *http.Client HttpClient *http.Client
Log *logging.LogConfig Log *logging.LogConfig
Cache bool // Enable caching for read queries
CacheStore *bigcache.BigCache
} }
func pickGraphqlEndpoint() (graphqlEndpoint string) { func pickGraphqlEndpoint() (graphqlEndpoint string) {
@@ -46,19 +49,56 @@ func pickGraphqlEndpoint() (graphqlEndpoint string) {
return graphqlEndpoint return graphqlEndpoint
} }
func setCacheTTL() int {
value, present := os.LookupEnv("GRAPHQL_CACHE_TTL")
if present && value != "" {
i, err := strconv.Atoi(value)
if err != nil {
panic("Invalid value for query cache ttl")
}
return int(i)
} else {
return 5
}
}
func setCacheEnabled() bool {
value, present := os.LookupEnv("GRAPHQL_CACHE")
if present && value != "" {
b, err := strconv.ParseBool(value)
if err != nil {
panic("Invalid value for query cache")
}
return b
} else {
return false
}
}
func NewConnection() *GraphQL { func NewConnection() *GraphQL {
return &GraphQL{ g := GraphQL{
Endpoint: pickGraphqlEndpoint(), Endpoint: pickGraphqlEndpoint(),
HttpClient: &http.Client{ HttpClient: &http.Client{
Timeout: time.Second * 30,
Transport: &http2.Transport{ Transport: &http2.Transport{
DisableCompression: false, DisableCompression: false,
AllowHTTP: true, AllowHTTP: true,
DialTLS: func(network, addr string, cfg *tls.Config) (net.Conn, error) { PingTimeout: 10 * time.Second,
return net.Dial(network, addr) TLSClientConfig: &tls.Config{
InsecureSkipVerify: true,
}, },
}, },
}, },
Log: logging.NewLogger(), Log: logging.NewLogger(),
Cache: setCacheEnabled(),
CacheStore: setupCache(),
} }
return &g
}
func setupCache() *bigcache.BigCache {
cache, err := bigcache.NewBigCache(bigcache.DefaultConfig(time.Duration(setCacheTTL()) * time.Second))
if err != nil {
panic("Error creating cache: " + err.Error())
}
return cache
} }
+30 -7
View File
@@ -2,6 +2,7 @@ package gql
import ( import (
"bytes" "bytes"
"crypto/md5"
"errors" "errors"
"fmt" "fmt"
"io" "io"
@@ -29,16 +30,11 @@ func (g *GraphQL) queryBuilder(queryContent string, queryVariables interface{})
Variables: queryVariables, Variables: queryVariables,
} }
// j := new(bytes.Buffer)
j2, err := json.Marshal(qb) j2, err := json.Marshal(qb)
if err != nil { if err != nil {
g.Log.Critical("Unable to marshal the query", map[string]interface{}{"_error": err.Error(), "_query": queryContent, "_variables": queryVariables}) g.Log.Critical("Unable to marshal the query", map[string]interface{}{"_error": err.Error(), "_query": queryContent, "_variables": queryVariables})
return []byte{}, err return []byte{}, err
} }
// if err = json.Compact(j, j2); err != nil {
// g.Log.Critical("Unable to compact the query", map[string]interface{}{"error": err.Error()})
// return []byte{}, err
// }
return j2, err return j2, err
} }
@@ -49,6 +45,23 @@ func (g *GraphQL) Query(queryContent string, queryVariables interface{}, queryHe
g.Log.Error("Unable to build the query", map[string]interface{}{"_error": err.Error()}) g.Log.Error("Unable to build the query", map[string]interface{}{"_error": err.Error()})
return "", err return "", err
} }
var body []byte
var queryResult *queryResults
queryHash := fmt.Sprintf("%x", md5.Sum(query))
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 {
g.Log.Debug("Found the query in the cache", map[string]interface{}{"_query": queryHash})
if pandati.IsZero(entryInfo.EntryStatus) {
return string(entry), nil
}
} else {
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.Add("Content-Type", "application/json")
for header, value := range queryHeaders { for header, value := range queryHeaders {
@@ -63,12 +76,12 @@ func (g *GraphQL) Query(queryContent string, queryVariables interface{}, queryHe
defer io.Copy(ioutil.Discard, httpResponse.Body) defer io.Copy(ioutil.Discard, httpResponse.Body)
defer httpResponse.Body.Close() defer httpResponse.Body.Close()
body, err := ioutil.ReadAll(httpResponse.Body) body, err = ioutil.ReadAll(httpResponse.Body)
if err != nil { if err != nil {
g.Log.Critical("Unable to read the response", map[string]interface{}{"_error": err.Error()}) g.Log.Critical("Unable to read the response", map[string]interface{}{"_error": err.Error()})
return "", err return "", err
} }
var queryResult *queryResults
err = json.Unmarshal(body, &queryResult) err = json.Unmarshal(body, &queryResult)
if err != nil { if err != nil {
g.Log.Error("Unable to unmarshal the query", map[string]interface{}{"_error": err.Error()}) g.Log.Error("Unable to unmarshal the query", map[string]interface{}{"_error": err.Error()})
@@ -91,5 +104,15 @@ func (g *GraphQL) Query(queryContent string, queryVariables interface{}, queryHe
return "", err return "", err
} }
if g.Cache {
g.Log.Debug("Caching the query", map[string]interface{}{"_query": queryHash})
if queryContent[0:5] == "query" {
err = g.CacheStore.Set(queryHash, []byte(responseContent))
if err != nil {
g.Log.Error("Unable to cache the query", map[string]interface{}{"_query": queryHash, "_error": err.Error()})
}
}
}
return return
} }
+65 -65
View File
@@ -1,69 +1,69 @@
package gql package gql
import ( // import (
"testing" // "testing"
) // )
func Benchmark_GraphQL_Query(t *testing.B) { // func Benchmark_GraphQL_Query(t *testing.B) {
if testing.Short() { // if testing.Short() {
t.Skip("Skipping test in short / CI mode") // t.Skip("Skipping test in short / CI mode")
} // }
type args struct { // type args struct {
queryContent string // queryContent string
queryVariables interface{} // queryVariables interface{}
} // }
tests := []struct { // tests := []struct {
name string // name string
endpoint string // endpoint string
isLocal bool // isLocal bool
args args // args args
wantResult string // wantResult string
mockedReply string // mockedReply string
wantErr bool // wantErr bool
}{ // }{
{ // {
name: "Valid query", // name: "Valid query",
endpoint: "http://hasura.local/v1/graphql", // endpoint: "http://hasura.local/v1/graphql",
isLocal: false, // isLocal: false,
args: args{ // args: args{
queryContent: `query listUserBots { // queryContent: `query listUserBots {
tbl_bots(limit: 1) { // tbl_bots(limit: 1) {
bot_name // bot_name
} // }
}`, // }`,
queryVariables: nil, // queryVariables: nil,
}, // },
wantResult: `{"tbl_bots":[{"bot_name":"littleMentionBot"}]}`, // wantResult: `{"tbl_bots":[{"bot_name":"littleMentionBot"}]}`,
mockedReply: `{"data":{"tbl_bots":[{"bot_name":"littleMentionBot"}]}}`, // mockedReply: `{"data":{"tbl_bots":[{"bot_name":"littleMentionBot"}]}}`,
wantErr: false, // wantErr: false,
}, // },
{ // {
name: "Invalid query", // name: "Invalid query",
endpoint: "http://hasura.local/v1/graphql", // endpoint: "http://hasura.local/v1/graphql",
isLocal: false, // isLocal: false,
args: args{ // args: args{
queryContent: `query listUserBots { // queryContent: `query listUserBots {
tbl_botz(limit: 1) { // tbl_botz(limit: 1) {
bot_name // bot_name
} // }
}`, // }`,
queryVariables: nil, // queryVariables: nil,
}, // },
mockedReply: `{"errors":[{"message":"Unknown field \"tbl_botz\" on type \"Query\""}]}`, // mockedReply: `{"errors":[{"message":"Unknown field \"tbl_botz\" on type \"Query\""}]}`,
wantResult: ``, // wantResult: ``,
wantErr: true, // wantErr: true,
}, // },
} // }
for _, tt := range tests { // for _, tt := range tests {
t.Run(tt.name, func(t *testing.B) { // t.Run(tt.name, func(t *testing.B) {
g := NewConnection() // g := NewConnection()
server, serverURL := mockGraphQLServerResponses(tt.mockedReply) // server, serverURL := mockGraphQLServerResponses(tt.mockedReply)
g.Endpoint = serverURL // g.Endpoint = serverURL
for n := 0; n < t.N; n++ { // for n := 0; n < t.N; n++ {
g.Query(tt.args.queryContent, tt.args.queryVariables, nil) // g.Query(tt.args.queryContent, tt.args.queryVariables, nil)
} // }
server.Close() // server.Close()
}) // })
} // }
} // }
+71 -14
View File
@@ -1,7 +1,7 @@
package gql package gql
import ( import (
"os" "fmt"
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@@ -54,22 +54,58 @@ func (suite *TestSuite) Test_GraphQL_Query() {
if testing.Short() { if testing.Short() {
suite.T().Skip("Skipping test in short / CI mode") suite.T().Skip("Skipping test in short / CI mode")
} }
g := NewConnection()
type args struct { type args struct {
queryContent string queryContent string
queryVariables interface{} queryVariables interface{}
} }
tests := []struct { tests := []struct {
name string name string
endpoint string endpoint string
isLocal bool isLocal bool
args args cache_enabled bool
wantResult string args args
wantErr bool wantResult string
wantErr bool
}{ }{
{ {
name: "Valid query", name: "Valid query, no cache",
endpoint: "http://hasura.local/v1/graphql", endpoint: "http://hasura.local/v1/graphql",
isLocal: true, isLocal: true,
cache_enabled: false,
args: args{
queryContent: `query listUserBots {
tbl_bots(limit: 1) {
bot_name
}
}`,
queryVariables: nil,
},
wantResult: `{"tbl_bots":[{"bot_name":"littleMentionBot"}]}`,
wantErr: false,
},
{
name: "Valid query, with cache empty",
endpoint: "http://hasura.local/v1/graphql",
isLocal: true,
cache_enabled: true,
args: args{
queryContent: `query listUserBots {
tbl_bots(limit: 1) {
bot_name
}
}`,
queryVariables: nil,
},
wantResult: `{"tbl_bots":[{"bot_name":"littleMentionBot"}]}`,
wantErr: false,
},
{
name: "Valid query, with cache filled",
endpoint: "http://hasura.local/v1/graphql",
isLocal: true,
cache_enabled: true,
args: args{ args: args{
queryContent: `query listUserBots { queryContent: `query listUserBots {
tbl_bots(limit: 1) { tbl_bots(limit: 1) {
@@ -96,13 +132,33 @@ func (suite *TestSuite) Test_GraphQL_Query() {
wantResult: ``, wantResult: ``,
wantErr: true, wantErr: true,
}, },
{
name: "Valid query to https endpoint",
endpoint: "https://web-dev.telegram-bot.app/v1/graphql",
isLocal: false,
args: args{
queryContent: `query packages_prices {
available_packages: tbl_available_packages(where: {enabled: {_eq: true}}) {
package_name
package_discount
package_price
package_size
package_type
}
}`,
queryVariables: nil,
},
wantResult: `{"available_packages":[{"package_discount":0,"package_name":"media_1000","package_price":750,"package_size":1000,"package_type":"media"},{"package_discount":5,"package_name":"media_5000","package_price":3563,"package_size":5000,"package_type":"media"},{"package_discount":10,"package_name":"media_10000","package_price":6750,"package_size":10000,"package_type":"media"},{"package_discount":15,"package_name":"media_25000","package_price":15938,"package_size":25000,"package_type":"media"},{"package_discount":0,"package_name":"voice_500","package_price":1000,"package_size":500,"package_type":"voice"},{"package_discount":10,"package_name":"voice_1000","package_price":1800,"package_size":1000,"package_type":"voice"},{"package_discount":15,"package_name":"voice_2500","package_price":4250,"package_size":2500,"package_type":"voice"}]}`,
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) {
if tt.isLocal { // if tt.isLocal {
os.Setenv("GRAPHQL_ENDPOINT", tt.endpoint) // os.Setenv("GRAPHQL_ENDPOINT", tt.endpoint)
} // }
g := NewConnection() g.Endpoint = tt.endpoint
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, nil)
if tt.wantErr { if tt.wantErr {
assert.Error(t, gotErr) assert.Error(t, gotErr)
@@ -110,4 +166,5 @@ func (suite *TestSuite) Test_GraphQL_Query() {
assert.Equal(t, tt.wantResult, gotResult) assert.Equal(t, tt.wantResult, gotResult)
}) })
} }
fmt.Println(g.CacheStore.Capacity())
} }