Go言語でAPIを使う練習のため、タイトルにある「GitHubのリポジトリにある特定の1ファイルの内容を取得する」プログラムを書いてみました。
Contents
取得するファイル(GitHubリポジトリ側)
今回はチュートリアル用のリポジトリから、以下のようなREADME.mdのコンテンツを取ってきてみたいと思います。
This is a script for API-tutorial- feature-A- fix-B- feature-C
プログラム全文
package mainimport ("encoding/base64""encoding/json""fmt""io/ioutil""net/http")func main() {blobUrl := "https://api.github.com/repos/fugithora812/git-tutorial/contents/README.md"req, err := http.NewRequest("GET", blobUrl, nil)if err != nil {fmt.Println("failed: NewRequest")}req.Header.Set("Accept", "application/vnd.github.v3+json")client := new(http.Client)resp, err := client.Do(req)if err != nil {fmt.Println("failed: DoReq")}defer resp.Body.Close()contents, err := ioutil.ReadAll(resp.Body)if err != nil {fmt.Println("failed: ReadAll")}var blob interface{}err = json.Unmarshal(contents, &blob)if err != nil {fmt.Println("failed: Unmarshal")}src := blob.(map[string]interface{})["content"]dec, err := base64.StdEncoding.DecodeString(src.(string))fmt.Println(string(dec))}
実行結果
$ go run main.goThis is a script for API-tutorial- feature-A- fix-B- feature-C
解説
少し解説じみたことを書きます。上のmain()では、まずGitHubのAPIを用いてファイル情報を取得するための準備をしています。
blobUrl := "https://api.github.com/repos/fugithora812/git-tutorial/contents/README.md"req, err := http.NewRequest("GET", blobUrl, nil)if err != nil {fmt.Println("failed: NewRequest")}req.Header.Set("Accept", "application/vnd.github.v3+json")
リクエストのヘッダには、{"Accept": "application/vnd.github.v3+json"}
を指定します(⇒Resources in the REST API – GitHub Docs)。もし取得先のリポジトリがプライベートなものであれば、これに加えて適切な権限をもったパーソナルアクセストークンが必要です。トークンは以下のように設定できます。
token := {GitHubのPersonal Access Token}req.Header.Set("Authorization", fmt.Sprintf("token %s", token))
main()関数ではこのトークンの設定は行わず(パブリックなので)、実際にAPIリクエストを行っています。
client := new(http.Client)resp, err := client.Do(req)if err != nil {fmt.Println("failed: DoReq")}defer resp.Body.Close()
ここからAPIレスポンスの内容を取得していきます。GitHubのドキュメントによると、レスポンスとして返ってくるJSONデータは以下のような構造になっています。
{ "type": "file", "encoding": "base64", "size": 5362, "name": "README.md", "path": "README.md", "content": "encoded content ...", "sha": "3d21ec53a331a6f037a91c368710b99387d012c1", "url": "https://api.github.com/repos/octokit/octokit.rb/contents/README.md", "git_url": "<https://api.github.com/repos/octokit/octokit.rb/git/blobs/3d21ec53a331a6f037a91c368710b99387d012c1>", "html_url": "https://github.com/octokit/octokit.rb/blob/master/README.md", "download_url": "https://raw.githubusercontent.com/octokit/octokit.rb/master/README.md", "_links": { "git": "<https://api.github.com/repos/octokit/octokit.rb/git/blobs/3d21ec53a331a6f037a91c368710b99387d012c1>", "self": "https://api.github.com/repos/octokit/octokit.rb/contents/README.md", "html": "https://github.com/octokit/octokit.rb/blob/master/README.md" }}
ここで欲しいのは、この中の”content”の値です。base64でエンコーディングされているので、そのデコード処理も行っています。
// レスポンスのJSON全体を(バイト列で)取得contents, err := ioutil.ReadAll(resp.Body)if err != nil {fmt.Println("failed: ReadAll")}// jsonとして扱えるようUnmarshallして"content"の内容を取得var blob interface{}err = json.Unmarshal(contents, &blob)if err != nil {fmt.Println("failed: Unmarshal")}src := blob.(map[string]interface{})["content"]// 取得した"content"の値をデコードdec, err := base64.StdEncoding.DecodeString(src.(string))// ファイルの内容を出力fmt.Println(string(dec))
これで、ファイル内容の取得・出力ができました。