...
1 package graphql
2
3 import (
4 "bytes"
5 "context"
6 "encoding/json"
7 "fmt"
8 "io/ioutil"
9 "net/http"
10
11 "github.com/shurcooL/graphql/internal/jsonutil"
12 "golang.org/x/net/context/ctxhttp"
13 )
14
15
16 type Client struct {
17 url string
18 httpClient *http.Client
19 }
20
21
22
23 func NewClient(url string, httpClient *http.Client) *Client {
24 if httpClient == nil {
25 httpClient = http.DefaultClient
26 }
27 return &Client{
28 url: url,
29 httpClient: httpClient,
30 }
31 }
32
33
34
35
36 func (c *Client) Query(ctx context.Context, q interface{}, variables map[string]interface{}) error {
37 return c.do(ctx, queryOperation, q, variables)
38 }
39
40
41
42
43 func (c *Client) Mutate(ctx context.Context, m interface{}, variables map[string]interface{}) error {
44 return c.do(ctx, mutationOperation, m, variables)
45 }
46
47
48 func (c *Client) do(ctx context.Context, op operationType, v interface{}, variables map[string]interface{}) error {
49 var query string
50 switch op {
51 case queryOperation:
52 query = constructQuery(v, variables)
53 case mutationOperation:
54 query = constructMutation(v, variables)
55 }
56 in := struct {
57 Query string `json:"query"`
58 Variables map[string]interface{} `json:"variables,omitempty"`
59 }{
60 Query: query,
61 Variables: variables,
62 }
63 var buf bytes.Buffer
64 err := json.NewEncoder(&buf).Encode(in)
65 if err != nil {
66 return err
67 }
68 resp, err := ctxhttp.Post(ctx, c.httpClient, c.url, "application/json", &buf)
69 if err != nil {
70 return err
71 }
72 defer resp.Body.Close()
73 if resp.StatusCode != http.StatusOK {
74 body, _ := ioutil.ReadAll(resp.Body)
75 return fmt.Errorf("non-200 OK status code: %v body: %q", resp.Status, body)
76 }
77 var out struct {
78 Data *json.RawMessage
79 Errors errors
80
81 }
82 err = json.NewDecoder(resp.Body).Decode(&out)
83 if err != nil {
84
85 return err
86 }
87 if out.Data != nil {
88 err := jsonutil.UnmarshalGraphQL(*out.Data, v)
89 if err != nil {
90
91 return err
92 }
93 }
94 if len(out.Errors) > 0 {
95 return out.Errors
96 }
97 return nil
98 }
99
100
101
102
103
104 type errors []struct {
105 Message string
106 Locations []struct {
107 Line int
108 Column int
109 }
110 }
111
112
113 func (e errors) Error() string {
114 return e[0].Message
115 }
116
117 type operationType uint8
118
119 const (
120 queryOperation operationType = iota
121 mutationOperation
122
123 )
124
View as plain text