Skip to content

Releases: hasura/go-graphql-client

v0.6.3

05 Feb 04:48
dedae85
Compare
Choose a tag to compare

v0.6.2

11 Jan 14:46
01a575e
Compare
Choose a tag to compare
  • fix: race condition in the Close method of the SubscriptionClient (#27) @davitovmasyan

v0.6.1

04 Jan 17:26
9eed82e
Compare
Choose a tag to compare

Update nhooyr/websocket v1.8.7 dependency to fix the DDoS vulnerability issue (#26)

v0.6.0

18 Dec 03:57
3578c9b
Compare
Choose a tag to compare

Highlights

Custom scalar tag

Because the generator reflects recursively struct objects, it can't know if the struct is a custom scalar such as JSON. To avoid expansion of the field during query generation, let's add the tag scalar:"true" to the custom scalar. If the scalar implements the JSON decoder interface, it will be automatically decoded.

struct {
	Viewer struct {
		ID         interface{}
		Login      string
		CreatedAt  time.Time
		DatabaseID int
	}
}
// Output:
// {
//   viewer {
//	   id
//		 login
//		 createdAt
//		 databaseId
//   }	
// }
struct {
	Viewer struct {
		ID         interface{}
		Login      string
		CreatedAt  time.Time
		DatabaseID int
	} `scalar:"true"`
}
// Output
// { viewer }

Add mechanism to modify outgoing HTTP request

This feature allows reusing the same client amongst slightly different "configurations". We are able to use one single HTTP client in multitenant applications with different authentication headers.

func setAuthHeader(secret string) func(req *http.Request) {
	return func(req *http.Request) {
		req.Header.Add("x-hasura-admin-secret", secret)
	}
}

client := graphql.NewClient("http://localhost:8080/v1/graphql", nil)

// return new client wrapper with different authentication header
client2 := client.WithRequestModifier(setAuthHeader("hasura"))

Changelog

  • feat: add mechanism to modify outgoing http request (#23) @dbarrosop
  • feat: allow tagging of the field as having a scalar GraphQL type (#24) @nizar-m

v0.5.2

14 Dec 15:11
e67ba68
Compare
Choose a tag to compare
  • export Errors and add extensions to allow clients parsing the error (#22) @dbarrosop

v0.5.1

18 Nov 10:52
d3bb811
Compare
Choose a tag to compare

Improvement for #20. When we access interface{} in reflect we need to call v.Elem() to get the actual object inside (#21) @grihabor

v0.5.0

15 Nov 02:43
2b4feca
Compare
Choose a tag to compare
  • allow building queries and mutations from ordered maps ([][2]string) (#20)

You might need to make multiple mutations in single query. It's not very convenient with structs, so you can use ordered map [][2]interface{} instead.

For example, to make the following GraphQL mutation:

mutation($login1: String!, $login2: String!, $login3: String!) {
	createUser(login: $login1) { login }
	createUser(login: $login2) { login }
	createUser(login: $login3) { login }
}
variables {
	"login1": "grihabor",
	"login2": "diman",
	"login3": "indigo"
}

You can define:

type CreateUser struct {
	Login graphql.String
}
m := [][2]interface{}{
	{"createUser(login: $login1)", &CreateUser{}},
	{"createUser(login: $login2)", &CreateUser{}},
	{"createUser(login: $login3)", &CreateUser{}},
}
variables := map[string]interface{}{
	"login1": graphql.String("grihabor"),
	"login2": graphql.String("diman"),
	"login3": graphql.String("indigo"),
}

v0.4.0

18 Oct 17:52
0d5d3af
Compare
Choose a tag to compare
  • add extensible option arguments (#18)
  • docs: add an example for mutation without fields (#17)

There are extensible parts in the GraphQL query. We shouldn't required them in the method. To make it flexible, we can abstract these options as optional arguments that follow this interface.

type Option interface {
	Type() OptionType
	String() string
}

client.Query(ctx context.Context, q interface{}, variables map[string]interface{}, options ...Option) error

Currently we support 2 option types: operation_name and operation_directive. The operation name option is built-in because it is unique. We can use the option directly with OperationName

// query MyQuery {
//	...
// }
client.Query(ctx, &q, variables, graphql.OperationName("MyQuery"))

In contrast, operation directive is various and customizable on different GraphQL servers. There isn't any built-in directive in the library. You need to define yourself. For example:

// define @cached directive for Hasura queries
// https://hasura.io/docs/latest/graphql/cloud/response-caching.html#enable-caching
type cachedDirective struct {
	ttl int
}

func (cd cachedDirective) Type() OptionType {
	// operation_directive
	return graphql.OptionTypeOperationDirective
}

func (cd cachedDirective) String() string {
	if cd.ttl <= 0 {
		return "@cached"
	}
	return fmt.Sprintf("@cached(ttl: %d)", cd.ttl)
}

// query MyQuery @cached {
//	...
// }
client.Query(ctx, &q, variables, graphql.OperationName("MyQuery"), cachedDirective{})

v0.3.0

21 Sep 19:16
c37b892
Compare
Choose a tag to compare

This release includes bug fixes, improvements and documentation updates

  • introduce SubscribeRaw and wrap all subscriptions map access with lock to avoid race condition (#4) (thank @digitalcrab)
  • allow clients to receive all GraphQL errors from server (#8) (thank @totalys)
  • support raw JSON field with json.RawMessage type (#14) (thank @kwapik)
  • expose WebsocketHandler and custom WebSocket client documentation (#15)
  • misc: automation test with Github Action

v0.2.0

12 Nov 10:18
0806e5e
Compare
Choose a tag to compare

In the case we developers want to decode JSON response ourself. Moreover, the default UnmarshalGraphQL function isn't ideal with complicated nested interfaces

func (c *Client) QueryRaw(ctx context.Context, q interface{}, variables map[string]interface{}) (*json.RawMessage, error)

func (c *Client) MutateRaw(ctx context.Context, q interface{}, variables map[string]interface{}) (*json.RawMessage, error)

func (c *Client) NamedQueryRaw(ctx context.Context, name string, q interface{}, variables map[string]interface{}) (*json.RawMessage, error)

func (c *Client) NamedMutateRaw(ctx context.Context, name string, q interface{}, variables map[string]interface{}) (*json.RawMessage, error)