なんていうかもっと。

instagram あれこれで 3 記事ほど書いて、もっと簡単さをアピールできないかと思った結果、アクセストークンの取得だけなら a タグでリンク張ればできるということに気がついた。

instagram の遊び方。

開発者用のページからアプリケーション登録をします。(instagram のアカウントを取ってログインしてください。)

Manage ってリンクから行けます。

f:id:aerith:20111225033712p:plain

Register a New Client とかいうボタンを押します。

f:id:aerith:20111225033715p:plain

内容を入力して、Register とかいうボタンを押します。

f:id:aerith:20111225033718p:plain

これであなた用のアプリケーションを作る準備ができました。(CLIENT SECRET は隠してあります。)

f:id:aerith:20111225033720p:plain

こんな感じで index.html を作成します。

ログインに失敗した場合は、instagram 上でバリデーションしてくれます。ユーザがログインを放棄したら何も返ってきません。

ログインに成功して、アプリケーションを承認した場合、次のような URL でこちらにリダイレクトされます。

http://i.sakura.aerith.sc/demo/redirect.html#access_token=アクセストークン

ログインに成功して、アプリケーションを承認しない場合、次のような URL でこちらにリダイレクトされます。

http://i.sakura.aerith.sc/demo/redirect.html?error_reason=user_denied&error=access_denied&error_description=The+user+denied+your+request.

こんな感じで redirect.html を作成します。

簡易的にですが、承認失敗時のエラーもいちおう出しています。アクセストークン取得後に、page.html に飛ばしています。

こんな感じで page.html を作成します。

これで自分のフィードのサムネイル画像の一覧を表示できました。

データはこんな感じなので、ユーザ名やその写真に使ったフィルターの名前なんかも表示することができます。

もちろん他にも取れるデータはあるので、いろいろと試してみると面白いかもしれません。取得するデータによってはパーミッションを承認時に指定する必要がある場合があります。そのあたりはドキュメントを参照してみてください。

instagram で遊ぶ前に説明。

instagram で遊ぶためにはどうしたらいいのか、サイトのドキュメントを交えて流れを追っていきます。認証に関する説明は、ドキュメントのこのページに記載されています。(訳に関しては意訳でかなりぐだぐだですが気にしないでください。間違いがあった場合の訂正は、ぜひよろしくおねがいします。)

Instagram は簡易で、しかし効果的な認証と承認のため、OAuth 2.0 プロトコルを利用しています。

Instagram's API uses the OAuth 2.0 protocol for simple, yet effective authentication and authorization.

あなたは認証する必要がありますか?

多くの場合、あなたはユーザを認証させなくてもいい、ということに注意してください。たとえば、あなたが今日人気の写真を見せるシンプルなアプリケーションを作るとします。この場合、あなたは API からデータを読むのにアクセストークンを持つ必要はありません。ただ、あなたのクライアント ID をリクエスト時に利用してください。あなたが認証されたユーザに代わってアクセスすることを強制したいときだけ、アクセストークンを必須要件にしています。

Note that in many situations, you may not authenticate users at all. For instance, you may create an app that simply shows the most popular photos today. In this case, you do not need to have an access_token to read from the API – just use your client ID with your request. We have only included the access_token requirement where we would like to enforce that you are representing an authenticated user (commenting, liking, browsing a user’s feeds).

アクセストークンの受け取り

ユーザに代わってAPIにアクセスするためにアクセストークンを受け取るには、あなたは二つのことをする必要があります。

In order to receive an access_token to access the API on a user's behalf, you must do two things

