golang访问GitHub GraphQL API v4的插件库githubql的使用

Golang 访问 GitHub GraphQL API v4 的插件库 githubql 使用

简介

githubv4 是一个用于访问 GitHub GraphQL API v4 的客户端库。它提供了友好、简单且功能强大的 API,支持所有 GitHub GraphQL API v4 功能。

安装

go get github.com/shurcooL/githubv4

认证

GitHub GraphQL API v4 需要认证。推荐使用 golang.org/x/oauth2 包进行认证:

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)
    // 使用 client...
}

如果是 GitHub Enterprise,使用 NewEnterpriseClient

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

简单查询

定义 Go 类型对应 GitHub GraphQL 模式,然后调用 client.Query

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

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

标量类型

GitHub GraphQL 标量类型对应 Go 类型:

var query struct {
    Viewer struct {
        Login          githubv4.String
        CreatedAt      githubv4.DateTime
        IsBountyHunter githubv4.Boolean
        BioHTML        githubv4.HTML
        WebsiteURL     githubv4.URI
    }
}

也可以使用 Go 原生类型:

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

参数和变量

使用 graphql 结构体标签定义参数:

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

使用变量:

func fetchRepoDescription(ctx context.Context, owner, name string) (string, error) {
    var q struct {
        Repository struct {
            Description string
        } `graphql:"repository(owner: $owner, name: $name)"`
    }
    
    variables := map[string]interface{}{
        "owner": githubv4.String(owner),
        "name":  githubv4.String(name),
    }
    
    err := client.Query(ctx, &q, variables)
    return q.Repository.Description, err
}

内联片段

使用 graphql 标签定义内联片段:

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\")"`
}

分页

获取所有评论示例:

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条
        } `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), // 获取第一页
}

// 获取所有页面的评论
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)
}

变更

变更操作示例:

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, // 从之前查询获取的目标issue ID
    Content:   githubv4.ReactionContentHooray,
}

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

完整示例

以下是一个完整的示例,展示如何查询用户的登录名和创建时间:

package main

import (
    "context"
    "fmt"
    "os"
    
    "github.com/shurcooL/githubv4"
    "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)

    // 定义查询
    var query struct {
        Viewer struct {
            Login     string
            CreatedAt string
        }
    }

    // 执行查询
    err := client.Query(context.Background(), &query, nil)
    if err != nil {
        fmt.Printf("Error: %v\n", err)
        return
    }

    // 输出结果
    fmt.Printf("Login: %s\n", query.Viewer.Login)
    fmt.Printf("CreatedAt: %s\n", query.Viewer.CreatedAt)
}

这个示例展示了如何使用 githubv4 包进行基本的 GraphQL 查询。你可以根据需要扩展这个示例,添加更多字段或执行更复杂的查询和变更操作。


更多关于golang访问GitHub GraphQL API v4的插件库githubql的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang访问GitHub GraphQL API v4的插件库githubql的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


使用githubql访问GitHub GraphQL API v4

githubql是Go语言的一个第三方库,专门用于访问GitHub的GraphQL API v4版本。它提供了类型安全的GraphQL查询构建和执行功能。

安装

首先安装githubql库:

go get github.com/shurcooL/githubql

基本使用

1. 创建客户端

import (
	"context"
	"fmt"
	"net/http"
	"os"

	"github.com/shurcooL/githubql"
	"golang.org/x/oauth2"
)

func main() {
	src := oauth2.StaticTokenSource(
		&oauth2.Token{AccessToken: os.Getenv("GITHUB_TOKEN")},
	)
	httpClient := oauth2.NewClient(context.Background(), src)
	client := githubql.NewClient(httpClient)
	
	// 使用client进行查询...
}

2. 基本查询示例

type query struct {
	Viewer struct {
		Login     githubql.String
		CreatedAt githubql.DateTime
	} `graphql:"viewer"`
}

func main() {
	// ...创建client代码同上...

	var q query
	err := client.Query(context.Background(), &q, nil)
	if err != nil {
		// 处理错误
	}
	
	fmt.Println("Login:", q.Viewer.Login)
	fmt.Println("Created at:", q.Viewer.CreatedAt)
}

