GitHubのRest APIでファイルを取得する

# GitHub REST API まとめ

## はじめに
GitHub REST APIのうち、Repository関連のよく使うものについてまとめました。


一部の項目ではHeaderにTokenが必要になります。古いdocumentでは`token XXXXX`が`bearer XXXXX`として記載されているので注意してください。
またTokenが必須でない場合も、TokenをHeaderに含めることでアクセス回数制限が大幅に緩和されます。

```javascript
GitHubToken = "XXXXXX"
header_auth = {"Authorization":`token ${GitHubToken}`, 
    "Accept":"application/vnd.github.v3+json"};
```

## Repositoryファイル情報取得

Repositoryに含まれるファイルのリストを取得します。
Private Repositoryの場合、適切なtokenが必要です。

```javascript
GitHubName = "imaya"
GitHubRepo = "zlib.js"
GitHubPath = "src"
header_auth={"Accept":"application/vnd.github.v3+json"};

git_url = `https://api.github.com/repos/${GitHubName}/${GitHubRepo}/contents/${GitHubPath}`;
res_get = await fetch(git_url, { method:"GET", headers:header_auth}).then(d=>d.json());

// res_get
[
    {
        "name": "zlib.js",
        "path": "src/zlib.js",
        "sha": "XXXXXXXXXXXXXXXXXXX",
        "size": 479,
        "url": "https://api.github.com/repos/imaya/zlib.js/contents/src/zlib.js?ref=develop",
        "html_url": "https://github.com/imaya/zlib.js/blob/develop/src/zlib.js",
        "git_url": "https://api.github.com/repos/imaya/zlib.js/git/blobs/XXXXXXXXXXXXXXXXXXX",
        "download_url": "https://raw.githubusercontent.com/imaya/zlib.js/develop/src/zlib.js",
        "type": "file",
        "_links": {
            "self": "https://api.github.com/repos/imaya/zlib.js/contents/src/zlib.js?ref=develop",
            "git": "https://api.github.com/repos/imaya/zlib.js/git/blobs/XXXXXXXXXXXXXXXXXXX",
            "html": "https://github.com/imaya/zlib.js/blob/develop/src/zlib.js"
        }
    } // ....省略
]

```

## ファイル情報取得・DL

ファイル内容はbase64でencodeされているので、`atob()`でdecodeする必要があります。

### Repositoryファイル情報取得を経由しない

pathとしてファイル名まで入力すれば、contentとしてencodeされたものが得られます。

```javascript
GitHubName = "imaya"
GitHubRepo = "zlib.js"
GitHubPath = "src/zlib.js"
header_auth={"Accept":"application/vnd.github.v3+json"};

git_url = `https://api.github.com/repos/${GitHubName}/${GitHubRepo}/contents/${GitHubPath}`;
res = await fetch(git_url, { method:"GET", headers:header_auth}).then(d=>d.json());

// res
{
    "name": "zlib.js",
    "path": "src/zlib.js",
    "sha": "XXXXXXXXXXXXXXXXXXX",
    "size": 479,
    "url": "https://api.github.com/repos/imaya/zlib.js/contents/src/zlib.js?ref=develop",
    "html_url": "https://github.com/imaya/zlib.js/blob/develop/src/zlib.js",
    "git_url": "https://api.github.com/repos/imaya/zlib.js/git/blobs/XXXXXXXXXXXXXXXXXXX",
    "download_url": "https://raw.githubusercontent.com/imaya/zlib.js/develop/src/zlib.js",
    "type": "file",
    "content": "LyoqCiAqIEBmaW......", // 省略
    "encoding": "base64",
    "_links": {
        "self": "https://api.github.com/repos/imaya/zlib.js/contents/src/zlib.js?ref=develop",
        "git": "https://api.github.com/repos/imaya/zlib.js/git/blobs/XXXXXXXXXXXXXXXXXXX",
        "html": "https://github.com/imaya/zlib.js/blob/develop/src/zlib.js"
    }
}

data = atob(res.content);
```

### 大容量ファイルの場合 (Repositoryファイル情報取得を経由)

上記の方法では、ファイルの容量に1MBの制限があります。
それを超えるファイルをダウンロードしたい場合、Repository情報取得から得られる、git_urlを利用します。

```javascript
gitFile = res_get[19];
git_url = gitFile.git_url;
res = await fetch(git_url).then(d=>d.json());
data = atob(res.content);
```

## 検索

検索文字列`q`はurlの後ろにつなげます。検索文字列の要素数にはいくつかの制限があります。

```javascript
// search
GitHubName = "imaya"
GitHubRepo = "zlib.js"
header_auth = {"Accept":"application/vnd.github.v3+json"};

q="filename:*.js path:src -filename:z*.js"
git_search_url = `https://api.github.com/search/code`;
search_query = `q=${q}+repo:${GitHubName}/${GitHubRepo}`;
res_get = await fetch(git_search_url+"?"+search_query, { method:"GET", headers: header_auth}).then(d=>d.json());

searchedFiles = res_get.items;
```

## ファイル内容更新・作成

ファイルの更新にはTokenに加えて、shaと呼ばれる符号が必要になります。これはRepositoryファイル情報取得で得られます。
ファイル内容はbase64でのencodeが必要なので、`btoa()`を使用します。
この際、GitHub上ではencodeされたファイルが保存されるため、日本語を含むファイルをバックアップ以外の目的で保存するのには適していません。

以下のScriptでは同名のファイルが存在する場合は更新、存在しない場合は新規作成するようになっています。

```javascript
//check file
GitHubName = "XXXXXXXXXXXX" // rest apiのテストは自己管理のRepositoryで行ってください。
GitHubRepo = "XXXXXXXXXXXXX"
GitHubToken = "XXXXXXXXXXXXX"
GitHubDir = "Backup"
newFileName = "new.md"

header_auth={"Authorization":`token ${GitHubToken}`, "Accept":"application/vnd.github.v3+json"};
git_url = `https://api.github.com/repos/${GitHubName}/${GitHubRepo}/contents/${GitHubDir}/${newFileName}`;
res_get = await fetch(git_url, { method:"GET", headers:header_auth}).then(d=>d.json());

sha = null;
if (/200|302/.test(res_get["status"])){
    console.log("connection error");
    return;
} else if (res_get["sha"]) sha = res_get["sha"];

// create or update file
put_body = Object.assign({message:"auto backup", content:btoa(note_md)}, (sha) ? {sha: sha} : {});
put_header = {...header_auth ,"Content-Type": "application/json"};

res_put = await fetch(git_url, { method:"PUT", body:JSON.stringify(put_body), headers:put_header})
.then(d=>d.json());
if (res_put.status!=200) console.log("can't push");
```

## Reference

[GitHub REST API reference / Repository](https://docs.github.com/ja/rest/reference/repos)