migrating Dropbox API v1 to v2

Dropbox側の修正を終えたのでテストしてみたところGoogle Driveに対する読み書きでコケる。なんで?

OAuth2による認証が成功した直後、自身のプロファイル情報を得るAPIを呼び、認証に成功したIDと一致することを確認している。Google Driveの場合は、
https://www.googleapis.com/oauth2/v1/userinfo
に対してPOSTして返ってくるjsonを参照している。このエンドポイントが404を返すようになった。11日前にwasaviをリリースした際にはもちろんすべてのテストが通ったことを確認してあるので、その間になんか変わったようだ。

Googleが提供するAPIの包括的なリファレンスというのは、どこにあるのかよくわからない。しかしAPI Explorerというものがあり、実質的にここでAPIの仕様を確認できる。ということで Google OAuth2 API v2 を見てみると確かにuserinfoはない。その代わりoauth2.userinfo.v2.me.getというものがあるのでこれがどうも最新のようだ。エンドポイントは
https://www.googleapis.com/userinfo/v2/me
だ。これにどのフィールドを参照するかのクエリ文字列(今回の場合は[cci]?fields=id[/cci])を付加して、GETで取得すると結果が返ってくる。

API Explorerで参照できるAPI名らしきものとエンドポイントのURLの構造が微妙に似ているような似てないような感じになっているのは何なんだろう。わからん。それと、この最新のAPIを使ったとしても、POSTだとやはり404が返される。ちゃんと書いてあるとおりにGETじゃないといけない。

Google Drive #4

  • 前回の記事で Google Drive 上のファイルを読み出すために 3 回のアクセスが必要と書いたが、パスの構築時に basename も含めることでこれを 2 回に抑えることができた。
  • あるファイルがその親ディレクトリを複数持てるというのは、そのままの通りの意味のようだ。ハードリンクみたいな感じか。ちょっとこれは面倒なのでちゃんと対応するのは後回し。現状では、パスの構築時は親は 1 つだけの前提にしている。
  • ファイルの実体を読み出す際、ファイルのメタデータに含まれる downloadUrl が指すアドレス(たいてい https://*.googleuserconent.com/*)を参照することになる。一方で、OAuth 2.0 による承認を行う際、スコープと呼ばれる識別子を送る。[cci]https://www.googleapis.com/auth/drive[/cci] が最も強い権限、[cci]~/drive.file[/cci] がファイルの操作、[cci]~/drive.readonly.metadata[/cci] がメタデータの読み込み、みたいな。

    このうち最も強い権限を持つ drive スコープはほんとうに必要な場合のみ使ってね! とドキュメントにも明示してあるのだが、どうも downloadUrl からの読み込みは drive スコープじゃないと行えないような。drive.file だと 404 が帰ってくる。これは……バグじゃないのかな。というわけで drive スコープを使わざるを得ない。そんなような問いと答えが stackoverflow にもあった。

残るのはファイルの書き込み。

Google Drive #3

Google Drive 上の、あるファイルへのパスが与えられたときそれを読み込む手順は以下のとおりとした:

  • パスを dirname と basename に分割する
  • dirname をディレクトリ名ごとに分割し、各フラグメントを [cci]title=’ディレクトリ名'[/cci] に変換し、[cci]or[/cci] で結合してクエリ文字列を得る。[cci]/foo/bar[/cci] は [cci]title=’foo’ or title=’bar'[/cci] となる
  • File:list API を呼び出す。このとき q パラメータは上のクエリ文字列を与える
  • API の結果から、目的のパスに合致するメタデータの並びを得る。上の例で言うと、まずディレクトリ bar があり、その親 ID を持ち、かつタイトルが foo であるものを抜き出す。その処理をルートに向かって再帰的に行い、ルートに達した(分割したディレクトリの個数 == 抜き出したメタデータの個数となった)らパスが決定する
  • File:list API を呼び出す。このとき q パラメータは dirname の最後のフラグメントの fileID を親に持つファイル、とする。つまり [cci]’fileID’ in parents[/cci] とする。これは Children:list API でもよい気がするが、Children:list は指定のファイルの子供の ID しか返さない。
  • API の結果から、basename に一致するものがあれば、その downloadUrl を用いてファイルの内容を読み込む。なければ新しいファイルの編集とみなし、空文字列を wasavi へ返す

つまり 1 つのファイルを読み込むのに 3 回のリクエストが必要になる……それにしてもイケてないなー! もっとうまい方法はないのかしら。

あと、ひとつ気になる点がある。あるファイルのメタデータ内に、その親ファイルの ID が格納されているのだが、名前が parents で、型は配列なのである。あるファイルが複数の親を持つことができる? どうやって?