Skip to content

Commit

Permalink
add graphql package
Browse files Browse the repository at this point in the history
  • Loading branch information
krabiworld committed Jun 12, 2024
1 parent 46b6873 commit ecbc749
Show file tree
Hide file tree
Showing 5 changed files with 350 additions and 81 deletions.
121 changes: 61 additions & 60 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ A small toolkit for creating microservices.

### Env

Main library: [joho/godotenv](https://github.com/joho/godotenv)
Thanks: [joho/godotenv](https://github.com/joho/godotenv)

Create `.env` file in the root of your project or run app with env variables.
```dotenv
Expand All @@ -21,82 +21,91 @@ DEBUG=true

Then in your Go app you can do something like:
```go
package main

import "github.com/Toscale-platform/kit/env"

func main() {
token := env.GetString("TOKEN")
port := env.GetInt("PORT")
exchanges := env.GetSlice("EXCHANGES")
debug := env.GetBool("DEBUG")
}
token := env.GetString("TOKEN")
port := env.GetInt("PORT")
exchanges := env.GetSlice("EXCHANGES")
debug := env.GetBool("DEBUG")
```

### Log

Main library: [rs/zerolog](https://github.com/rs/zerolog)
Thanks: [rs/zerolog](https://github.com/rs/zerolog)

```go
package main

import "github.com/Toscale-platform/kit/log"

func main() {
log.Error().Msg("Error message")
log.Info().Str("key", "value").Msg("Info message")
}
log.Error().Msg("Error message")
log.Info().Str("key", "value").Msg("Info message")
```

### HTTP

Main library: [valyala/fasthttp](https://github.com/valyala/fasthttp)
Thanks: [valyala/fasthttp](https://github.com/valyala/fasthttp)

```go
package main

import "github.com/Toscale-platform/kit/http"

func main() {
http.Get("https://example.com", nil)
http.Get("https://example.com", nil)

body := Body{}
http.Post("https://example.com", &body, nil)
}
body := Body{}
http.Post("https://example.com", &body, nil)
```

### Validator
### GraphQL

Thanks: [machinebox/graph](https://github.com/machinebox/graphql)

```go
package main
import (
"time"
"github.com/Toscale-platform/kit/http"
)

client := graphql.NewClient("https://machinebox.io/graphql")

req := graphql.NewRequest(`
query ($key: String!) {
items (id: $key) {
field1
field2
field3
}
}
`)

req.Var("key", "value")
req.Header.Set("Cache-Control", "no-cache")

var respData ResponseStruct
err := client.Run(req, &respData, time.Minute)
```

### Validator

```go
import "github.com/Toscale-platform/kit/validator"

func main() {
if validator.IsSymbol("BTC/USDT") {
//
}

if validator.IsExchange("binance") {
//
}
if validator.IsSymbol("BTC/USDT") {
//
}

if validator.IsExchange("binance") {
//
}
```


### Output

```go
package main

import "github.com/Toscale-platform/kit/output"

func main() {
r := router.New()

r.GET("/path", handler)
r.OPTIONS("/path", output.CORSOptions)
}
r := router.New()

r.GET("/path", handler)
r.OPTIONS("/path", output.CORSOptions)

func handler(ctx *fasthttp.RequestCtx){
res := map[string]string{"foo": "bar"}
Expand All @@ -109,32 +118,24 @@ func handler(ctx *fasthttp.RequestCtx){
### Auth

```go
package main

import "github.com/Toscale-platform/kit/auth"

func main() {
isDebug := env.GetBool("DEBUG")
host := env.GetString("AUTH_HOST")
authManager := auth.Init(host, isDebug)

r := router.New()

r.GET("/path", authManager.IsAdmin(handler))
}
isDebug := env.GetBool("DEBUG")
host := env.GetString("AUTH_HOST")
authManager := auth.Init(host, isDebug)

r := router.New()

r.GET("/path", authManager.IsAdmin(handler))
```

### Exchange

```go
package main

import "github.com/Toscale-platform/kit/exchange"

func main() {
symbols, err := exchange.GetSymbols("binance")
if err != nil {
//
}
symbols, err := exchange.GetSymbols("binance")
if err != nil {
//
}
```
16 changes: 7 additions & 9 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,18 @@ module github.com/Toscale-platform/kit
go 1.21

require (
github.com/goccy/go-json v0.10.3
github.com/joho/godotenv v1.5.1
github.com/rs/zerolog v1.32.0
github.com/valyala/fasthttp v1.52.0
github.com/matryer/is v1.4.1
github.com/rs/zerolog v1.33.0
github.com/valyala/fasthttp v1.54.0
)

require (
github.com/andybalholm/brotli v1.1.0 // indirect
github.com/klauspost/compress v1.17.8 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
)

require (
github.com/goccy/go-json v0.10.2
github.com/klauspost/compress v1.17.9 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
golang.org/x/sys v0.20.0 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
golang.org/x/sys v0.21.0 // indirect
)
24 changes: 12 additions & 12 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M=
github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA=
github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU=
github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
github.com/matryer/is v1.4.1 h1:55ehd8zaGABKLXQUe2awZ99BD/PTc2ls+KV/dXphgEQ=
github.com/matryer/is v1.4.1/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU=
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.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
Expand All @@ -16,16 +18,14 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/rs/zerolog v1.32.0 h1:keLypqrlIjaFsbmJOBdB/qvyF8KEtCWHwobLp5l/mQ0=
github.com/rs/zerolog v1.32.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8=
github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasthttp v1.52.0 h1:wqBQpxH71XW0e2g+Og4dzQM8pk34aFYlA1Ga8db7gU0=
github.com/valyala/fasthttp v1.52.0/go.mod h1:hf5C4QnVMkNXMspnsUlfM3WitlgYflyhHYoKol/szxQ=
github.com/valyala/fasthttp v1.54.0 h1:cCL+ZZR3z3HPLMVfEYVUMtJqVaui0+gu7Lx63unHwS0=
github.com/valyala/fasthttp v1.54.0/go.mod h1:6dt4/8olwq9QARP/TDuPmWyWcl4byhpvTJ4AAtcz+QM=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
132 changes: 132 additions & 0 deletions graphql/graphql.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
package graphql

import (
"fmt"
"github.com/goccy/go-json"
"github.com/valyala/fasthttp"
"net/http"
"time"
)

// Client is a client for interacting with a GraphQL API.
type Client struct {
endpoint string
httpClient *fasthttp.Client
}

// NewClient makes a new Client capable of making GraphQL requests.
func NewClient(endpoint string) *Client {
return &Client{
endpoint: endpoint,
httpClient: &fasthttp.Client{StreamResponseBody: false},
}
}

// Run executes the query and unmarshals the response from the data field
// into the response object.
// Pass in a nil response object to skip response parsing.
// If the request fails or the server returns an error, the first error
// will be returned.
func (c *Client) Run(req *Request, resp interface{}, timeout time.Duration) error {
requestBodyObj := internalRequest{
Query: req.q,
Variables: req.vars,
}

requestBody, err := json.Marshal(requestBodyObj)
if err != nil {
return fmt.Errorf("encode body: %w", err)
}

gr := &graphResponse{
Data: resp,
}

r := fasthttp.AcquireRequest()
r.Header.SetMethod(fasthttp.MethodPost)
r.SetRequestURI(c.endpoint)
r.SetBodyRaw(requestBody)

r.Header.SetContentType("application/json; charset=utf-8")
r.Header.Set("Accept", "application/json; charset=utf-8")

for key, values := range req.Header {
for _, value := range values {
r.Header.Add(key, value)
}
}

res := fasthttp.AcquireResponse()

if err := c.httpClient.DoTimeout(r, res, timeout); err != nil {
return err
}

fasthttp.ReleaseRequest(r)
defer fasthttp.ReleaseResponse(res)

if err := json.Unmarshal(res.Body(), &gr); err != nil {
return fmt.Errorf("decoding response: %w", err)
}

if len(gr.Errors) > 0 {
// return first error
return gr.Errors[0]
}

return nil
}

type internalRequest struct {
Query string `json:"query"`
Variables map[string]interface{} `json:"variables"`
}

type graphErr struct {
Message string
}

func (e graphErr) Error() string {
return "graphql: " + e.Message
}

type graphResponse struct {
Data interface{}
Errors []graphErr
}

// Request is a GraphQL request.
type Request struct {
q string
vars map[string]interface{}

// Header represent any request headers that will be set
// when the request is made.
Header http.Header
}

// NewRequest makes a new Request with the specified string.
func NewRequest(q string) *Request {
return &Request{
q: q,
Header: make(map[string][]string),
}
}

// Var sets a variable.
func (req *Request) Var(key string, value interface{}) {
if req.vars == nil {
req.vars = make(map[string]interface{})
}
req.vars[key] = value
}

// Vars gets the variables for this Request.
func (req *Request) Vars() map[string]interface{} {
return req.vars
}

// Query gets the query string of this request.
func (req *Request) Query() string {
return req.q
}
Loading

0 comments on commit ecbc749

Please sign in to comment.