【Go】GitHub上の「特定の1ファイル」を取得する

Categories:Go

Go言語でAPIを使う練習のため、タイトルにある「GitHubのリポジトリにある特定の1ファイルの内容を取得する」プログラムを書いてみました。

取得するファイル(GitHubリポジトリ側)

今回はチュートリアル用のリポジトリから、以下のようなREADME.mdのコンテンツを取ってきてみたいと思います。

This is a script for API-tutorial

- feature-A
- fix-B
- feature-C

プログラム全文

package main

import (
	"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.go
This 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))

これで、ファイル内容の取得・出力ができました。

参考

返信がありません

コメントを残す

メールアドレスが公開されることはありません。