Amazon Drive API を使ってみる


Amazon Drive API の使い方の説明です (2016/1/18 新規作成)。

Amazon Drive / 準備 / 認可 / API呼び出し / Nodes / 戻る / トップページ


Amazon Drive

Amazon Drive は、 Amazon 社が提供しているクラウドストレージサービスです。 クラウドストレージの中ではあまり名前を聞きませんが、 Amazon EC2/S3 などを提供している同社だけあって、性能や信頼性は高い クラウドストレージになっています。 なお、2016/7/21頃以前は Amazon Cloud Drive と呼ばれていました。
 
Amazon Drive API はその Amazon Drive とのファイルの やりとりや操作ができる機能を提供します。 iOS/Android 向けには専用の SDK が提供されており、 ここでは REST API を直接叩く、 Web サービス側からの利用について説明を書きます。
 
Amazon Drive サービスは日本国内の amazon.co.jp でも提供されていますが、API は公式には amazon.com でのみ提供されています (Login with Amazon 機能が日本では提供されていないため だそうです)。 ですが2016年4月頃から、ここで説明している方法で (amazon.com サーバーへ API 呼び出しする方法で) amazon.co.jp アカウントで API を利用できるようになっているようです。
 
なお、日本からでも amazon.com のアカウントを取得して、 amazon.com のみの容量無制限サービスや API の利用は普通にできます。 余談ですが、公式のデスクトップアプリや iOS/Android アプリは amazon.co.jp のみに繋ごうとするため利用できないように見えますが、 OS の言語・地域設定を一時的に米国にしてログインしておけば、 我々も amazon.com アカウントでアプリを利用できます。

準備

Amazon Drive API を使うには、まず開発者ページで Security Profile を登録し、アクセスに使う Client ID を取得します。
 
Amazon Apps & Services Developer Portal にログインし、 "Create a New Security Profile" ボタンから必要事項を記入して Security Profile を作ります。
 
この Security Profile は Amazon の API 全般に使うもので、 Amazon Drive API で利用するには Amazon Drive 用の許可 (ホワイトリストへの登録) も必要です。 こちら の "Whitelist Security Profile" ボタンから先ほど作成した Security Profile のホワイトリストへの登録申請をします。 アップロードなど書き込み系の処理もしたいなら、 "Permission Level" の設定に Write を含めることをお忘れなく。 しばらくすると登録されたことを知らすメールが届きます。
 
登録が完了したら、 Amazon Apps & Services Developer Portal に作った Security Profile が並んでいるので、 "Show Client ID and Client Secret" ボタンで表示できる Client ID と Client Secret をメモしておきましょう。
 
また、同ページの Security Profile の右にある歯車アイコンから "Web Settings" を開き、 OAuth 認可後に開くサイトのアドレスを "Allowed Return URLs" に、 クライアント JavaScript から利用するのであればそのサイトのドメインを "Allowed Origins" に、登録しておきます。 ここで登録できるアドレスは https プロトコルのみです。 今や個人でもサーバ証明書を無料で取得できる Let's Encrypt のようなサービスも あるので、利用させてもらいましょう。
 
この時点でこの Security Profile を使った API 呼び出しは、 個人で開発するのには十分な程度のアクセス数の制限がかかっています。 公開して多くの人に使って貰うには制限がきつい状態なので、 API を使ったアプリが完成したらホワイトリスト登録完了メールに書かれている アドレスにアプリを送ってレビューして貰い、制限を緩和します。

OAuth2 認可

API を使うには、はじめに利用者に OAuth2 でアクセス許可をしてもらい、 access token を得ます。後は access token を使って各 API が呼べます。
 
認可には二通り あります。 クライアントアプリ向けのシンプルな Implicit Grant と、 サーバーアプリ向けの安全性の高い Authorization Code Grant です。 どちらも認可用の Web ページを開いて、利用者が承認すると 指定ページにリダイレクトされ、 リダイレクト先のアドレスに付与されている情報から access token を導いていきます。
 
Implicit Grant
 
