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))
これで、ファイル内容の取得・出力ができました。
返信がありません