graphqlc

package module
v0.0.0-...-e49e13f Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 3, 2023 License: MIT Imports: 10 Imported by: 0

README

graphqlc

Package graphqlc provides a GraphQL client implementation.

Installation

go get -u github.com/solid-wang/graphqlc

Usage

Construct a GraphQL client, specifying the GraphQL server URL. Then, you can use it to make GraphQL queries、 mutations and subscription.

client, _ := graphqlc.NewClient("https://example.com/graphql")
// Use client...
Query
Simple Query

For example, to make the following GraphQL query:

query {
	me {
		name
	}
}

You can define this graphql request:

req := NewGraphRequest(`
    query Me {
        me {
            name
        }
    }
`, nil)

You also need to define the struct:

type Me struct {
    Name          string
}
type Response struct {
    Me Me
}

Then do request, you need passing a pointer to resp:

var resp Response
err := client.Body(req).QueryOrMutate().Do(context.Background()).Decode(&resp)
if err != nil {
	// Handle error.
}
fmt.Println(query.Me.Name)

// Output: Luke Skywalker
Arguments and Variables

Often, you'll want to specify arguments on some fields.

For example, to make the following GraphQL query:

{
	human(id: "1000") {
		name
		height(unit: METER)
	}
}

You can define this graphql request:

req := NewGraphRequest(`
    {
        human(id: "1000") {
            name
            height(unit: METER)
        }
    }
`, nil)

Usually, you might want to use:

req := NewGraphRequest(`
    query Human($id: ID!, $unit: LengthUnit) {
        human(id: $id) {
            name
            height(unit: $unit)
        }
    }
`, map[string]any{"id": "1000", "unit": "METER"})

You also need to define the struct:

type Human struct {
    Name          string
	height          string
}
type Response struct {
    Human Human
}

Then do request:

var resp Response
err := client.Body(req).QueryOrMutate().Do(context.Background()).Decode(&resp)
if err != nil {
	// Handle error.
}
fmt.Println(q.Human.Name)
fmt.Println(q.Human.Height)

// Output:
// Luke Skywalker
// 1.72
Mutations

Mutations often require information that you can only find out by performing a query first. Let's suppose you've already done that.

For example, to make the following GraphQL mutation:

mutation($ep: Episode!, $review: ReviewInput!) {
	createReview(episode: $ep, review: $review) {
		stars
		commentary
	}
}
variables {
	"ep": "JEDI",
	"review": {
		"stars": 5,
		"commentary": "This is a great movie!"
	}
}

You can define:

req := NewGraphRequest(`
    mutation($ep: Episode!, $review: ReviewInput!) {
        createReview(episode: $ep, review: $review) {
            stars
            commentary
        }
    }
`, map[string]any{"ep": "JEDI", "review": map[string]any{"start": 5, "commentary": "This is a great movie!"}})

You also need to define the struct:

type CreateReview struct {
    stars          int
    commentary     string
}
type Response struct {
    CreateReview CreateReview
}

Then do request:

var resp Response
err = client.Body(req).QueryOrMutate().Do(context.Background()).Decode(&resp)
if err != nil {
	// Handle error.
}
fmt.Printf("Created a %v star review: %v\n", m.CreateReview.Stars, m.CreateReview.Commentary)

// Output:
// Created a 5 star review: This is a great movie!
Subscription

For example, to make the following GraphQL query:

subscription {
	me {
		name
	}
}

You can define this graphql request:

req := NewGraphRequest(`
    subscription {
        me {
            name
        }
    }
`, nil)

You also need to define the struct:

type Me struct {
    Name          string
}
type Response struct {
    Me Me
}

Then run subscribe, passing a pointer to it:

subscribe := client.Body(req).Subscription()
go subscribe.Run(context.Background())
defer subscribe.Stop()
for {
    decoder := <-subscribe.ResultChan()
    var resp Response
    err := decoder.Decode(&resp)
    if err != nil {
        // Handle error.
    return
    }
}

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Client

type Client struct {
	// contains filtered or unexported fields
}

func NewClient

func NewClient(rawURL string) (*Client, error)

func (*Client) Body

func (c *Client) Body(req *GraphRequest) *Client

func (*Client) Header

func (c *Client) Header(header map[string]string) *Client

func (*Client) QueryOrMutate

func (c *Client) QueryOrMutate() QueryOrMutate

func (*Client) SetOperationName

func (c *Client) SetOperationName(name string) *Client

func (*Client) Subscription

func (c *Client) Subscription() Subscription

type Decoder

type Decoder interface {
	Decode(v interface{}) error
}

type Event

type Event interface {
	Message() *SubscribeMessage
	Error() *SubscribeError
}

type GraphError

type GraphError struct {
	Message string `json:"message"`
}

func (GraphError) Error

func (ge GraphError) Error() string

type GraphRequest