ユーザに代わってAPIにアクセスするためにアクセストークンを受け取るには、あなたは二つのことをする必要があります。

  • 承認用のURLにユーザを誘導してください。もしユーザがログインしていなかったら、ログインするかどうかを確認します。さらにどちらにせよ、instagram で所有してるデータにあなたのアプリケーションをアクセスさせたいかどうかをユーザに確認します。
  • そのあとサーバは、ふたつのうちから選んだあなたの方法でユーザをリダイレクトします。
    1. 一つ目は(アプリケーションの大半に推奨している)サーバーサイドフローとして知られる流れです。あなたがコードという値とともに指定した URI にユーザをリダイレクトさせます。そうしたらコードをうけとり、アクセストークンを取得するための URL にコードを POST で送信することで、認証されたユーザ用のアクセストークンとコードを引き換えます。
    2. 二つ目は暗黙的な流れとして知られています。この流れではユーザをコード付きの URI にリダイレクトさせる代わりに、アクセストークンを URL のフラグメント(#) の値としてアクセストークンを含めます。この手法だとサーバの要素のないアプリケーションが簡単にアクセストークンを受け取ることができます。

In order to receive an access_token to access the API on a user's behalf, you must do two things:

  • Direct the user to our authorization url. If the user is not logged in, they will be asked to login. Either way, they will the be asked if they'd like to give your application access to his or her Instagram data.
  • The server will then redirect the user in one of two ways that you choose:
    1. The first flow (which we recommend for the majority of applications) is known as the server-side flow. It involves us redirecting the user to a URI of your choice with a code parameter in the URL. You then take this code, and exchange it for an access_token for the authenticated user by POSTing the code to our access_token url.
    2. The second flow is known as the implicit flow. In this flow, instead of redirecting to a URI with a code, we include the access_token as a fragment (#) in the URL. This method allows applications without any server-component to receive an access_token with ease.

今回使用するのは、2つ目の暗黙的なフローです。

クライアント側での(暗黙的な)認証

ステップ1: 承認用のURLにユーザを誘導してください。

https://instagram.com/oauth/authorize/?client_id=CLIENT-ID&redirect_uri=REDIRECT-URI&response_type=token

ステップ2: URL のフラグメントを通してアクセストークンを受け取ってください。

いったんユーザが認証し、あなたのアプリケーションを承認した後、アクセストークンを URL のフラグメントに含めたリダイレクト用の URI にユーザをリダイレクトします。

https://instagram.com/oauth/authorize/?client_id=CLIENT-ID&redirect_uri=REDIRECT-URI&response_type=token

ただ単純に URL のフラグメントからアクセストークンを取得すればいいだけです。もしユーザがアプリケーションを承認しなかった場合、あなたは同じエラー明示的な流れとして受け取ることになります。

Once the user has authenticated and then authorized your application, we'll redirect them to your redirect_uri with the access_token in the url fragment. It'll look like so:

http://your-redirect-uri#access_token=ACCESS-TOKEN

Simply grab the access_token off the URL fragment and you're good to go. If the user chooses not to authorize your application, you'll receive the same error response as in the explicit flow

まとめ

要約すると、「ユーザを承認用の URL に飛ばせば、instagram 側で認証と承認をしたあとに結果を URL で返すので、URL から情報を取得してください。」ということになります。

instagram で遊ぼう。

おはようございます。こんにちは、こんばんは。JavaScript Advent Calendar 2011 の 19 日目の記事になります。@aerith です。JavaScript の話そんなにまったくないです。

  1. サンプルデータが欲しい。
  2. 気軽に UI 設計の練習したい。
  3. なんでもいいから作りたい。

上記のようなことをやろうと思ったときに JavaScript は、「なんでもいいから作りたい。」「気軽に練習したい。」の部分はとても満たしてくれます。

さらに最近では jQuery や Ext JS、prototype.js なんかのフレームワークもこなれてきて、自分でクロスブラウザ対応を考えたりすることも減ってきているので。いきなりフレームワークを使う是非は置いておきますが、比較的とっつきやすい言語なんじゃないかなあと思っています。

でも JavaScript でサンプルデータが欲しいって思ったときに、実際どうしますか?自分でアプリを作れる人はそれで済みます。でも、みんながみんな一度にいくつもの言語を覚えることができるわけではないです。かといって例えば、サーバに CSV とか XML とか YAML とか JSON を手書きしてアップロードする、というのはあまり現実的ではないです。しかもそれにしたって、なんとか太郎とかかくかく花子とかいうデータばかり見てても何が正しいのかわからなくなってきますし、生きたデータが手にはいるならそれに越したことないです。(今だと JSONP とかありますけどね。/ iframe から抜いたりとか。/ JavaScript だけで認証下のデータを取得できて、それが仕様化されてるのがすごい。)

それで instagram さんで遊んでみたわけなのですが。

  1. ドキュメントが割としっかりしてる(英語だけど、返ってくるデータの構造も記載されているので、理解できなくてもなんとかなります。)
  2. 返ってくるデータの構造が好き(他の方はどうだかわかりません。)
  3. そもそもパソコンからだとまともに見れない(iPhone 用に特化したサイトなのでしょうがないです。)
  4. 上記理由からパソコン用のアプリケーションを作るのは比較的モチベーションになりやすい。
  5. デモページ作りながら食べたにくまんとかおでんおいしかった。

instagram さんは、OAuth 2.0 プロトコルを採用した認証方法が API にあって、上記の「サンプルデータが欲しい。」という用件を JavaScript だけで満たすことができます。

このサイト用に実装したファイルは以下の 3 点です。

  1. http://i.sakura.aerith.sc/index.html
  2. http://i.sakura.aerith.sc/javascripts/asayake.js
  3. http://i.sakura.aerith.sc/stylesheets/content.css

(中はそんなに大事でもないので、暇な方だけ追ってください。ページを開いたときにトークンがあるかどうかを見てその結果で認証 → ページの初期化 → データの取得 → 要素の追加 → アクションの付与、がおおざっぱな流れになります。)

ぼくが知ってるころといえば、取得するデータの数だけ裏側に CGI とか作ったり(クエリストリングとかポストデータで切り替えとかはしてましたけど。)、JavaScript も ページとかグローバルメニューのカテゴリ分だけ用意したり、ちょっとしたものを試そうとするだけでもちょっと大変でした(ぼくが無能なだけです。)。ぼくが始めて JavaScript をやったときは、本に載ってた document.writeLn を document.writeIn だと勘違いしてサンプルを動かすことができずに、一回挫折しました。

(こんなのはちょっとした笑い話で、今回のデモページ作るのも、自分の打ち間違いを直してた時間のほうが実装時間よりも長かったので、実装にはまったく関係なくて、ドジをいい加減直そうっていうだけなのですが。)

閑話休題、最近ではベースの HTML を一枚用意しておいて、API を経由して要素を操作して作る、1ページのアプリケーションが流行ってきています。たぶん。

上のデモページもそんな感じを若干意識してます。これは見るだけですが、写真やフォローしてる人をページ繰りで取得したり、画像に star/unstar できたり、コメントをつけられる用にしたら、そこそこ使えるパソコン用のアプリケーションになります。見るだけとはいえ、いろんな人の写真を自分が動かせているのは楽しい。こういうのも、生きたデータの利点だと思います。

(SPA でも OPA でもいんですけど、どっちもえっちくないですか?おっぱいおっぱい。失礼しました。)

だらだらと長いこと書きましたけど。

  1. 別に instagram じゃなくても OAuth 2.0 対応サイトならどこでもよかった。
  2. でも、instagram さんくらいドキュメントがしっかりできていれば見ただけでだいたいどう作ればいいかわかってすごい。
  3. google 先生とか他の人のサイトを呼んでいいところはどんどんパクろう。
  4. Twitter とかでも簡単に聞けたりしてすごい。
  5. フレームワークとか、JSONP とか OAuth 2.0 とか人に聞ける環境とかどんどん環境よくなるし、JavaScript 楽しいのでやってみてください。

みんなが楽しくモノ作りをできますように。次は @nazomikan さんです。エントリあげるの遅くなってごめんなさい!!

追記しました。

  1. instagram で遊ぶ前に説明。
  2. instagram の遊び方。

N-gram ってなに…。

def ngram(target, n)
    analyzed = []

    keywords = target.split(//u)

    keywords.size.times do |i|
        keyword = keywords[i, n].delete_if { |i| i.nil? || i.blank? || i.match(/^\s+$/) }
        next if keyword.size < n
        analyzed << keyword.join
    end

    analyzed.join(" ")
end

なんか作ってくださいって言われたので作った。文字列を n 文字で分割したものを作ればいいのかなくらいしか理解してない!無知でほんとうにごめんなさい。

他の人の作ったメソッドを見てみると、もっと長かったり、いろいろなことをしてたので、これじゃダメなのかなーと思いました。

あと、Ruby 久しぶりすぎて、delete_if のあたりとか一発でできるメソッドありそう…。

instagram さんについて軽く調べたのでメモ。

  • ユーザブロック機能とか、スパムユーザの報告機能があったのに気づいてなかった。アプリだと、ユーザの画面開いて右上の歯車っぽいアイコンから。
  • 公開状態の切り替え機能があるけど、api でユーザのデータとってきても、その中に公開状態のデータがない。
  • 公開状態は /users/{hoge さんの id}/relationships でとれる。
  • target_user_is_private の値が 1 だったらプライベート、空文字だったら公開。
  • 自分がプライベートかどうかは /users/self から自分の id を取得してから、/users/{自分のid}/relationships から取れる。
  • /users/self/relationship みたいなのはなかった。めんどくさい。(あっても変わらない気がするけど。あったらあったで URL、それどうなのという感じするけど。)

instagram で遊んだスクリプトがこれ。

#!/usr/bin/perl
use strict;
use warnings;

use Config::Pit;
use LWP::UserAgent;
use HTTP::Cookies;
use URI;
use URI::QueryParam;
use JSON::Syck;

my $config = pit_get('aerith.instagr.am', require => {
    username => 'your username',
    password => 'your password',
    access_token => 'your token on instagram'
});

my $api_base = 'https://api.instagram.com/v1';
my $api_path = shift || '/users/self/feed';

my $agent = LWP::UserAgent->new();
$agent->cookie_jar(HTTP::Cookies->new);

my $login_uri = URI->new('https://instagram.com/accounts/login/');
my $login = $agent->post($login_uri, {
    username => $config->{username},
    password => $config->{password},
});

if ($login->is_redirect && $login->content eq '') {
    my $endpoint = URI->new($api_base.$api_path);
    $endpoint->query_param_append(access_token => $config->{access_token});

    my $request = $agent->get($endpoint);

    print YAML::Syck::Dump(JSON::Syck::Load($request->content));
} else {
    print "Authentication failed.";
}

exit;

__DATA__

アクセストークン取得はまた別の話。

インストールした Redmine を動かしてみた。

$ gem install unicorn --no-rdoc --no-ri
$ nohup unicorn --host 127.0.0.1 --port 19292 &

バーチャルホストの設定

$ sudo su -
$ cd /etc/nginx/site-enabled
$ touch /etc/nginx/sites-available/00n-redmine.aerith.sc
$ ln -s /etc/nginx/sites-available/00n-redmine.aerith.sc redmine.aerith.sc
$ vim /etc/nginx/sites-available/00n-redmine.aerith.sc
server {
        listen 80;
        server_name redmine.aerith.sc;
        server_name_in_redirect off;
        error_log /var/log/nginx/redmine.aerith.sc.error.log;
        access_log /var/log/nginx/redmine.aerith.sc.access.log;

        location /javascripts {
                alias /home/redmine/redmine-1.2.1/public/javascripts;
        }

        location /stylesheets {
                alias /home/redmine/redmine-1.2.1/public/stylesheets;
} location /images { alias /home/redmine/redmine-1.2.1/public/images;
} location /themes { alias /home/redmine/redmine-1.2.1/public/themes;
} location /help { alias /home/redmine/redmine-1.2.1/public/help;
} location /files { alias /home/redmine/redmine-1.2.1/files;
} location / { proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Forwarded-Server $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_pass http://127.0.0.1:19292/; } }
$ /etc/init.d/nginx restart

うごいたー。