GitHub の GraphQL を叩く。.NET Framework C# から

# 概要

GitHub の GraphQL を叩く。.NET Framework (わたしの場合は ASP.NET MVC) C# から。

最近はやりの

- LINE の [URL プレビュー](https://blog.kcr-cp.com/index.php/2018/01/16/what-is-url-preview/)
- Twitter の [Summary card](https://developer.twitter.com/en/docs/tweets/optimize-with-cards/overview/summary)

これらがごとく…
GitHub の Issue or PullRequest の URL をもとに、
「タイトル」「Open or Closed」をさらっと取得し、表示したい。

# GraphQL API Explorer でクエリを設計する

[GraphQL API Explorer | GitHub Developer Guide](https://developer.github.com/v4/explorer/) で設計します。

![2020-01-29_23h20_23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/364126/54fb4d0f-326a-e01f-2eb8-2f73db85889f.png)

# コーディング

C# での、リクエストボディー構築:

```csharp
  var body =
      JsonConvert.SerializeObject(
          new {
              query = Resources.GitHubTopic,
              variables = new {
                  owner = match.Groups["owner"].Value,
                  name = match.Groups["name"].Value,
                  number = int.Parse(match.Groups["number"].Value),
              },
          }
      );
```

```GitHubTopic.graphql
query ($name: String!, $owner: String!, $number: Int!) {
  repository(name: $name, owner: $owner) {
    issueOrPullRequest(number: $number) {
      __typename
      ... on Issue {
        title
        closed
      }
      ... on PullRequest {
        title
        closed
      }
    }
  }
}
```

正規表現で URL を解析:

```csharp
  var match = Regex.Match(href, "https://github.com/(?<owner>[\\w\\-]+)/(?<name>[\\w\\-]+)/(issues|pull)/(?<number>\\d+)");
  if (match.Success) {
    // match.Groups["owner"].Value
    // match.Groups["name"].Value
    // int.Parse(match.Groups["number"].Value)
  }
```

HttpClient でリクエスト送信と、レスポンスのデコードまで:

```csharp
  var client = new HttpClient();
  client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(
      "Basic", 
      ConfigurationManager.AppSettings["GitHub:Authorization"]
  );
  // Request forbidden by administrative rules. Please make sure your request has a User-Agent header (http://developer.github.com/v3/#user-agent-required). Check https://developer.github.com for other possible causes.
  client.DefaultRequestHeaders.UserAgent.Add(
      new ProductInfoHeaderValue("アプリ名をこちらに", "0.1")
  );

  var resp = client.PostAsync(
      "https://api.github.com/graphql",
      new StringContent(body)
  )
      .Result;

  var topic = JsonConvert.DeserializeObject<GitHubTopic>(
      resp.Content.ReadAsStringAsync()
          .Result
  );
```

`GitHubTopic` クラスの定義例:

```csharp
  class GitHubTopic {
      public Data data { get; set; }
      public string message { get; set; }
      public string documentation_url { get; set; }

      public class Data {
          public Repository repository { get; set; }
      }
      public class Repository {
          public IssueOrPullRequest issueOrPullRequest { get; set; }
      }
      public class IssueOrPullRequest {
          public string title { get; set; }
          public bool closed { get; set; }
      }
  }
```

レスポンスをモデル化:

```csharp
  return new KadaiSummary {
      Title = topic.data.repository.issueOrPullRequest.title,
      Status = topic.data.repository.issueOrPullRequest.closed ? "Closed" : "Open",
  };
```

## appSettings にシークレット情報を…

**※ この方法が安全かどうかは不明です。**

`GitHub:Authorization` には、`USERNAME:PersonalAccessToken` を BASE64 化した文字列を `value` へ設定します。

### Web.config に定義する場合

`Web.config` は、デフォルトでソースコード管理に入るような代物です。
ここにシークレットを書くことは勧められません。

```Web.config
<?xml version="1.0"?>
<configuration>
  <appSettings>
    <add key="GitHub:Authorization" value="xxx"/>
  </appSettings>
</configuration>
```

### IIS Express の applicationhost.config に定義?

つぎのファイルを試行錯誤しましたが、定義のやり方を見つけられませんでした…

- `.vs\config\applicationhost.config`
- `%USERPROFILE%\Documents\IISExpress\config\applicationhost.config` 

### 外部ファイル Secret.config に定義する場合

開発環境… IIS Express でも機能しました。

```Web.config
<?xml version="1.0"?>
<configuration>
  <appSettings file="Secret.config">
  </appSettings>
</configuration>
```

`file="Secret.config"` を指定することで、`Secret.config` ファイルを別途参照するそうです。
`Secret.config` が存在しなくてもエラーにならないとの情報がありました。

```xml:Secret.config
<?xml version="1.0" encoding="utf-8" ?>
<appSettings>
  <add key="GitHub:Authorization" value="xxx"/>
</appSettings>
```

`Secret.config` をソースコード管理に含めないように手当しておけば、
意図しないシークレットの拡散は防ぐことが出来ると思います。

### IIS 8.0 で定義

Windows Server 2012 R2 です。

![2020-01-29_23h31_08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/364126/dee57c40-b5f7-85cf-aa9d-b5b7723a64ab.png)

構成エディターのセクション `appSettings` で定義できます。

例のごとく… 安全かどうかは、つぎの保存先がセキュリティー的に大丈夫かどうか…? によると思います。

| 場所の選択 | 保存先 例: |
|---|---|
| Default Web Site Web.config | C:\inetpub\wwwroot\web.config |
| ルート Web.config &lt;location path='Default Web Site' /&gt; | C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Config\web.config |