type GraphRequest struct {
	Query     string                 `json:"query"`
	Variables map[string]interface{} `json:"variables,omitempty"`
	// OperationName is only required if multiple operations are present in the query.
	OperationName string `json:"operationName,omitempty"`
}

GraphRequest is a standard GraphQL POST request https://graphql.org/learn/serving-over-http/#post-request

func NewGraphRequest

func NewGraphRequest(query string, variables map[string]any) *GraphRequest

type GraphResponse

type GraphResponse struct {
	Data   json.RawMessage `json:"data"`
	Errors []GraphError    `json:"errors"`
}

GraphResponse is a standard GraphQL response https://graphql.org/learn/serving-over-http/#response

func (*GraphResponse) Decode

func (gr *GraphResponse) Decode(v interface{}) error

type Interface

type Interface interface {
	QueryOrMutate() QueryOrMutate
	Subscription() Subscription
}

type Query

type Query struct {
	// contains filtered or unexported fields
}

func (*Query) Do

func (q *Query) Do(ctx context.Context) Decoder

type QueryOrMutate

type QueryOrMutate interface {
	Do(ctx context.Context) Decoder
}

type Subscribe

type Subscribe struct {
	// contains filtered or unexported fields
}

func (*Subscribe) Init

func (s *Subscribe) Init(ctx context.Context) error

func (*Subscribe) ResultChan

func (s *Subscribe) ResultChan() <-chan Decoder

func (*Subscribe) Run

func (s *Subscribe) Run(ctx context.Context)

func (*Subscribe) Stop

func (s *Subscribe) Stop()

type SubscribeError

type SubscribeError struct {
	Code   websocket.StatusCode
	Reason string
}

func (*SubscribeError) Error

func (s *SubscribeError) Error() string

type SubscribeEvent

type SubscribeEvent struct {
	// contains filtered or unexported fields
}

func (*SubscribeEvent) Error

func (s *SubscribeEvent) Error() *SubscribeError

func (*SubscribeEvent) Message

func (s *SubscribeEvent) Message() *SubscribeMessage

type SubscribeMessage

type SubscribeMessage struct {
	ID      string               `json:"id,omitempty"`
	Type    SubscribeMessageType `json:"type"`
	Payload json.RawMessage      `json:"payload,omitempty"`
}

SubscribeMessage represents a subscription operation message graphql-ws: https://github.com/enisdenjo/graphql-ws/blob/master/PROTOCOL.md

func (*SubscribeMessage) Decode

func (sm *SubscribeMessage) Decode(v interface{}) error

type SubscribeMessageType

type SubscribeMessageType string

SubscribeMessageType represents a subscription message enum type

const (
	// GQLConnectionInit Direction: Client -> Server
	// Indicates that the client wants to establish a connection within the existing socket.
	// This connection is not the actual WebSocket communication channel, but is rather a frame within it asking the server to allow future operation requests.
	GQLConnectionInit SubscribeMessageType = "connection_init"

	// GQLConnectionAck Direction: Server -> Client
	// Expected response to the ConnectionInit message from the client acknowledging a successful connection with the server.
	GQLConnectionAck SubscribeMessageType = "connection_ack"

	// GQLPing Direction: bidirectional
	// The Ping message can be sent at any time within the established socket.
	GQLPing SubscribeMessageType = "ping"

	// GQLPong Direction: bidirectional
	// The response to the Ping message. Must be sent as soon as the Ping message is received.
	GQLPong SubscribeMessageType = "pong"

	// GQLSubscribe Direction: Client -> Server
	// Requests an operation specified in the message payload. This message provides a unique ID field to connect published messages to the operation requested by this message.
	GQLSubscribe SubscribeMessageType = "subscribe"

	// GQLNext Direction: Server -> Client
	// Operation execution result(s) from the source stream created by the binding Subscribe message. After all results have been emitted, the Complete message will follow indicating stream completion.
	GQLNext SubscribeMessageType = "next"

	// GQLError Direction: Server -> Client
	// Operation execution error(s) in response to the Subscribe message.
	// This can occur before execution starts, usually due to validation errors, or during the execution of the request.
	GQLError SubscribeMessageType = "error"

	// GQLComplete Direction: bidirectional
	// indicates that the requested operation execution has completed. If the server dispatched the Error message relative to the original Subscribe message, no Complete message will be emitted.
	GQLComplete SubscribeMessageType = "complete"

	// GQLInvalidMessage Direction: bidirectional
	// Receiving a message of a type or format which is not specified in this document will result in an immediate socket closure with the event 4400: <error-message>. The <error-message> can be vaguely descriptive on why the received message is invalid.
	GQLInvalidMessage SubscribeMessageType = "invalid message"
)

type Subscription

type Subscription interface {
	Run(ctx context.Context)
	Stop()
	ResultChan() <-chan Decoder
}

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL