Firefox OSのTwitter APIライブラリを作っているという話は前述の通り。
すっかり忘れていたけれど、es6-promiseとか使うとWindowsのVisual Studio(JavaScript)を使った開発でもこのviolet.jsを使うことができる。
閑話休題。Twitterに画像を投稿する方法は2つ。
POST statuses/update_with_media
を使うPOST media/upload
を使ってから、POST statuses/update
を使う
前者はすでにdeprecatedなので、今後作られるTwitterクライアントでは後者を採用するのが望ましい。ここでは後者について解説する。
POST media/upload
で写真を送信する
POST media/upload
では写真を1枚ずつmultipart/form-dataで送信する。返り値のmedia_idをPOST statuses/update
の引数に渡すことで画像のツイートを行うことができる。
Authorizationヘッダの生成
投稿には当然OAuthが必要になる。oauth_signatureの作り方等は以前紹介しているのでこちらを参照のこと。
必要なOAuthパラメータは以下の通り
- oauth_consumer_key
- oauth_nonce
- oauth_signature
- oauth_signature_method
- oauth_timestamp
- oauth_token
- oauth_version
通常、POSTリクエストでRESTエンドポイントを叩く場合はリクエストボディもsignatureの生成時にパラメータに含める必要があるが、POST media/upload
の場合は必要ない。それ以外は通常どおりの認証プロセスとなる。
これ以降はOAuthの認証は突破できたものとして扱う。
JavaScriptでファイルを送信する
XMLHttpRequest Level2から、send時にFormDataを引数に渡すことにより自動的にmultipartで送信されるようになっている。
サンプルコード
HTML
<input type="file" id="file">
JavaScript
var data = document.querySelector('#file').files; var fd = new FormData(); // mediaパラメータが必須なので、第一引数は必ずmedia fd.append("media", data[0]); var xhr = new XMLHttpRequest({mozSystem: true}); xhr.open("POST", "https://upload.twitter.com/1.1/media/upload.json", true); xhr.setRequestHeader('Authorization', /* 生成したOAuthのヘッダ */); xhr.send(fd); xhr.addEventListener('load', function() { console.log(JSON.parse(xhr.responseText)); });
勢い的にはこのようなコードで良い。注意点として
- FQDNはapi.twitter.comではなくupload.twitter.com
- xhr.setRequestHeaderでmultipart/form-dataを指定する必要はない
- FormDataを引数にすると自動でmultipart/form-dataになる
- 自前で指定するとbounderyが指定されずBad Requestが返る
リクエストに成功するとmedia_idを含むJSONが返る。
POST statuses/update
で写真を投稿する
前項で得たmedia_id_strをPOST statuses/update
の引数に含める。media_idsにmedia_id_strを指定する。複数指定したい場合はカンマで繋げば良い。
まとめ
以上がJavaScriptでTwitterに画像を投稿する概略である。violet.jsのdevelopブランチに同様のコミットを追加しているので分からないことがあればこれを参照すると良い。
GitHub - masawada/violet at develop
--- 追記 ---
JavaScriptでTwitterに画像を投稿する - あんパン手でmultipart/form-data指定するとboundery空になるの不思議な感じする.手でboundary指定したらどうなるんだろ
2015/02/01 18:24
手でmultipart/form-data指定するとboundery空になるの不思議な感じする.手でboundary指定したらどうなるんだろ - side_tanaのコメント / はてなブックマーク
setRequestHeaderを行わないでおくと自動で以下のようなContent-Typeが設定される。
Content-Type: "multipart/form-data; boundary=---------------------------84533449419325157531249583443"
自前でsetRequestHeaderするとこれがmultipart/form-dataで上書きされてしまうのでboundaryを識別できずmediaパラメータがないというエラー(Bad Request)が返ってくる。
setRequesHeaderでmultipart/form-data; boundary=...
というような設定すれば良いのだろうがそもそもFormDataをsendする際にboundaryを自動生成してくれるため、それを知る術がなく設定ができないという話でした。
あと綴りboundaryだった。