1graphql
2=======
3
4Package `graphql` provides a GraphQL client implementation, and is forked from `https://github.com/shurcooL/graphql`.
5
6Installation
7------------
8
9```bash
10go get -u github.com/cli/shurcooL-graphql
11```
12
13Usage
14-----
15
16Construct a GraphQL client, specifying the GraphQL server URL. Then, you can use it to make GraphQL queries and mutations.
17
18```Go
19client := graphql.NewClient("https://example.com/graphql", nil)
20// Use client...
21```
22
23### Authentication
24
25Some 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:
26
27```Go
28import "golang.org/x/oauth2"
29
30func main() {
31 src := oauth2.StaticTokenSource(
32 &oauth2.Token{AccessToken: os.Getenv("GRAPHQL_TOKEN")},
33 )
34 httpClient := oauth2.NewClient(context.Background(), src)
35
36 client := graphql.NewClient("https://example.com/graphql", httpClient)
37 // Use client...
38```
39
40### Simple Query
41
42To make a GraphQL query, you need to define a corresponding Go type.
43
44For example, to make the following GraphQL query:
45
46```GraphQL
47query {
48 me {
49 name
50 }
51}
52```
53
54You can define this variable:
55
56```Go
57var query struct {
58 Me struct {
59 Name graphql.String
60 }
61}
62```
63
64Then call `client.Query`, passing a pointer to it:
65
66```Go
67err := client.Query(context.Background(), &query, nil)
68if err != nil {
69 // Handle error.
70}
71fmt.Println(query.Me.Name)
72
73// Output: Luke Skywalker
74```
75
76### Arguments and Variables
77
78Often, you'll want to specify arguments on some fields. You can use the `graphql` struct field tag for this.
79
80For example, to make the following GraphQL query:
81
82```GraphQL
83{
84 human(id: "1000") {
85 name
86 height(unit: METER)
87 }
88}
89```
90
91You can define this variable:
92
93```Go
94var q struct {
95 Human struct {
96 Name graphql.String
97 Height graphql.Float `graphql:"height(unit: METER)"`
98 } `graphql:"human(id: \"1000\")"`
99}
100```
101
102Then call `client.Query`:
103
104```Go
105err := client.Query(context.Background(), &q, nil)
106if err != nil {
107 // Handle error.
108}
109fmt.Println(q.Human.Name)
110fmt.Println(q.Human.Height)
111
112// Output:
113// Luke Skywalker
114// 1.72
115```
116
117However, 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:
118
119```Go
120var q struct {
121 Human struct {
122 Name graphql.String
123 Height graphql.Float `graphql:"height(unit: $unit)"`
124 } `graphql:"human(id: $id)"`
125}
126```
127
128Then, define a `variables` map with their values:
129
130```Go
131variables := map[string]any{
132 "id": graphql.ID(id),
133 "unit": starwars.LengthUnit("METER"),
134}
135```
136
137Finally, call `client.Query` providing `variables`:
138
139```Go
140err := client.Query(context.Background(), &q, variables)
141if err != nil {
142 // Handle error.
143}
144```
145
146### Inline Fragments
147
148Some GraphQL queries contain inline fragments. You can use the `graphql` struct field tag to express them.
149
150For example, to make the following GraphQL query:
151
152```GraphQL
153{
154 hero(episode: "JEDI") {
155 name
156 ... on Droid {
157 primaryFunction
158 }
159 ... on Human {
160 height
161 }
162 }
163}
164```
165
166You can define this variable:
167
168```Go
169var q struct {
170 Hero struct {
171 Name graphql.String
172 Droid struct {
173 PrimaryFunction graphql.String
174 } `graphql:"... on Droid"`
175 Human struct {
176 Height graphql.Float
177 } `graphql:"... on Human"`
178 } `graphql:"hero(episode: \"JEDI\")"`
179}
180```
181
182Alternatively, you can define the struct types corresponding to inline fragments, and use them as embedded fields in your query:
183
184```Go
185type (
186 DroidFragment struct {
187 PrimaryFunction graphql.String
188 }
189 HumanFragment struct {
190 Height graphql.Float
191 }
192)
193
194var q struct {
195 Hero struct {
196 Name graphql.String
197 DroidFragment `graphql:"... on Droid"`
198 HumanFragment `graphql:"... on Human"`
199 } `graphql:"hero(episode: \"JEDI\")"`
200}
201```
202
203Then call `client.Query`:
204
205```Go
206err := client.Query(context.Background(), &q, nil)
207if err != nil {
208 // Handle error.
209}
210fmt.Println(q.Hero.Name)
211fmt.Println(q.Hero.PrimaryFunction)
212fmt.Println(q.Hero.Height)
213
214// Output:
215// R2-D2
216// Astromech
217// 0
218```
219
220### Mutations
221
222Mutations often require information that you can only find out by performing a query first. Let's suppose you've already done that.
223
224For example, to make the following GraphQL mutation:
225
226```GraphQL
227mutation($ep: Episode!, $review: ReviewInput!) {
228 createReview(episode: $ep, review: $review) {
229 stars
230 commentary
231 }
232}
233variables {
234 "ep": "JEDI",
235 "review": {
236 "stars": 5,
237 "commentary": "This is a great movie!"
238 }
239}
240```
241
242You can define:
243
244```Go
245var m struct {
246 CreateReview struct {
247 Stars graphql.Int
248 Commentary graphql.String
249 } `graphql:"createReview(episode: $ep, review: $review)"`
250}
251variables := map[string]any{
252 "ep": starwars.Episode("JEDI"),
253 "review": starwars.ReviewInput{
254 Stars: graphql.Int(5),
255 Commentary: graphql.String("This is a great movie!"),
256 },
257}
258```
259
260Then call `client.Mutate`:
261
262```Go
263err := client.Mutate(context.Background(), &m, variables)
264if err != nil {
265 // Handle error.
266}
267fmt.Printf("Created a %v star review: %v\n", m.CreateReview.Stars, m.CreateReview.Commentary)
268
269// Output:
270// Created a 5 star review: This is a great movie!
271```
272
273License
274-------
275
276- [MIT License](LICENSE)
View as plain text