F# - HTTP で Google Drive API を利用する

commits5 min read読了の目安(約4500字

序文

Google Drive API の .NET 用クライアントライブラリ Google.Apis.Drive.v3 [↗]uploadType [↗] を設定する方法が見当たらなかったので HTTP から直接利用する方法を調べてみました。

概要

  • F# で アクセストークン を取得する方法の紹介。

事前準備

  1. Drive API、Docs API が有効な Google Cloud Platform のプロジェクトを用意する [↗]
  2. 認証情報を作る [↗]

認可コードの取得

次の項目のリフレッシュトークンを取得するために必要です。

https://accounts.google.com/o/oauth2/v2/auth?
response_type=code&client_id=🐣
&redirect_uri=urn:ietf:wg:oauth:2.0:oob&
scope=https://www.googleapis.com/auth/drive&access_type=offline
  1. URL の 🐣 をクライアント ID に書き換える。
  2. URL をブラウザで開く。
  3. 開いたページを進めると認可コードが表示される。

リフレッシュトークンの取得

アクセストークンは約1時間で有効期限が切れます。
アクセストークンを繰り返し取得するにはリフレッシュトークンが必要です。

RefreshToken.fsx
let bodyJson =
    """{
        "client_id": "🐣",
        "client_secret": "😎",
        "grant_type": "authorization_code",
        "code": "🦑",
        "redirect_uri": "urn:ietf:wg:oauth:2.0:oob",
        "access_type": "offline"
    }"""

let content =
    new System.Net.Http.StringContent(
        bodyJson,
        System.Text.Encoding.UTF8,
        @"application/json"
    )

let request =
    new System.Net.Http.HttpRequestMessage(
        System.Net.Http.HttpMethod.Post,
        "https://www.googleapis.com/oauth2/v4/token",
        Content = content
    )

let client = new System.Net.Http.HttpClient()
let response = client.Send(request)
client.Dispose()

printfn "%s"
<| response.Content.ReadAsStringAsync().Result
  1. RefreshToken.fsx ファイルを作る。
  2. ソースコードの絵文字を書き換える。
記号 書き換え先
🐣 クライアント ID
😎 クライアントシークレット
🦑 認可コード
  1. ターミナルでコマンドを実行する。
PowerShell
dotnet fsi RefreshToken.fsx
  1. 出力された JSON の "refresh_token" の値を記録する。

アクセストークンの取得

Google Drive API の使用時に必要です。

Program.fs
let regex =
    new System.Text.RegularExpressions.Regex(
        @"^{\n  ""access_token"": ""(.*?)""",
        System.Text.RegularExpressions.RegexOptions.Compiled
    )

let bodyJson =
    """{
        "client_id": "🐣",
        "client_secret": "😎",
        "grant_type": "refresh_token",
        "refresh_token": "🍎"
    }"""

let refresh () =
    let content =
        new System.Net.Http.StringContent(
            bodyJson,
            System.Text.Encoding.UTF8,
            @"application/json"
        )

    let request =
        new System.Net.Http.HttpRequestMessage(
            System.Net.Http.HttpMethod.Post,
            "https://www.googleapis.com/oauth2/v4/token",
            Content = content
        )

    let client = new System.Net.Http.HttpClient()
    let response = client.Send(request)
    client.Dispose()

    if response.IsSuccessStatusCode then
        let resultJson = response.Content.ReadAsStringAsync().Result
        let accessToken = regex.Match(resultJson).Groups.[1].Value
        Some(accessToken)
    else
        None

JSON をデータ構造に変換する方法は FSharp.Data [↗] などがあります。

  1. Program.fs ファイルを作る。
  2. ソースコードの絵文字を書き換える。
記号 書き換え先
🐣 クライアント ID
😎 クライアントシークレット
🍎 リフレッシュトークン

使用例

  • フォルダを作成する関数 createFolder
  • 失敗時に前の項目で作った refresh を呼び出している。
Program.fs
let mutable accessToken = ""

let rec createFolder name =
    let bodyJson =
        $"""{{
            "mimeType": "application/vnd.google-apps.folder",
            "name": "{name}"
        }}"""

    let content =
        new System.Net.Http.StringContent(
            bodyJson,
            System.Text.Encoding.UTF8,
            @"application/json"
        )

    let parameters = "uploadType=multipart"

    let request =
        new System.Net.Http.HttpRequestMessage(
            System.Net.Http.HttpMethod.Post,
            $"https://www.googleapis.com/drive/v3/files?{parameters}",
            Content = content
        )

    request.Headers.Add("Authorization", $"Bearer {accessToken}")

    let client = new System.Net.Http.HttpClient()
    let response = client.Send(request)
    client.Dispose()

    if not response.IsSuccessStatusCode then
        let newToken = refresh()
        if newToken.IsSome then
            accessToken <- newToken.Value
            createFolder name

関連記事

end