1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
|
graphql
=======
[![Build Status](https://travis-ci.org/shurcooL/graphql.svg?branch=master)](https://travis-ci.org/shurcooL/graphql) [![GoDoc](https://godoc.org/github.com/shurcooL/graphql?status.svg)](https://godoc.org/github.com/shurcooL/graphql)
Package `graphql` provides a GraphQL client implementation.
For more information, see package [`github.com/shurcooL/githubv4`](https://github.com/shurcooL/githubv4), which is a specialized version targeting GitHub GraphQL API v4. That package is driving the feature development.
**Status:** In active early research and development. The API will change when opportunities for improvement are discovered; it is not yet frozen.
Installation
------------
`graphql` requires Go version 1.8 or later.
```bash
go get -u github.com/shurcooL/graphql
```
Usage
-----
Construct a GraphQL client, specifying the GraphQL server URL. Then, you can use it to make GraphQL queries and mutations.
```Go
client := graphql.NewClient("https://example.com/graphql", nil)
// Use client...
```
### Authentication
Some GraphQL servers may require authentication. The `graphql` package does not directly handle authentication. Instead, when creating a new client, you're expected to pass an `http.Client` that performs authentication. The easiest and recommended way to do this is to use the [`golang.org/x/oauth2`](https://golang.org/x/oauth2) package. You'll need an OAuth token with the right scopes. Then:
```Go
import "golang.org/x/oauth2"
func main() {
src := oauth2.StaticTokenSource(
&oauth2.Token{AccessToken: os.Getenv("GRAPHQL_TOKEN")},
)
httpClient := oauth2.NewClient(context.Background(), src)
client := graphql.NewClient("https://example.com/graphql", httpClient)
// Use client...
```
### Simple Query
To make a GraphQL query, you need to define a corresponding Go type.
For example, to make the following GraphQL query:
```GraphQL
query {
me {
name
}
}
```
You can define this variable:
```Go
var query struct {
Me struct {
Name graphql.String
}
}
```
Then call `client.Query`, passing a pointer to it:
```Go
err := client.Query(context.Background(), &query, nil)
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. You can use the `graphql` struct field tag for this.
For example, to make the following GraphQL query:
```GraphQL
{
human(id: "1000") {
name
height(unit: METER)
}
}
```
You can define this variable:
```Go
var q struct {
Human struct {
Name graphql.String
Height graphql.Float `graphql:"height(unit: METER)"`
} `graphql:"human(id: \"1000\")"`
}
```
Then call `client.Query`:
```Go
err := client.Query(context.Background(), &q, nil)
if err != nil {
// Handle error.
}
fmt.Println(q.Human.Name)
fmt.Println(q.Human.Height)
// Output:
// Luke Skywalker
// 1.72
```
However, that'll only work if the arguments are constant and known in advance. Otherwise, you will need to make use of variables. Replace the constants in the struct field tag with variable names:
```Go
var q struct {
Human struct {
Name graphql.String
Height graphql.Float `graphql:"height(unit: $unit)"`
} `graphql:"human(id: $id)"`
}
```
Then, define a `variables` map with their values:
```Go
variables := map[string]interface{}{
"id": graphql.ID(id),
"unit": starwars.LengthUnit("METER"),
}
```
Finally, call `client.Query` providing `variables`:
```Go
err := client.Query(context.Background(), &q, variables)
if err != nil {
// Handle error.
}
```
### Inline Fragments
Some GraphQL queries contain inline fragments. You can use the `graphql` struct field tag to express them.
For example, to make the following GraphQL query:
```GraphQL
{
hero(episode: "JEDI") {
name
... on Droid {
primaryFunction
}
... on Human {
height
}
}
}
```
You can define this variable:
```Go
var q struct {
Hero struct {
Name graphql.String
Droid struct {
PrimaryFunction graphql.String
} `graphql:"... on Droid"`
Human struct {
Height graphql.Float
} `graphql:"... on Human"`
} `graphql:"hero(episode: \"JEDI\")"`
}
```
Alternatively, you can define the struct types corresponding to inline fragments, and use them as embedded fields in your query:
```Go
type (
DroidFragment struct {
PrimaryFunction graphql.String
}
HumanFragment struct {
Height graphql.Float
}
)
var q struct {
Hero struct {
Name graphql.String
DroidFragment `graphql:"... on Droid"`
HumanFragment `graphql:"... on Human"`
} `graphql:"hero(episode: \"JEDI\")"`
}
```
Then call `client.Query`:
```Go
err := client.Query(context.Background(), &q, nil)
if err != nil {
// Handle error.
}
fmt.Println(q.Hero.Name)
fmt.Println(q.Hero.PrimaryFunction)
fmt.Println(q.Hero.Height)
// Output:
// R2-D2
// Astromech
// 0
```
### 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:
```GraphQL
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:
```Go
var m struct {
CreateReview struct {
Stars graphql.Int
Commentary graphql.String
} `graphql:"createReview(episode: $ep, review: $review)"`
}
variables := map[string]interface{}{
"ep": starwars.Episode("JEDI"),
"review": starwars.ReviewInput{
Stars: graphql.Int(5),
Commentary: graphql.String("This is a great movie!"),
},
}
```
Then call `client.Mutate`:
```Go
err := client.Mutate(context.Background(), &m, variables)
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!
```
Directories
-----------
| Path | Synopsis |
|----------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------|
| [example/graphqldev](https://godoc.org/github.com/shurcooL/graphql/example/graphqldev) | graphqldev is a test program currently being used for developing graphql package. |
| [ident](https://godoc.org/github.com/shurcooL/graphql/ident) | Package ident provides functions for parsing and converting identifier names between various naming convention. |
| [internal/jsonutil](https://godoc.org/github.com/shurcooL/graphql/internal/jsonutil) | Package jsonutil provides a function for decoding JSON into a GraphQL query data structure. |
License
-------
- [MIT License](LICENSE)
|