• Home
  • History
  • Annotate
Name Date Size #Lines LOC

..21-Jan-2021-

.travis.ymlH A D21-Jan-2021386 1716

LICENSEH A D21-Jan-20211 KiB2217

README.mdH A D21-Jan-202111.2 KiB414329

doc.goH A D21-Jan-2021383 111

enum.goH A D21-Jan-202193.5 KiB1,381870

githubv4.goH A D21-Jan-20211.9 KiB5730

input.goH A D21-Jan-202188.9 KiB1,847861

scalar.goH A D21-Jan-20214.3 KiB14056

README.md

1githubv4
2========
3
4[![Build Status](https://travis-ci.org/shurcooL/githubv4.svg?branch=master)](https://travis-ci.org/shurcooL/githubv4) [![GoDoc](https://godoc.org/github.com/shurcooL/githubv4?status.svg)](https://godoc.org/github.com/shurcooL/githubv4)
5
6Package `githubv4` is a client library for accessing GitHub GraphQL API v4 (https://docs.github.com/en/graphql).
7
8If you're looking for a client library for GitHub REST API v3, the recommended package is [`github.com/google/go-github/github`](https://godoc.org/github.com/google/go-github/github).
9
10Focus
11-----
12
13-	Friendly, simple and powerful API.
14-	Correctness, high performance and efficiency.
15-	Support all of GitHub GraphQL API v4 via code generation from schema.
16
17Installation
18------------
19
20`githubv4` requires Go version 1.8 or later.
21
22```bash
23go get -u github.com/shurcooL/githubv4
24```
25
26Usage
27-----
28
29### Authentication
30
31GitHub GraphQL API v4 [requires authentication](https://docs.github.com/en/graphql/guides/forming-calls-with-graphql#authenticating-with-graphql). The `githubv4` 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 from GitHub (for example, a [personal API token](https://help.github.com/articles/creating-a-personal-access-token-for-the-command-line/)) with the right scopes. Then:
32
33```Go
34import "golang.org/x/oauth2"
35
36func main() {
37	src := oauth2.StaticTokenSource(
38		&oauth2.Token{AccessToken: os.Getenv("GITHUB_TOKEN")},
39	)
40	httpClient := oauth2.NewClient(context.Background(), src)
41
42	client := githubv4.NewClient(httpClient)
43	// Use client...
44}
45```
46
47If you are using GitHub Enterprise, use [`githubv4.NewEnterpriseClient`](https://godoc.org/github.com/shurcooL/githubv4#NewEnterpriseClient):
48
49```Go
50client := githubv4.NewEnterpriseClient(os.Getenv("GITHUB_ENDPOINT"), httpClient)
51// Use client...
52```
53
54### Simple Query
55
56To make a query, you need to define a Go type that corresponds to the GitHub GraphQL schema, and contains the fields you're interested in querying. You can look up the GitHub GraphQL schema at https://docs.github.com/en/graphql/reference/queries.
57
58For example, to make the following GraphQL query:
59
60```GraphQL
61query {
62	viewer {
63		login
64		createdAt
65	}
66}
67```
68
69You can define this variable:
70
71```Go
72var query struct {
73	Viewer struct {
74		Login     githubv4.String
75		CreatedAt githubv4.DateTime
76	}
77}
78```
79
80Then call `client.Query`, passing a pointer to it:
81
82```Go
83err := client.Query(context.Background(), &query, nil)
84if err != nil {
85	// Handle error.
86}
87fmt.Println("    Login:", query.Viewer.Login)
88fmt.Println("CreatedAt:", query.Viewer.CreatedAt)
89
90// Output:
91//     Login: gopher
92// CreatedAt: 2017-05-26 21:17:14 +0000 UTC
93```
94
95### Scalar Types
96
97For each scalar in the GitHub GraphQL schema listed at https://docs.github.com/en/graphql/reference/scalars, there is a corresponding Go type in package `githubv4`.
98
99You can use these types when writing queries:
100
101```Go
102var query struct {
103	Viewer struct {
104		Login          githubv4.String
105		CreatedAt      githubv4.DateTime
106		IsBountyHunter githubv4.Boolean
107		BioHTML        githubv4.HTML
108		WebsiteURL     githubv4.URI
109	}
110}
111// Call client.Query() and use results in query...
112```
113
114However, depending on how you're planning to use the results of your query, it's often more convenient to use other Go types.
115
116The `encoding/json` rules are used for converting individual JSON-encoded fields from a GraphQL response into Go values. See https://godoc.org/encoding/json#Unmarshal for details. The [`json.Unmarshaler`](https://godoc.org/encoding/json#Unmarshaler) interface is respected.
117
118That means you can simplify the earlier query by using predeclared Go types:
119
120```Go
121// import "time"
122
123var query struct {
124	Viewer struct {
125		Login          string    // E.g., "gopher".
126		CreatedAt      time.Time // E.g., time.Date(2017, 5, 26, 21, 17, 14, 0, time.UTC).
127		IsBountyHunter bool      // E.g., true.
128		BioHTML        string    // E.g., `I am learning <a href="https://graphql.org">GraphQL</a>!`.
129		WebsiteURL     string    // E.g., "https://golang.org".
130	}
131}
132// Call client.Query() and use results in query...
133```
134
135The [`DateTime`](https://docs.github.com/en/graphql/reference/scalars#datetime) scalar is described as "an ISO-8601 encoded UTC date string". If you wanted to fetch in that form without parsing it into a `time.Time`, you can use the `string` type. For example, this would work:
136
137```Go
138// import "html/template"
139
140type MyBoolean bool
141
142var query struct {
143	Viewer struct {
144		Login          string        // E.g., "gopher".
145		CreatedAt      string        // E.g., "2017-05-26T21:17:14Z".
146		IsBountyHunter MyBoolean     // E.g., MyBoolean(true).
147		BioHTML        template.HTML // E.g., template.HTML(`I am learning <a href="https://graphql.org">GraphQL</a>!`).
148		WebsiteURL     template.URL  // E.g., template.URL("https://golang.org").
149	}
150}
151// Call client.Query() and use results in query...
152```
153
154### Arguments and Variables
155
156Often, you'll want to specify arguments on some fields. You can use the `graphql` struct field tag for this.
157
158For example, to make the following GraphQL query:
159
160```GraphQL
161{
162	repository(owner: "octocat", name: "Hello-World") {
163		description
164	}
165}
166```
167
168You can define this variable:
169
170```Go
171var q struct {
172	Repository struct {
173		Description string
174	} `graphql:"repository(owner: \"octocat\", name: \"Hello-World\")"`
175}
176```
177
178Then call `client.Query`:
179
180```Go
181err := client.Query(context.Background(), &q, nil)
182if err != nil {
183	// Handle error.
184}
185fmt.Println(q.Repository.Description)
186
187// Output:
188// My first repository on GitHub!
189```
190
191However, 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:
192
193```Go
194// fetchRepoDescription fetches description of repo with owner and name.
195func fetchRepoDescription(ctx context.Context, owner, name string) (string, error) {
196	var q struct {
197		Repository struct {
198			Description string
199		} `graphql:"repository(owner: $owner, name: $name)"`
200	}
201```
202
203When sending variables to GraphQL, you need to use exact types that match GraphQL scalar types, otherwise the GraphQL server will return an error.
204
205So, define a `variables` map with their values that are converted to GraphQL scalar types:
206
207```Go
208	variables := map[string]interface{}{
209		"owner": githubv4.String(owner),
210		"name":  githubv4.String(name),
211	}
212```
213
214Finally, call `client.Query` providing `variables`:
215
216```Go
217	err := client.Query(ctx, &q, variables)
218	return q.Repository.Description, err
219}
220```
221
222### Inline Fragments
223
224Some GraphQL queries contain inline fragments. You can use the `graphql` struct field tag to express them.
225
226For example, to make the following GraphQL query:
227
228```GraphQL
229{
230	repositoryOwner(login: "github") {
231		login
232		... on Organization {
233			description
234		}
235		... on User {
236			bio
237		}
238	}
239}
240```
241
242You can define this variable:
243
244```Go
245var q struct {
246	RepositoryOwner struct {
247		Login        string
248		Organization struct {
249			Description string
250		} `graphql:"... on Organization"`
251		User struct {
252			Bio string
253		} `graphql:"... on User"`
254	} `graphql:"repositoryOwner(login: \"github\")"`
255}
256```
257
258Alternatively, you can define the struct types corresponding to inline fragments, and use them as embedded fields in your query:
259
260```Go
261type (
262	OrganizationFragment struct {
263		Description string
264	}
265	UserFragment struct {
266		Bio string
267	}
268)
269
270var q struct {
271	RepositoryOwner struct {
272		Login                string
273		OrganizationFragment `graphql:"... on Organization"`
274		UserFragment         `graphql:"... on User"`
275	} `graphql:"repositoryOwner(login: \"github\")"`
276}
277```
278
279Then call `client.Query`:
280
281```Go
282err := client.Query(context.Background(), &q, nil)
283if err != nil {
284	// Handle error.
285}
286fmt.Println(q.RepositoryOwner.Login)
287fmt.Println(q.RepositoryOwner.Description)
288fmt.Println(q.RepositoryOwner.Bio)
289
290// Output:
291// github
292// How people build software.
293//
294```
295
296### Pagination
297
298Imagine you wanted to get a complete list of comments in an issue, and not just the first 10 or so. To do that, you'll need to perform multiple queries and use pagination information. For example:
299
300```Go
301type comment struct {
302	Body   string
303	Author struct {
304		Login     string
305		AvatarURL string `graphql:"avatarUrl(size: 72)"`
306	}
307	ViewerCanReact bool
308}
309var q struct {
310	Repository struct {
311		Issue struct {
312			Comments struct {
313				Nodes    []comment
314				PageInfo struct {
315					EndCursor   githubv4.String
316					HasNextPage bool
317				}
318			} `graphql:"comments(first: 100, after: $commentsCursor)"` // 100 per page.
319		} `graphql:"issue(number: $issueNumber)"`
320	} `graphql:"repository(owner: $repositoryOwner, name: $repositoryName)"`
321}
322variables := map[string]interface{}{
323	"repositoryOwner": githubv4.String(owner),
324	"repositoryName":  githubv4.String(name),
325	"issueNumber":     githubv4.Int(issue),
326	"commentsCursor":  (*githubv4.String)(nil), // Null after argument to get first page.
327}
328
329// Get comments from all pages.
330var allComments []comment
331for {
332	err := s.clQL.Query(ctx, &q, variables)
333	if err != nil {
334		return err
335	}
336	allComments = append(allComments, q.Repository.Issue.Comments.Nodes...)
337	if !q.Repository.Issue.Comments.PageInfo.HasNextPage {
338		break
339	}
340	variables["commentsCursor"] = githubv4.NewString(q.Repository.Issue.Comments.PageInfo.EndCursor)
341}
342```
343
344There is more than one way to perform pagination. Consider additional fields inside [`PageInfo`](https://docs.github.com/en/graphql/reference/objects#pageinfo) object.
345
346### Mutations
347
348Mutations often require information that you can only find out by performing a query first. Let's suppose you've already done that.
349
350For example, to make the following GraphQL mutation:
351
352```GraphQL
353mutation($input: AddReactionInput!) {
354	addReaction(input: $input) {
355		reaction {
356			content
357		}
358		subject {
359			id
360		}
361	}
362}
363variables {
364	"input": {
365		"subjectId": "MDU6SXNzdWUyMTc5NTQ0OTc=",
366		"content": "HOORAY"
367	}
368}
369```
370
371You can define:
372
373```Go
374var m struct {
375	AddReaction struct {
376		Reaction struct {
377			Content githubv4.ReactionContent
378		}
379		Subject struct {
380			ID githubv4.ID
381		}
382	} `graphql:"addReaction(input: $input)"`
383}
384input := githubv4.AddReactionInput{
385	SubjectID: targetIssue.ID, // ID of the target issue from a previous query.
386	Content:   githubv4.ReactionContentHooray,
387}
388```
389
390Then call `client.Mutate`:
391
392```Go
393err := client.Mutate(context.Background(), &m, input, nil)
394if err != nil {
395	// Handle error.
396}
397fmt.Printf("Added a %v reaction to subject with ID %#v!\n", m.AddReaction.Reaction.Content, m.AddReaction.Subject.ID)
398
399// Output:
400// Added a HOORAY reaction to subject with ID "MDU6SXNzdWUyMTc5NTQ0OTc="!
401```
402
403Directories
404-----------
405
406| Path                                                                                      | Synopsis                                                                            |
407|-------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------|
408| [example/githubv4dev](https://godoc.org/github.com/shurcooL/githubv4/example/githubv4dev) | githubv4dev is a test program currently being used for developing githubv4 package. |
409
410License
411-------
412
413-	[MIT License](LICENSE)
414