Implicit Grant で開く認可用の Web ページは以下の形になります。
    https://www.amazon.com/ap/oa?client_id=ClientID&scope=パーミッション指定&response_type=token&redirect_uri=リダイレクト先のアドレス
他人に知られてはいけない Client Secret の組み込みが不要なので クライアントアプリに向いています。 パーミッション指定は Scopes and Permissions の表Customer Profile から選びます (読み書き両方かつ利用者名が欲しいのであれば、 "clouddrive:read_all clouddrive:write profile")。 リダイレクト先のアドレスは、先ほどの Web Settings で設定した Allowed Return URLs の一つと一致していないとエラーになります。
 
リダイレクトされたページのアドレスには hash の形で情報がついており、 access token もその中にあります。
    リダイレクト先のアドレス#access_token=AccessToken&token_type=bearer&expires_in=3600&scope=パーミッション指定
そのため access token の取り出しは簡単ですが、 この access token は 1 時間しか有効ではありません。
 
Authorization Code Grant
 
Authorization Code Grant で開く認可用の Web ページは response_type の指定が違うだけです。
    https://www.amazon.com/ap/oa?client_id=ClientID&scope=パーミッション指定&response_type=code&redirect_uri=リダイレクト先のアドレス
リダイレクトされたページのアドレスには query の形で情報がついており、 その中の code を利用します。
    リダイレクト先のアドレス?code=code&scope=パーミッション指定
次に、code をアプリから認可用 API へ投げて、access token を受け取ります。 https://api.amazon.com/auth/o2/token へ以下の内容を POST で投げます (application/x-www-form-urlencoded 形式)。
    grant_type=authorization_code&code=code&client_id=ClientID&client_secret=ClientSecret&redirect_uri=リダイレクト先のアドレス
code は受け取ったものを、 リダイレクト先のアドレスは先ほどと同じものを渡します。 Client Secret の組み込みが必要なため、サーバーアプリ向けと言えます。 JSON 形式で情報が返ってきますが、 その中に key=access_token の値として access token が得られます。
 
これだけだと、Implicit Grant に比べて手間が増えただけに見えますが、 access token の更新ができるようになっています ( Authorization Code Grant 認可であっても access token は 1 時間で失効します)。 access token 以外に key=refresh_token の値として refresh token が得られるので、それを再び https://api.amazon.com/auth/o2/token へ POST で投げると更新できます。
    grant_type=refresh_token&refresh_token=RefreshToken&client_id=ClientID&client_secret=ClientSecret
返ってくる値は access token を始めに得たときと同じ形式です。 access token, refresh token ともに新しい値になっている点に注意です。

Amazon Drive API の呼び出し

access token が得られたら、後は各 API を目的に応じて簡単に呼び出せます。 各 REST API を呼ぶ際に HTTP ヘッダーとして以下の指定をするだけです。
    Authorization: Bearer AccessToken
API によって、GET, POST 以外に PUT, PATCH, DELETE メソッドも使います。 なお、OAuth 認可処理は Amazon の API 共通の処理で、 この Amazon Drive API とは若干設計思想に違いが見られます。 POST で投げるデータは認可時は application/x-www-form-urlencoded 形式でしたが、 Amazon Drive API では JSON 形式 (multipart もあり) に なる点に注意です。
 
Security Profile の Web Settings で Allowed Origins を指定してあれば、 レスポンスに Access-Control-Allow-Origin ヘッダーがその値で付与されるので、 JavaScript で XMLHttpRequest Level 2 を使ってクロスドメインアクセスで API を呼び出せます。
 
