Convert Figma logo to code with AI

shurcooL logogithubv4

Package githubv4 is a client library for accessing GitHub GraphQL API v4 (https://docs.github.com/en/graphql).

1,106
89
1,106
41

Top Related Projects

Ruby toolkit for the GitHub API

10,287

Go library for accessing the GitHub v3 API

Typed interactions with the GitHub API v3

37,027

GitHub’s official command line tool

The all-batteries-included GitHub SDK for Browsers, Node.js, and Deno.

Quick Overview

shurcooL/githubv4 is a Go client library for accessing the GitHub GraphQL API v4. It provides a strongly typed and user-friendly interface for interacting with GitHub's GraphQL API, allowing developers to easily integrate GitHub functionality into their Go applications.

Pros

  • Strongly typed: Provides compile-time type checking for GraphQL queries
  • Auto-generated: The library is automatically generated from GitHub's GraphQL schema, ensuring up-to-date coverage
  • Efficient: Uses GraphQL, which allows for more precise and efficient data fetching compared to REST APIs
  • Well-documented: Includes clear documentation and examples for easy integration

Cons

  • Learning curve: Requires understanding of GraphQL concepts and syntax
  • Limited to GitHub: Only works with GitHub's API, not applicable for other GraphQL services
  • Dependency management: Relies on external dependencies, which may require additional maintenance
  • API changes: GitHub's GraphQL API may change, potentially requiring updates to the library

Code Examples

  1. Authenticating and creating a client:
import (
    "context"
    "github.com/shurcooL/githubv4"
    "golang.org/x/oauth2"
)

func createClient() *githubv4.Client {
    src := oauth2.StaticTokenSource(
        &oauth2.Token{AccessToken: "your-access-token"},
    )
    httpClient := oauth2.NewClient(context.Background(), src)
    return githubv4.NewClient(httpClient)
}
  1. Querying repository information:
func getRepoInfo(client *githubv4.Client, owner, name string) (string, int, error) {
    var query struct {
        Repository struct {
            Description githubv4.String
            StargazerCount githubv4.Int
        } `graphql:"repository(owner: $owner, name: $name)"`
    }
    variables := map[string]interface{}{
        "owner": githubv4.String(owner),
        "name":  githubv4.String(name),
    }
    err := client.Query(context.Background(), &query, variables)
    return string(query.Repository.Description), int(query.Repository.StargazerCount), err
}
  1. Creating an issue:
func createIssue(client *githubv4.Client, owner, repo, title, body string) (string, error) {
    var mutation struct {
        CreateIssue struct {
            Issue struct {
                URL githubv4.String
            }
        } `graphql:"createIssue(input: $input)"`
    }
    input := githubv4.CreateIssueInput{
        RepositoryID: githubv4.ID(owner + "/" + repo),
        Title:        githubv4.String(title),
        Body:         githubv4.NewString(githubv4.String(body)),
    }
    err := client.Mutate(context.Background(), &mutation, input, nil)
    return string(mutation.CreateIssue.Issue.URL), err
}

Getting Started

  1. Install the library:

    go get github.com/shurcooL/githubv4
    
  2. Import the library in your Go code:

    import "github.com/shurcooL/githubv4"
    
  3. Create a client with your GitHub access token:

    src := oauth2.StaticTokenSource(
        &oauth2.Token{AccessToken: "your-access-token"},
    )
    httpClient := oauth2.NewClient(context.Background(), src)
    client := githubv4.NewClient(httpClient)
    
  4. Start making queries or mutations using the client.

Competitor Comparisons

Ruby toolkit for the GitHub API

Pros of octokit.rb

  • Written in Ruby, making it ideal for Ruby-based projects and integrations
  • Comprehensive support for GitHub REST API v3
  • Well-established library with a large community and extensive documentation

Cons of octokit.rb

  • Limited support for GitHub GraphQL API v4
  • May have performance limitations compared to GraphQL-based solutions
  • Potentially more verbose code for complex queries

Code Comparison

octokit.rb (REST API):

client = Octokit::Client.new(access_token: 'your_token')
repo = client.repository('octokit/octokit.rb')
issues = client.issues('octokit/octokit.rb')

githubv4 (GraphQL API):

var query struct {
    Repository struct {
        Issues struct {
            Nodes []struct {
                Title string
            }
        } `graphql:"issues(first: 10)"`
    } `graphql:"repository(owner: \"octokit\", name: \"octokit.rb\")"`
}
client.Query(context.Background(), &query, nil)

The githubv4 library offers a more efficient way to fetch specific data in a single request, while octokit.rb may require multiple API calls for complex data retrieval. However, octokit.rb provides a simpler interface for basic operations and is more suitable for Ruby developers.

10,287

Go library for accessing the GitHub v3 API

Pros of go-github

  • More comprehensive coverage of GitHub API endpoints
  • Well-established and widely used in the Go community
  • Extensive documentation and examples

Cons of go-github

  • Uses GitHub API v3 (REST), which can be less efficient for complex queries
  • Requires more boilerplate code for certain operations
  • May require multiple API calls for related data

Code Comparison

go-github:

client := github.NewClient(nil)
repo, _, err := client.Repositories.Get(ctx, "owner", "repo")
if err != nil {
    // Handle error
}

githubv4:

var query struct {
    Repository struct {
        Name string
    } `graphql:"repository(owner: $owner, name: $name)"`
}
variables := map[string]interface{}{
    "owner": githubv4.String("owner"),
    "name":  githubv4.String("repo"),
}
err := client.Query(ctx, &query, variables)

Key Differences

  • githubv4 uses GitHub's GraphQL API (v4), allowing for more efficient and flexible queries
  • go-github provides a more traditional REST API approach
  • githubv4 requires less code for complex queries but may have a steeper learning curve for those unfamiliar with GraphQL
  • go-github offers broader API coverage, while githubv4 focuses on the newer GraphQL API

Choose based on your specific needs, API familiarity, and desired query efficiency.

Typed interactions with the GitHub API v3

Pros of PyGithub

  • Supports both GitHub REST API v3 and GraphQL API v4
  • Extensive documentation and examples available
  • Large and active community with frequent updates

Cons of PyGithub

  • Primarily designed for Python, limiting language options
  • Can be more verbose for simple operations compared to githubv4

Code Comparison

PyGithub:

from github import Github
g = Github("access_token")
repo = g.get_repo("PyGithub/PyGithub")
issues = repo.get_issues(state="open")

githubv4:

var query struct {
    Repository struct {
        Issues struct {
            Nodes []struct {
                Title string
            }
        } `graphql:"issues(states: OPEN, first: 100)"`
    } `graphql:"repository(owner: \"shurcooL\", name: \"githubv4\")"`
}

PyGithub offers a more straightforward approach for simple operations, while githubv4 provides a more structured query system using GraphQL. PyGithub is more versatile in terms of API support, but githubv4 offers a more efficient way to fetch specific data using GraphQL queries. The choice between the two depends on the programming language preference and the specific requirements of the project.

37,027

GitHub’s official command line tool

Pros of cli

  • Provides a complete command-line interface for GitHub, offering a wide range of functionalities
  • Supports multiple authentication methods, including SSH keys and personal access tokens
  • Offers a user-friendly interactive mode for complex operations

Cons of cli

  • Larger codebase and more dependencies, potentially leading to longer installation times
  • May have a steeper learning curve for users unfamiliar with command-line interfaces
  • Limited to GitHub-specific operations, unlike githubv4's more flexible GraphQL approach

Code Comparison

githubv4:

var query struct {
    Repository struct {
        Issues struct {
            Nodes []struct {
                Title string
            }
        } `graphql:"issues(first: 100)"`
    } `graphql:"repository(owner: $owner, name: $name)"`
}

cli:

func issueList(cmd *cobra.Command, args []string) error {
    apiClient, err := apiClientForContext(ctx)
    if err != nil {
        return err
    }
    issues, err := api.IssueList(apiClient, repo, state, labels, assignee, limit)
    // ... (handling and output)
}

The githubv4 example shows a GraphQL query structure, while the cli example demonstrates a higher-level function for listing issues using the GitHub API.

The all-batteries-included GitHub SDK for Browsers, Node.js, and Deno.

Pros of octokit.js

  • Broader API coverage, supporting more GitHub features
  • Active development with frequent updates and community support
  • Extensive documentation and examples

Cons of octokit.js

  • Larger package size due to comprehensive feature set
  • Steeper learning curve for beginners
  • JavaScript-specific, limiting use in other languages

Code Comparison

octokit.js:

const octokit = new Octokit({ auth: 'token' });
const { data } = await octokit.rest.repos.get({
  owner: 'octokit',
  repo: 'octokit.js'
});

githubv4:

var query struct {
    Repository struct {
        Name string
    } `graphql:"repository(owner: \"shurcooL\", name: \"githubv4\")"`
}
client.Query(context.Background(), &query, nil)

The octokit.js example demonstrates REST API usage, while githubv4 showcases GraphQL query structure. octokit.js offers a more familiar JavaScript syntax, whereas githubv4 provides a strongly-typed Go implementation for GraphQL queries.

githubv4 focuses solely on GitHub's GraphQL API, making it more specialized and potentially easier to use for GraphQL-specific tasks. However, octokit.js offers greater flexibility with support for both REST and GraphQL APIs, catering to a wider range of GitHub interactions.

Convert Figma logo designs to code with AI

Visual Copilot

Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.

Try Visual Copilot

README

githubv4

Go Reference

Package githubv4 is a client library for accessing GitHub GraphQL API v4 (https://docs.github.com/en/graphql).

If you're looking for a client library for GitHub REST API v3, the recommended package is github (also known as go-github).

Focus

  • Friendly, simple and powerful API.
  • Correctness, high performance and efficiency.
  • Support all of GitHub GraphQL API v4 via code generation from schema.

Installation

go get github.com/shurcooL/githubv4

Usage

Authentication

GitHub GraphQL API v4 requires authentication. 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 package. You'll need an OAuth token from GitHub (for example, a personal API token) with the right scopes. Then:

import "golang.org/x/oauth2"

func main() {
	src := oauth2.StaticTokenSource(
		&oauth2.Token{AccessToken: os.Getenv("GITHUB_TOKEN")},
	)
	httpClient := oauth2.NewClient(context.Background(), src)

	client := githubv4.NewClient(httpClient)
	// Use client...
}

If you are using GitHub Enterprise, use githubv4.NewEnterpriseClient:

client := githubv4.NewEnterpriseClient(os.Getenv("GITHUB_ENDPOINT"), httpClient)
// Use client...

Simple Query

To 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.

For example, to make the following GraphQL query:

query {
	viewer {
		login
		createdAt
	}
}

You can define this variable:

var query struct {
	Viewer struct {
		Login     githubv4.String
		CreatedAt githubv4.DateTime
	}
}

Then call client.Query, passing a pointer to it:

err := client.Query(context.Background(), &query, nil)
if err != nil {
	// Handle error.
}
fmt.Println("    Login:", query.Viewer.Login)
fmt.Println("CreatedAt:", query.Viewer.CreatedAt)

// Output:
//     Login: gopher
// CreatedAt: 2017-05-26 21:17:14 +0000 UTC

Scalar Types

For 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.

You can use these types when writing queries:

var query struct {
	Viewer struct {
		Login          githubv4.String
		CreatedAt      githubv4.DateTime
		IsBountyHunter githubv4.Boolean
		BioHTML        githubv4.HTML
		WebsiteURL     githubv4.URI
	}
}
// Call client.Query() and use results in query...

However, depending on how you're planning to use the results of your query, it's often more convenient to use other Go types.

The 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 interface is respected.

That means you can simplify the earlier query by using predeclared Go types:

// import "time"

var query struct {
	Viewer struct {
		Login          string    // E.g., "gopher".
		CreatedAt      time.Time // E.g., time.Date(2017, 5, 26, 21, 17, 14, 0, time.UTC).
		IsBountyHunter bool      // E.g., true.
		BioHTML        string    // E.g., `I am learning <a href="https://graphql.org">GraphQL</a>!`.
		WebsiteURL     string    // E.g., "https://golang.org".
	}
}
// Call client.Query() and use results in query...

The 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:

// import "html/template"

type MyBoolean bool

var query struct {
	Viewer struct {
		Login          string        // E.g., "gopher".
		CreatedAt      string        // E.g., "2017-05-26T21:17:14Z".
		IsBountyHunter MyBoolean     // E.g., MyBoolean(true).
		BioHTML        template.HTML // E.g., template.HTML(`I am learning <a href="https://graphql.org">GraphQL</a>!`).
		WebsiteURL     template.URL  // E.g., template.URL("https://golang.org").
	}
}
// Call client.Query() and use results in query...

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:

{
	repository(owner: "octocat", name: "Hello-World") {
		description
	}
}

You can define this variable:

var q struct {
	Repository struct {
		Description string
	} `graphql:"repository(owner: \"octocat\", name: \"Hello-World\")"`
}

Then call client.Query:

err := client.Query(context.Background(), &q, nil)
if err != nil {
	// Handle error.
}
fmt.Println(q.Repository.Description)

// Output:
// My first repository on GitHub!

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:

// fetchRepoDescription fetches description of repo with owner and name.
func fetchRepoDescription(ctx context.Context, owner, name string) (string, error) {
	var q struct {
		Repository struct {
			Description string
		} `graphql:"repository(owner: $owner, name: $name)"`
	}

When sending variables to GraphQL, you need to use exact types that match GraphQL scalar types, otherwise the GraphQL server will return an error.

So, define a variables map with their values that are converted to GraphQL scalar types:

	variables := map[string]interface{}{
		"owner": githubv4.String(owner),
		"name":  githubv4.String(name),
	}

Finally, call client.Query providing variables:

	err := client.Query(ctx, &q, variables)
	return q.Repository.Description, err
}

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:

{
	repositoryOwner(login: "github") {
		login
		... on Organization {
			description
		}
		... on User {
			bio
		}
	}
}

You can define this variable:

var q struct {
	RepositoryOwner struct {
		Login        string
		Organization struct {
			Description string
		} `graphql:"... on Organization"`
		User struct {
			Bio string
		} `graphql:"... on User"`
	} `graphql:"repositoryOwner(login: \"github\")"`
}

Alternatively, you can define the struct types corresponding to inline fragments, and use them as embedded fields in your query:

type (
	OrganizationFragment struct {
		Description string
	}
	UserFragment struct {
		Bio string
	}
)

var q struct {
	RepositoryOwner struct {
		Login                string
		OrganizationFragment `graphql:"... on Organization"`
		UserFragment         `graphql:"... on User"`
	} `graphql:"repositoryOwner(login: \"github\")"`
}

Then call client.Query:

err := client.Query(context.Background(), &q, nil)
if err != nil {
	// Handle error.
}
fmt.Println(q.RepositoryOwner.Login)
fmt.Println(q.RepositoryOwner.Description)
fmt.Println(q.RepositoryOwner.Bio)

// Output:
// github
// How people build software.
//

Pagination

Imagine 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:

type comment struct {
	Body   string
	Author struct {
		Login     string
		AvatarURL string `graphql:"avatarUrl(size: 72)"`
	}
	ViewerCanReact bool
}
var q struct {
	Repository struct {
		Issue struct {
			Comments struct {
				Nodes    []comment
				PageInfo struct {
					EndCursor   githubv4.String
					HasNextPage bool
				}
			} `graphql:"comments(first: 100, after: $commentsCursor)"` // 100 per page.
		} `graphql:"issue(number: $issueNumber)"`
	} `graphql:"repository(owner: $repositoryOwner, name: $repositoryName)"`
}
variables := map[string]interface{}{
	"repositoryOwner": githubv4.String(owner),
	"repositoryName":  githubv4.String(name),
	"issueNumber":     githubv4.Int(issue),
	"commentsCursor":  (*githubv4.String)(nil), // Null after argument to get first page.
}

// Get comments from all pages.
var allComments []comment
for {
	err := client.Query(ctx, &q, variables)
	if err != nil {
		return err
	}
	allComments = append(allComments, q.Repository.Issue.Comments.Nodes...)
	if !q.Repository.Issue.Comments.PageInfo.HasNextPage {
		break
	}
	variables["commentsCursor"] = githubv4.NewString(q.Repository.Issue.Comments.PageInfo.EndCursor)
}

There is more than one way to perform pagination. Consider additional fields inside PageInfo object.

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($input: AddReactionInput!) {
	addReaction(input: $input) {
		reaction {
			content
		}
		subject {
			id
		}
	}
}
variables {
	"input": {
		"subjectId": "MDU6SXNzdWUyMTc5NTQ0OTc=",
		"content": "HOORAY"
	}
}

You can define:

var m struct {
	AddReaction struct {
		Reaction struct {
			Content githubv4.ReactionContent
		}
		Subject struct {
			ID githubv4.ID
		}
	} `graphql:"addReaction(input: $input)"`
}
input := githubv4.AddReactionInput{
	SubjectID: targetIssue.ID, // ID of the target issue from a previous query.
	Content:   githubv4.ReactionContentHooray,
}

Then call client.Mutate:

err := client.Mutate(context.Background(), &m, input, nil)
if err != nil {
	// Handle error.
}
fmt.Printf("Added a %v reaction to subject with ID %#v!\n", m.AddReaction.Reaction.Content, m.AddReaction.Subject.ID)

// Output:
// Added a HOORAY reaction to subject with ID "MDU6SXNzdWUyMTc5NTQ0OTc="!

Directories

PathSynopsis
example/githubv4devgithubv4dev is a test program currently being used for developing githubv4 package.

License