3. 带参数的查询

type repositoryQuery struct {
	Repository struct {
		Description githubql.String
		Stargazers  struct {
			TotalCount githubql.Int
		}
	} `graphql:"repository(owner: $owner, name: $name)"`
}

func main() {
	// ...创建client代码同上...

	var q repositoryQuery
	variables := map[string]interface{}{
		"owner": githubql.String("golang"),
		"name":  githubql.String("go"),
	}

	err := client.Query(context.Background(), &q, variables)
	if err != nil {
		// 处理错误
	}
	
	fmt.Println("Description:", q.Repository.Description)
	fmt.Println("Stars:", q.Repository.Stargazers.TotalCount)
}

4. 分页查询

type issuesQuery struct {
	Repository struct {
		Issues struct {
			Nodes []struct {
				Title githubql.String
				URL   githubql.URI
			}
			PageInfo struct {
				EndCursor   githubql.String
				HasNextPage githubql.Boolean
			}
		} `graphql:"issues(first: 10, after: $cursor)"`
	} `graphql:"repository(owner: $owner, name: $name)"`
}

func main() {
	// ...创建client代码同上...

	var cursor *githubql.String
	for {
		var q issuesQuery
		variables := map[string]interface{}{
			"owner":  githubql.String("golang"),
			"name":   githubql.String("go"),
			"cursor": cursor,
		}

		err := client.Query(context.Background(), &q, variables)
		if err != nil {
			// 处理错误
		}

		for _, issue := range q.Repository.Issues.Nodes {
			fmt.Println("Title:", issue.Title)
			fmt.Println("URL:", issue.URL)
		}

		if !q.Repository.Issues.PageInfo.HasNextPage {
			break
		}
		cursor = &q.Repository.Issues.PageInfo.EndCursor
	}
}

高级用法

1. 使用Mutation

type addStarMutation struct {
	AddStar struct {
		Starrable struct {
			Stargazers struct {
				TotalCount githubql.Int
			}
		}
	} `graphql:"addStar(input: $input)"`
}

func main() {
	// ...创建client代码同上...

	var m addStarMutation
	input := githubql.AddStarInput{
		StarrableID: "MDEwOlJlcG9zaXRvcnkxMjM0NTY3OA==", // 需要替换为实际的ID
	}
	variables := map[string]interface{}{
		"input": input,
	}

	err := client.Mutate(context.Background(), &m, variables)
	if err != nil {
		// 处理错误
	}
	
	fmt.Println("Total stars:", m.AddStar.Starrable.Stargazers.TotalCount)
}

2. 使用内联片段(Inline Fragments)

type searchQuery struct {
	Search struct {
		Nodes []struct {
			Typename  string `graphql:"__typename"`
			OnIssue   struct {
				Title githubql.String
			} `graphql:"... on Issue"`
			OnPullRequest struct {
				Title githubql.String
			} `graphql:"... on PullRequest"`
		}
	} `graphql:"search(query: $query, type: $type, first: 10)"`
}

func main() {
	// ...创建client代码同上...

	var q searchQuery
	variables := map[string]interface{}{
		"query": githubql.String("is:open"),
		"type":  githubql.SearchTypeIssue,
	}

	err := client.Query(context.Background(), &q, variables)
	if err != nil {
		// 处理错误
	}
	
	for _, node := range q.Search.Nodes {
		switch node.Typename {
		case "Issue":
			fmt.Println("Issue:", node.OnIssue.Title)
		case "PullRequest":
			fmt.Println("PR:", node.OnPullRequest.Title)
		}
	}
}

注意事项

  1. 需要GitHub个人访问令牌(PAT),可以在GitHub开发者设置中创建
  2. 注意API速率限制
  3. 复杂的查询可能需要多次请求和分页处理
  4. 所有字段名必须与GraphQL schema中的完全匹配
  5. 使用githubql类型而不是Go原生类型

githubql库提供了类型安全的GraphQL查询方式,通过Go结构体标签定义查询结构,能够有效减少错误并提高开发效率。

回到顶部