API の呼び先 (endpoint) は利用者によって異なりますので、 それを取得するために 始めに GET https://drive.amazonaws.com/drive/v1/account/endpoint を 呼ぶことになります。 metadataUrl (metadata 用の endpoint), contentUrl (content 用の endpoint) を 含んだ JSON データが返ってきますので、 API の種類に応じて endpoint を選んで使います。 この endpoint は 3〜5 日間キャッシュして 毎日呼ぶことのないように推奨されています。 ちなみに、metadata の endpoint は 固定アドレス https://drive.amazonaws.com/drive/v1/ で代用可能です (amazon.com アカウントに限り)。
	// JavaScriptのendpoint取得のサンプルコード
	//   accessToken = access token
	var xmlHttpRequest=new XMLHttpRequest();
	xmlHttpRequest.onreadystatechange=function() {
		if (xmlHttpRequest.readyState==4)
		{
			alert(xmlHttpRequest.response.metadataUrl+", "+xmlHttpRequest.response.contentUrl);
		}
	};
	xmlHttpRequest.open("GET","https://drive.amazonaws.com/drive/v1/account/endpoint",true);
	xmlHttpRequest.setRequestHeader("Authorization","Bearer "+accessToken);
	xmlHttpRequest.responseType="json";
	xmlHttpRequest.send();

Nodes API

Amazon Drive API ではファイルやフォルダを Node と呼びます。 Node はそれぞれ ID を持ち、 ファイル名や更新日などの属性情報である metadata と ファイルの実体である content で構成されます。 Node は親子関係を持ち、フォルダツリーが表現されています。
 
基本的な操作は Nodes API で実行できます。 Nodes API は Node に対する汎用的な処理機能が提供されているので、 目的の機能がどの API でできるかは Node に対してどのような操作になるかを考えれば分かります。
 
ルートフォルダの取得
 
ルートフォルダはノードの検索 API にルート指定をして呼べば得られます。
    GET metadataのendpoint/nodes?filters=isRoot:true
ファイルのリネーム
 
ファイルのリネームはノードの metadata である name の更新になります。
    PATCH metadataのendpoint/nodes/ファイルのID
    
    { "name": "新しいファイル名" }
ファイルの更新日
 
ファイルの更新日は metadata である modifiedDate に保持されています。 metadata の更新機能で変更できそうに見えますが、今はできるようには なっていません。 modifiedDate は Amazon Drive に最後にアップロードされた 日時に必ずなるため、アップロードしたファイルの更新日情報は 残念ながら反映できません。 変更できるようにして欲しいとの要望は開発チームに伝わっていますが、対応されるかどうかは不明 です。
 
ファイル・フォルダのキーワード検索
 
ドキュメントには書かれていませんが、ノードの検索 API に keywords: 指定でキーワード検索できるようです。 文字コードは UTF-8 です。 ただし、公式 Web UI の検索でもそうですが、 日本語のファイル名が希望通りに検索できないことがあります。
    GET metadataのendpoint/nodes?filters=keywords:検索語
ファイルのアップロード
 
ファイルのアップロードは新規と上書きで別々の API を使います。 multipart で情報を送りますが、 metadata の part を必ず先に、その内容は JSON 形式である点に注意です。
    POST contentのendpoint/nodes (新規アップロード)
    PUT contentのendpoint/nodes/ファイルのID/content (上書きアップロード)
	// JavaScriptの新規アップロードのサンプルコード
	//   file        = アップロードするFileオブジェクト
	//   parentId    = アップロード先のフォルダのID
	//   contentUrl  = contentのendpoint
	//   accessToken = access token
	var data=new FormData();
	data.append("metadata",JSON.stringify({
	    name      : file.name,
	    kind      : "FILE",
	    parents   : [ parentId ]
	}));
	data.append("content",file);
	
	var xmlHttpRequest=new XMLHttpRequest();
	xmlHttpRequest.onreadystatechange=function() {
		if (xmlHttpRequest.readyState==4)
		{
			// アップロード完了したファイルの metadata
			alert(xmlHttpRequest.response);
		}
	};
	xmlHttpRequest.upload.addEventListener("progress",function(event) {
		if (event.lengthComputable)
		{
			// event.loaded/event.total で進捗表示できる
		}
	},false);
	xmlHttpRequest.open("POST",contentUrl+"nodes?suppress=deduplication",true);
	xmlHttpRequest.setRequestHeader("Authorization","Bearer "+accessToken);
	xmlHttpRequest.responseType="json";
	xmlHttpRequest.send(data);
なお、Amazon Drive のファイルサイズの上限が 2GB までとの間違った情報がネットに散見されますが、 公式 Web UI だけの制限で (古いブラウザは 32bit までしか考慮されておらず 2GB 以上扱えない場合があるためだと思います)、 公式アプリや API で扱う限りは上限はありません。 0 サイズのファイルもアップロードできます。
 
アップロードでエラーがあったとき、全内容が送信完了してからエラーがでます。 すでにあるファイルに新規アップロードした時や、 access token が失効していたときも同様で、そのまま機能を使って実装すると 利用者にとっては長い時間待たされたあげく、 先に分かるはずのエラーを言われる状況になるため、 他の API 等で事前チェックしておくと良いです。 なお、接続開始した時点で access token が有効であれば、 全内容が送信完了した時に失効していても問題ありません。
 
また、アップロードのレジューム機能は 公式アプリ向けには実装されていますが、API 側への公開は日程不明 です。
 
巨大ファイルのダウンロード
 
9GB を超えるファイルに対してダウンロード API を呼び出すと、通常とは違い、 HTTPステータスコード 302 の転送コマンドが返ってきます。 Location ヘッダーにファイルの実体が取れる Amazon S3 上のアドレスが 示されていますので、そこから GET コマンドでファイルの実体をダウンロードできます。
 
この時、Authorization ヘッダーの指定は不要です。むしろ指定してしまうと 400 エラーになってしまいます ( Location ヘッダーに示されたアドレスに認可情報がすでに含まれているため)。 また、ファイル名に日本語が含まれていると、転送先アドレスに そのファイル名指定が入り、その対応ができない旨のエラーが返ってきます。 今は英数字だけのファイル名のみが対応しているようです。
 
Asset
 
特殊な Node として Asset があります。 ファイル Node の子として自動で生成される、そのファイルのサムネイルや ストリーミング再生用の動画データが Asset にあたります。 ファイルに対して子 Node を得る API でそれらを参照できます。
    GET metadataのendpoint/nodes/ファイルのID/children?filters=kind:ASSET
tempLink
 
ファイルをダウンロードする API はありますが、 それとは別に tempLink を使う方法が用意されています。 tempLink は一時的に使えるそのファイルの URL で、 access token なしにアクセスできるため扱いやすいものです。 ファイルの metadata を取得する際に tempLink 取得の指定をすれば、 tempLink が生成されて metadata に tempLink 情報が付きます。
    GET metadataのendpoint/nodes/ファイルのID?tempLink=true
また、動画ファイルなどの tempLink に viewBox クエリーを付けると、 そのサイズのサムネイル画像が得られます。
    <IMG SRC="tempLink?viewBox=320" /> (320×320 のサムネイル画像)
Properties
 
metadata に各アプリケーション固有の属性情報である Properties を載せることができます。 Properties はアプリケーションIDである Owner application Id と 任意の Key に対して値が設定出来ますが、 Key は 10 個まで、Owner 以外からは読み書きできない制限があります。 なお、公式アプリが設定する Owner application Id="CloudDrive" の 値だけは読めるようです。
    PUT metadataのendpoint/nodes/ファイルのID/properties/OwnerApplicationId/Key
    
    { "value": "設定する値" }
Owner application Id は Security Profile に設定した名前の後ろに ハイフンと内部で使われて居るであろう ID の英数字が並びますが、 困ったことにこの自分の Owner application Id を得る手段が 用意されていません。 適当に間違った Owner application Id を設定して API を呼ぶと 403 エラーになりますが、レスポンスの message の中に "Application Owner application Id does not have write access to properties" と自分の Owner application Id が書かれているので、 それで知ることはできます。
 
contentProperties
 
metadata にファイルの属性情報として contentProperties があります。 名前が似ていますが、Properties とは全く別ものです。 contentProperties はファイルの中身に応じた読み取り専用の情報で、 ファイルサイズ (contentProperties.size) や MD5 ハッシュ値 (contentProperties.md5) も含まれます。 画像や動画ファイルの場合、サイズや撮影日といったその属性情報 (Exif 情報など) が自動で解析されて contentProperties として 参照できるようになりますので、メディアファイルを扱う場合は便利です。

戻る