├── vba ├── Sheet1 └── README.md ├── c ├── utils.h ├── Makefile ├── README.md ├── http.h ├── mixi.h ├── utils.c ├── test.c ├── mixi.c └── http.c ├── Clojure ├── .gitignore ├── project.clj ├── README.markdown ├── test │ └── clj_mixi_graph_api │ │ └── test │ │ └── core.clj └── src │ └── clj_mixi_graph_api │ └── core.clj ├── golang ├── Makefile ├── config.json ├── README.md └── mixi.go ├── .gitmodules ├── Python ├── app.yaml ├── README.md ├── mixi.html └── mixi.py ├── scala ├── build.sbt ├── README.md └── src │ └── main │ └── scala │ ├── example02 │ └── Main.scala │ └── example01 │ └── Main.scala ├── cpp ├── Makefile ├── README.md └── sample.cpp ├── chrome ├── README.md ├── manifest.json ├── mixi.html └── mixi.js ├── Java ├── README.md └── Mixi.java ├── Perl ├── README.md └── sample.pl ├── objc ├── README.md └── main.m ├── PHP ├── README.md └── sample.php ├── Ruby ├── README.md └── sample.rb ├── haskell ├── README.md └── show_friend.hs ├── android └── README.md ├── erlang ├── README.md ├── test.erl └── mixi.erl ├── R ├── README.md ├── sample.R └── lib │ └── mixiGraphAPI.R ├── README.md ├── bash ├── README.md └── mixi.sh └── cs ├── README.md └── Main.cs /vba/Sheet1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mixi-inc/mixi_graph_api_examples/HEAD/vba/Sheet1 -------------------------------------------------------------------------------- /c/utils.h: -------------------------------------------------------------------------------- 1 | int get_integer_digit(int len); 2 | 3 | char* new_concat_strings(int len, ...); 4 | -------------------------------------------------------------------------------- /Clojure/.gitignore: -------------------------------------------------------------------------------- 1 | pom.xml 2 | *jar 3 | /lib/ 4 | /classes/ 5 | .lein-failures 6 | .lein-deps-sum 7 | -------------------------------------------------------------------------------- /golang/Makefile: -------------------------------------------------------------------------------- 1 | include $(GOROOT)/src/Make.inc 2 | 3 | TARG=mixi 4 | GOFILES=\ 5 | mixi.go\ 6 | 7 | include $(GOROOT)/src/Make.cmd 8 | -------------------------------------------------------------------------------- /golang/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "client_id":"YOUR CLIENT ID", 3 | "client_secret":"YOUR SECRET", 4 | "redirect_port":"8080" 5 | } 6 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "android/oauth_people"] 2 | path = android/oauth_people 3 | url = git://github.com/tnj/AndroidOAuthExample.git 4 | -------------------------------------------------------------------------------- /Python/app.yaml: -------------------------------------------------------------------------------- 1 | application: *********** 2 | version: 1 3 | runtime: python 4 | api_version: 1 5 | 6 | handlers: 7 | - url: /.* 8 | script: mixi.py -------------------------------------------------------------------------------- /scala/build.sbt: -------------------------------------------------------------------------------- 1 | name := "mixi Graph API Example" 2 | 3 | version := "1.0" 4 | 5 | libraryDependencies ++= Seq( 6 | "commons-httpclient" % "commons-httpclient" % "3.1", 7 | "net.debasishg" %% "sjson" % "0.15" 8 | ) 9 | -------------------------------------------------------------------------------- /cpp/Makefile: -------------------------------------------------------------------------------- 1 | #Makefile 2 | LIBS=-lssl \ 3 | -lutilspp \ 4 | 5 | LIB_DIR= 6 | 7 | INCLUDES= 8 | 9 | default: 10 | gcc $(LIB_DIR) $(LIBS) $(INCLUDES) -o mixi_sample sample.cpp 11 | 12 | clean: 13 | rm mixi_sample 14 | -------------------------------------------------------------------------------- /chrome/README.md: -------------------------------------------------------------------------------- 1 | # Chrome Extension版 2 | 3 | ## 実行手順 4 | 5 | 1. Chromeで chrome://extensions にアクセス 6 | 2. 「パッケージ化されていない拡張機能を読み込む...」をクリックして manifest.json を含むディレクトリを選択 7 | 3. 新規タブを開き、「Mixi Chrome Extension Example」をクリック 8 | 4. 画面の指示に従う 9 | -------------------------------------------------------------------------------- /Python/README.md: -------------------------------------------------------------------------------- 1 | # 実行手順 2 | 3 | 1. mixi Partner DashboardでリダイレクトURLを [http://localhost:8080] にしたアプリを登録(ポート番号は任意) 4 | 2. app.yamlのプロジェクトを適切な内容に修正する 5 | 3. mixi.pyのCONSUMER_KEYとCONSUMER_SECRETを適切な内容に修正する 6 | 4. localhost:8080でGoogle App Engineを起動 7 | 5. ブラウザで[http://localhost8080/login]を開く 8 | -------------------------------------------------------------------------------- /Clojure/project.clj: -------------------------------------------------------------------------------- 1 | (defproject clj-mixi-graph-api "1.0.0-SNAPSHOT" 2 | :description "Clojure sample for using mixi Graph API." 3 | :dependencies [[org.clojure/clojure "1.3.0"] 4 | [clj-apache-http "2.3.2"] 5 | [clj-json "0.4.3"]] 6 | :main clj-mixi-graph-api.core) 7 | -------------------------------------------------------------------------------- /chrome/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Mixi Chrome Extension Example", 3 | "version": "1.0", 4 | "description": "Use mixi Graph API", 5 | "app": { 6 | "launch": { 7 | "local_path": "mixi.html" 8 | } 9 | }, 10 | "permissions": [ 11 | "*://*.mixi-platform.com/" 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /Java/README.md: -------------------------------------------------------------------------------- 1 | # 実行方法 2 | 3 | ## Authorization codeの入手 4 | 5 | 以下のURLにWebブラウザにてアクセスし、リダイレクト先に含まれるcodeパラメータ値を入手する。 6 | 7 | https://mixi.jp/connect_authorize.pl?client_id=Consumer key&scope=r_profile 8 | 9 | ## 実行 10 | 11 | $> cd Mixi.javaを保存したディレクトリパス 12 | $> javac Mixi.java 13 | $> java Mixi codeパラメータ値 14 | -------------------------------------------------------------------------------- /Perl/README.md: -------------------------------------------------------------------------------- 1 | # 実行手順 2 | ## コードの書き換え 3 | コード内のCONSUMER_KEY, CONSUMER_SECRET, REDIRECT_URIを適切に書き換えてください。 4 | ## Authorization codeの入手 5 | 以下のURLにWebブラウザにてアクセスし、リダイレクト先に含まれるcodeパラメータ値を入手する。 6 | 7 | https://mixi.jp/connect_authorize.pl?client_id=[YOUR CONSUMER KEY]&scope=r_profile 8 | 9 | ## 実行 10 | 11 | $ sample.pl [codeパラメータ値] 12 | 13 | -------------------------------------------------------------------------------- /objc/README.md: -------------------------------------------------------------------------------- 1 | # 実行方法 2 | 3 | ## Authorization codeの入手 4 | 5 | 以下のURLにWebブラウザにてアクセスし、リダイレクト先に含まれるcodeパラメータ値を入手する。 6 | 7 | https://mixi.jp/connect_authorize.pl?client_id=Consumer key&scope=r_profile 8 | 9 | ## 実行 10 | 11 | $> cd main.mを保存したディレクトリパス 12 | $> gcc -fobjc-gc -framework Foundation main.m 13 | $> ./a.out codeパラメータ値 14 | -------------------------------------------------------------------------------- /Python/mixi.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | python sample code for mixi graph api 4 | 5 | 6 |

友人一覧


7 | {% for row in results %} 8 | {{row.displayName}}
9 | {% endfor %} 10 | 11 | -------------------------------------------------------------------------------- /PHP/README.md: -------------------------------------------------------------------------------- 1 | # Requirement 2 | 3 | PHP >= 5.3.0 4 | 5 | # 実行手順 6 | ## コードの書き換え 7 | コード内のCONSUMER_KEY, CONSUMER_SECRET, REDIRECT_URIを適切に書き換えてください。 8 | ## Authorization codeの入手 9 | 以下のURLにWebブラウザにてアクセスし、リダイレクト先に含まれるcodeパラメータ値を入手する。 10 | 11 | https://mixi.jp/connect_authorize.pl?client_id=[YOUR CONSUMER KEY]&scope=r_profile 12 | 13 | ## 実行 14 | 15 | $ sample.php [codeパラメータ値] 16 | 17 | -------------------------------------------------------------------------------- /Ruby/README.md: -------------------------------------------------------------------------------- 1 | # 実行手順 2 | ## gemのインストール 3 | JSONをインストールする。 4 | 5 | $gem install json 6 | 7 | ## コードの書き換え 8 | コード内のconsumer_key, consumer_secret, redirect_uriを適切に書き換えてください。 9 | ## Authorization codeの入手 10 | 以下のURLにWebブラウザにてアクセスし、リダイレクト先に含まれるcodeパラメータ値を入手する。 11 | 12 | https://mixi.jp/connect_authorize.pl?client_id=[YOUR CONSUMER KEY]&scope=r_profile 13 | 14 | ## 実行 15 | 16 | $ ruby sample.rb 17 | input Authorization code > [codeパラメータ値] 18 | -------------------------------------------------------------------------------- /c/Makefile: -------------------------------------------------------------------------------- 1 | CC = gcc 2 | OBJ = utils.o http.o mixi.o test.o 3 | 4 | all: test 5 | 6 | test: $(OBJ) 7 | $(CC) $(OBJ) -o test -lssl -lcrypto 8 | 9 | utils.o: utils.c 10 | gcc -c utils.c 11 | 12 | utils.o: utils.h 13 | 14 | http.o: http.c 15 | gcc -c http.c 16 | 17 | http.o: http.h 18 | 19 | mixi.o: mixi.c 20 | gcc -c mixi.c 21 | 22 | mixi.o: mixi.h 23 | 24 | test.o: test.c 25 | gcc -c test.c 26 | 27 | clean: 28 | rm -f test utils.o http.o mixi.o test.o 29 | -------------------------------------------------------------------------------- /cpp/README.md: -------------------------------------------------------------------------------- 1 | # 実行方法 2 | ## Authorization codeの入手 3 | 4 | 以下のURLにWebブラウザにてアクセスし、リダイレクト先に含まれるcodeパラメータ値を入手する。 5 | 6 | https://mixi.jp/connect_authorize.pl?client_id=Consumer key&scope=r_profile 7 | 8 | ## コンパイル時に必要なもの 9 | GCC(gcc (GCC) 4.1.2 20080704 で動作確認をしています) 10 | OpenSSL(http://www.openssl.org/) 11 | CLX(http://clx.cielquis.net/) 12 | 13 | ## 実行 14 | 1. Makefileを必要に応じて変更する 15 | 2. makeを実行する 16 | 3. mixi_sample 取得したAuthorization Code を実行 17 | -------------------------------------------------------------------------------- /golang/README.md: -------------------------------------------------------------------------------- 1 | # 実行手順 2 | 3 | 1. mixi Developer DashboardでリダイレクトURLを [http://localhost:8080] にしたアプリを登録(ポート番号は任意) 4 | 2. config.jsonを作成 5 | 6 | { 7 | "client_id":"YOUR CLIENT ID", 8 | "client_secret":"YOUR SECRET", 9 | "redirect_port":"8080" 10 | } 11 | 12 | 3. コンパイルしてサーバー起動 13 | 14 | $ 6g mixi.go 15 | $ 6l mixi.6 16 | $ 6.out 17 | Please open http://localhost:8080 on a web browser. 18 | 19 | 4. ブラウザで [http://localhost:8080] を開く 20 | -------------------------------------------------------------------------------- /haskell/README.md: -------------------------------------------------------------------------------- 1 | # 実行手順 2 | 3 | ## 依存モジュールのインストール 4 | 5 | > $ cabal install json 6 | 7 | > $ cabal install http-enumerator 8 | 9 | ## Authorization codeの入手 10 | 11 | 以下のURLにWebブラウザにてアクセスし、リダイレクト先に含まれるcodeパラメータ値を入手する。 12 | 13 | https://mixi.jp/connect_authorize.pl?client_id=Consumer key&scope=r_profile 14 | 15 | ## Consumer Key, Consumer Secret を書きかえ 16 | 17 | > $ vim show_friend.hs # clientId, clientSecret をそれぞれ適切な値に編集 18 | 19 | ## 実行 20 | 21 | > $ runghc show_friend.hs ${取得したcode値} 22 | -------------------------------------------------------------------------------- /c/README.md: -------------------------------------------------------------------------------- 1 | # 実行手順 2 | 3 | ## 必要なもの 4 | 5 | > OpenSSL 6 | 7 | > GNU開発環境 8 | 9 | ## Authorization codeの入手 10 | 11 | 以下のURLにWebブラウザにてアクセスし、リダイレクト先に含まれるcodeパラメータ値を入手する。 12 | 13 | https://mixi.jp/connect_authorize.pl?client_id=Consumer key&scope=r_profile 14 | 15 | ## コードの修正 16 | 17 | test.c ファイルにある以下の文字列を適切なものに変更する。 18 | 19 | > YOUR CLIENT ID 20 | 21 | > YOUR CLIENT SECRET 22 | 23 | > YOUR REDIRECT URI 24 | 25 | ※ REDIRECT URIは、URLエンコード済みの文字列を記載してください。 26 | 27 | ## 実行 28 | 29 | $> make 30 | $> ./test codeパラメータ値 31 | -------------------------------------------------------------------------------- /android/README.md: -------------------------------------------------------------------------------- 1 | mixi Graph API Sample Codes for Android 2 | =============== 3 | 4 | Android で mixi Graph API を使用するためのサンプルコードです。 5 | mixi API SDK for Android を *使用しない* で、 mixi Graph API を使用する例となります。 6 | 7 | oauth_people 8 | --------------- 9 | このサンプルでは、 Android 上で mixi Graph API を利用するために必要な 10 | OAuth 2.0 の認証認可の手続きと、アクセストークンのリフレッシュ機構、 11 | および People API を用いた、友人一覧の取得処理を実装しています。 12 | 13 | コードについての解説は、以下の記事をご参照ください。 14 | 15 | "ネイティブアプリで実践! mixi Graph API活用法 OAuth 2.0を使うソーシャルなAndroidアプリの作り方" 16 | http://www.atmarkit.co.jp/fsmart/articles/androidmixi/01.html 17 | 18 | -------------------------------------------------------------------------------- /erlang/README.md: -------------------------------------------------------------------------------- 1 | # 実行手順 2 | 3 | ## mochiwebのインストール 4 | 5 | $> cd 6 | $> git clone git://github.com/mochi/mochiweb.git 7 | $> vi .bashrc 8 | $> source .bashrc 9 | 10 | .bashrcには以下を記述する。 11 | 12 | export ERL_LIBS=githubから入手したmochiwebのディレクトリパス 13 | 14 | ## Authorization codeの入手 15 | 16 | 以下のURLにWebブラウザにてアクセスし、リダイレクト先に含まれるcodeパラメータ値を入手する。 17 | 18 | https://mixi.jp/connect_authorize.pl?client_id=Consumer key&scope=r_profile 19 | 20 | ## 実行 21 | 22 | $> cd mixi.erlとtest.erlを保存したディレクトリパス 23 | $> erl 24 | 1> c(mixi). 25 | 2> c(test). 26 | 3> test:main("codeパラメータ値"). 27 | -------------------------------------------------------------------------------- /R/README.md: -------------------------------------------------------------------------------- 1 | # 実行手順 2 | ## R packageのインストール 3 | rjson,RCurlをインストールします。 4 | 5 | In your R console: 6 | > install.packages("rjson") 7 | > install.packages("RCurl") 8 | 9 | RCurlの依存ライブラリとしてlibcurl([http://curl.haxx.se.]())が必要です。 10 | 11 | 12 | ## コードの書き換え 13 | コード内のconsumer\_key, consumer\_secret, redirect\_uriを適切に書き換えてください。 14 | ## Authorization codeの入手 15 | 以下のURLにWebブラウザにてアクセスし、リダイレクト先に含まれるcodeパラメータ値を入手する。 16 | 17 | https://mixi.jp/connect_authorize.pl?client_id=[YOUR CONSUMER KEY]&scope=r_profile 18 | 19 | ## 実行 20 | 21 | $ Rscript sample.R 22 | Input Authorization Code : [codeパラメータ値] 23 | -------------------------------------------------------------------------------- /R/sample.R: -------------------------------------------------------------------------------- 1 | #demonstration 2 | 3 | #load library 4 | source("./lib/mixiGraphAPI.R") 5 | library(rjson) 6 | library(RCurl) 7 | 8 | grant_type ="authorization_code" 9 | client_id ="YOUR CONSUMER KEY" 10 | client_secret ="YOUR CONSUMER SECRET" 11 | redirect_uri ="YOUR REDIRECT URI" 12 | 13 | cat("Input Authorization Code : ") 14 | code <-readLines(file("stdin"),1) 15 | 16 | token<-get_token(client_id,client_secret,code,redirect_uri) 17 | print(token) 18 | 19 | people<-get_people("@friends",token$access_token) 20 | print(people) 21 | 22 | refreshed_token<-refresh_token(token$refresh_token,client_id,client_secret) 23 | print(refreshed_token) 24 | 25 | -------------------------------------------------------------------------------- /scala/README.md: -------------------------------------------------------------------------------- 1 | # 実行方法 2 | 3 | ## sbt 0.11 のセットアップ 4 | 5 | https://github.com/harrah/xsbt/wiki/Setup を参考に sbt をセットアップする。 6 | 7 | ## Authorization codeの入手 8 | 9 | 以下のURLにWebブラウザにてアクセスし、リダイレクト先に含まれるcodeパラメータ値を入手する。 10 | 11 | https://mixi.jp/connect_authorize.pl?client_id=Consumer key&scope=r_profile 12 | 13 | ## Consumer Key および Consumer Sercret を書き換える 14 | 15 | object Main { 16 | val CONSUMER_KEY = "XXXXXXXX" 17 | val CONSUMER_SECRET = "XXXXXXXXXXXXXXXX" 18 | : 19 | } 20 | 21 | ## 実行 22 | 23 | $ sbt 24 | > run 25 | 26 | example01.Main と example02.Main のどちらを実行するか聞かれるので、実行する方を選択します。 27 | example01.Main ではユーザIDとグループIDの入力待ちになります。それぞれをスペース区切りで入力します。 28 | example02.Main は友人一覧を取得して終了します。 29 | -------------------------------------------------------------------------------- /c/http.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct ssl_info { 4 | SSL* ssl; 5 | SSL_CTX* ctx; 6 | }; 7 | 8 | struct http_response { 9 | int status_code; 10 | char* body; 11 | }; 12 | 13 | enum ePROTOCOL { 14 | HTTP, 15 | HTTPS 16 | }; 17 | 18 | char* new_json_property_value(char* json, char* property_name); 19 | 20 | int get_http_status_code(const char* response); 21 | 22 | char* new_http_response_body(const char* response); 23 | 24 | int connect_to_server(char* host, int port, char* path); 25 | 26 | struct ssl_info ssl_initialize(int s); 27 | 28 | char* receive_http_response(enum ePROTOCOL protocol, int s, SSL* ssl); 29 | 30 | void close_connection(enum ePROTOCOL protocol, int s, struct ssl_info* ssl); 31 | 32 | void send_http_request(enum ePROTOCOL protocol, char* request, int s, SSL* ssl); 33 | -------------------------------------------------------------------------------- /vba/README.md: -------------------------------------------------------------------------------- 1 | # 実行方法 2 | 3 | ## 準備 4 | 5 | 任意のエクセルのSheet1に本コードを貼り付け、フォームにボタンを3つ追加する。 6 | 7 | Btn_GetAccessToken (Authorization codeでAccess tokenを取得する) 8 | Btn_GetProfile (People APIでプロフィール情報を取得する) 9 | Btn_Refresh (Refresh tokenでAccess tokenを再発行する) 10 | 11 | ## Authorization codeの入手 12 | 13 | 以下のURLにWebブラウザにてアクセスし、リダイレクト先に含まれるcodeパラメータ値を入手する。 14 | 15 | https://mixi.jp/connect_authorize.pl?client_id=Consumer key&scope=r_profile 16 | 17 | ## 以下のセル番号に対応するセルにそれぞれ値を入力する 18 | 19 | Private Const CL_CLIENT_ID = "C5" ' Consumer key 20 | Private Const CL_CLIENT_SECRET = "C6" ' Consumer Secret 21 | Private Const CL_REDIRECT_URI = "C7" ' Redirect URI 22 | Private Const CL_AUTHORIZATION_CODE = "C8" ' Authorization Code 23 | 24 | ## 実行 25 | 26 | フォーム上のボタンを押下して、処理を実行する。 27 | -------------------------------------------------------------------------------- /c/mixi.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct client_credential { 4 | char* client_id; 5 | char* client_secret; 6 | char* redirect_uri; 7 | }; 8 | 9 | void send_issue_token_request(struct client_credential cc, 10 | char* authorization_code, 11 | char* host, 12 | char* path, 13 | SSL* ssl); 14 | 15 | void send_get_my_profile_request(char* access_token, 16 | char* host, 17 | char* path, 18 | int s); 19 | 20 | struct http_response issue_token(struct client_credential cc, 21 | char* authorization_code); 22 | 23 | struct http_response get_my_profile(char* access_token); 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | mixi Graph APIを利用するためのサンプルコード集です。 2 | 3 |

4 | 6 | CC0 7 | 8 |
9 | To the extent possible under law, 10 | 12 | mixi Inc. 13 | has waived all copyright and related or neighboring rights to 14 | mixi Graph API Examples. 15 | This work is published from: 16 | 18 | Japan. 19 |

20 | -------------------------------------------------------------------------------- /chrome/mixi.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |
    8 |
  1. 9 | をクリックして認可し、クエリパラメータのcodeの値をコピーしてください。 10 |
  2. 11 |
  3. 12 | コピーした値をにペーストし、をクリックしてください。 13 |
  4. 14 |
  5. 15 | アクセストークン(未取得)が取得されたらをクリックしてください。 16 |
  6. 17 |
18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /bash/README.md: -------------------------------------------------------------------------------- 1 | # 実行方法 2 | 3 | ## スクリプト中の CONSUMER_KEY(Consumer Key), CONSUMER_SECRET(Consumer Secret), REDIRECT_URI(リダイレクトURI) を環境に応じて書き換えます 4 | 5 | CONSUMER_KEY='****' 6 | CONSUMER_SECRET='****' 7 | REDIRECT_URI='****' 8 | 9 | ## Authorization code の入手 10 | 11 | 以下のURLにWebブラウザにてアクセスし、リダイレクト先に含まれるcodeパラメータ値を入手します。 12 | 13 | https://mixi.jp/connect_authorize.pl?client_id=Consumer key&scope=r_profile 14 | 15 | ## 実行 16 | 17 | access_token の入手 18 | 19 | $ ./mixi.sh auth 20 | 21 | access_token のリフレッシュ 22 | 23 | $ ./mixi.sh refresh 24 | 25 | PeopleAPI にて自分自身の情報を取得 26 | 27 | $ ./mixi.sh people self 28 | 29 | PeopleAPI にて友人の情報を取得 30 | 31 | $ ./mixi.sh people friends 32 | 33 | 結果はそれぞれ JSON にて出力されます。 34 | json_xs コマンドが利用可能な場合、JSON を整形して出力します。 35 | 36 | -------------------------------------------------------------------------------- /c/utils.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "utils.h" 6 | 7 | int get_integer_digit(int len) { 8 | int i; 9 | 10 | for (i = 0; len != 0; i++) { 11 | len /= 10; 12 | } 13 | 14 | return i; 15 | } 16 | 17 | char* new_concat_strings(int len, ...) { 18 | va_list strings; 19 | int i; 20 | char* string; 21 | int all_len; 22 | char* result; 23 | 24 | va_start(strings, len); 25 | all_len = 0; 26 | for (i = 0; i < len; i++) { 27 | string = va_arg(strings, char*); 28 | all_len += strlen(string); 29 | } 30 | va_end(strings); 31 | 32 | result = calloc(all_len + 1, 1); 33 | va_start(strings, len); 34 | for (i = 0; i < len; i++) { 35 | string = va_arg(strings, char*); 36 | strcat(result, string); 37 | } 38 | va_end(strings); 39 | 40 | result[all_len] = '\0'; 41 | return result; 42 | } 43 | -------------------------------------------------------------------------------- /cs/README.md: -------------------------------------------------------------------------------- 1 | # INSTRUCTION 2 | ## Rewrite Credentials 3 | Please rewrite credentials in sample code about CONSUMER_KEY, CONSUMER_SECRET and REDIRECT_URL. 4 | 5 | ## Framework 6 | This sample application can run on .NET Framework of after version 3.5. 7 | 8 | ## Reference Settings for Build 9 | This sample application require reference settings of System.Web.Extentions. 10 | 11 | ## Run 12 | (Windows) 13 | Please launch in command line prompt. 14 | 15 | (Macintosh or Linux) 16 | $ mono main.exe 17 | 18 | # 利用案内 19 | ## クレデンシャル情報の書き換え 20 | サンプルコード内のCONSUMER_KEY,CONSUMER_SECRETおよびREDIRECT_URLを適切な内容に書き換えてください。 21 | 22 | ## フレームワーク 23 | このサンプルアプリケーションは.NET Framework 3.5以降で動作します。 24 | .NET Framework 4.0以降を利用する場合、dynamic型を使うことでJSONの取り扱いを簡略化した実装が可能です。 25 | 26 | ## ビルドのための参照設定 27 | System.Web.Extentionsを参照に追加してください。 28 | 29 | ## 実行方法 30 | (Windowsの場合) 31 | コマンドラインで実行してください。 32 | 33 | (MacintoshまたはLinuxの場合) 34 | mono 2.10での実行を確認しています。 35 | ターミナルで実行してください。 36 | $ mono main.exe 37 | -------------------------------------------------------------------------------- /Clojure/README.markdown: -------------------------------------------------------------------------------- 1 | # clj-mixi-graph-api 2 | 3 | Clojure sample for using mixi Graph API. 4 | 5 | ## Usage 6 | 7 | 0. Leiningen を入れる 8 | 9 | https://github.com/technomancy/leiningen 10 | 11 | 12 | 1. ConsumeKey と ConsumerSecret 及び、必要があれば RedirectUri を書き換える 13 | 14 | (def consumer-info 15 | {:key "xxxxxxxxxxxxxxxxxxxx" 16 | :secret "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" 17 | :redirect-uri "https://mixi.jp/connect_authorize_success.html"}) 18 | 19 | 2. 依存を解決する 20 | 21 | % lein deps 22 | 23 | 2. REPLで実行する 24 | 25 | request-access-token にはユーザーの認可で得た authorization code を渡してください。 26 | 27 | % lein repl 28 | clj-mixi-graph-api.core=> (def first-token (get-token (request-access-token "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"))) 29 | clj-mixi-graph-api.core=> (get-my-friends first-token) 30 | clj-mixi-graph-api.core=> (def refreshed-token (get-token (refresh-access-token (:refresh-token first-token)))) 31 | clj-mixi-graph-api.core=> (get-my-friends refreshed-token) 32 | -------------------------------------------------------------------------------- /erlang/test.erl: -------------------------------------------------------------------------------- 1 | -module(test). 2 | -export([main/1]). 3 | 4 | main(AuthorizationCode) -> 5 | initialize(), 6 | ClientId = "[Client ID]", 7 | ClientSecret = "[Client secret]", 8 | RedirectUri = "[Redirect URI]", 9 | try mixi:get_token(AuthorizationCode, 10 | ClientId, 11 | ClientSecret, 12 | RedirectUri) of 13 | {AccessToken, RefreshToken} -> 14 | io:format("Access token: ~p Refresh token: ~p~n", 15 | [AccessToken, RefreshToken]), 16 | Response = mixi:get_my_friends(AccessToken), 17 | {_, Entries} = lists:keyfind(<<"entry">>, 1, Response), 18 | lists:foreach(fun({struct, Entry}) -> 19 | {_, DisplayName} = lists:keyfind( 20 | <<"displayName">>, 1, Entry), 21 | io:format("~ts~n", [DisplayName]) 22 | end, Entries) 23 | catch 24 | throw:{Status, Error, Description} -> 25 | io:format("~p: ~s : ~s~n", 26 | [Status, Error, Description]) 27 | end, 28 | cleanup(). 29 | 30 | initialize() -> 31 | inets:start(), 32 | ssl:start(). 33 | 34 | cleanup() -> 35 | ssl:stop(), 36 | inets:stop(). 37 | -------------------------------------------------------------------------------- /chrome/mixi.js: -------------------------------------------------------------------------------- 1 | var CLIENT_ID = "YOUR CLIENT ID"; 2 | var CLIENT_SECRET = "YOUR CLIENT SECRET"; 3 | var REDIRECT_URI = encodeURIComponent("YOUR REDIRECT URI"); 4 | 5 | function authorize(code) { 6 | var xhr = new XMLHttpRequest(); 7 | xhr.onreadystatechange = function(){ 8 | if (xhr.readyState == 4 && xhr.status == 200){ 9 | var json = eval('(' + xhr.responseText + ')'); 10 | document.getElementById('access_token').innerHTML = json['access_token']; 11 | } 12 | } 13 | xhr.open('POST', 'https://secure.mixi-platform.com/2/token'); 14 | xhr.setRequestHeader("Content-Type" , "application/x-www-form-urlencoded"); 15 | xhr.send("grant_type=authorization_code&client_id=" + CLIENT_ID + 16 | "&client_secret=" + CLIENT_SECRET + "&code=" + code + "&redirect_uri=" + REDIRECT_URI); 17 | } 18 | 19 | function call(accessToken) { 20 | var xhr = new XMLHttpRequest(); 21 | xhr.onreadystatechange = function(){ 22 | if (xhr.readyState == 4 && xhr.status == 200){ 23 | document.getElementById('json').value = xhr.responseText; 24 | } 25 | } 26 | xhr.open('GET', 'http://api.mixi-platform.com/2/people/@me/@friends'); 27 | xhr.setRequestHeader("Authorization" , "OAuth " + accessToken); 28 | xhr.send(); 29 | } 30 | -------------------------------------------------------------------------------- /c/test.c: -------------------------------------------------------------------------------- 1 | #include "http.h" 2 | #include "mixi.h" 3 | 4 | int main(int argc, char* argv[]) { 5 | char* error; 6 | char* access_token; 7 | char* display_name; 8 | struct http_response token_response; 9 | struct http_response my_profile_response; 10 | 11 | if (argc != 2) { 12 | printf("Error: Authorization code is required.\n"); 13 | exit(1); 14 | } 15 | 16 | struct client_credential cc = { 17 | "YOUR CLIENT ID", 18 | "YOUR CLIENT SECRET", 19 | "YOUR REDIRECT URI" 20 | }; 21 | 22 | token_response = issue_token(cc, argv[1]); 23 | if (token_response.status_code != 200) { 24 | error = new_json_property_value(token_response.body, "error"); 25 | printf("Error at retrieving token: (%d) %s\n", 26 | token_response.status_code, error); 27 | 28 | free(error); 29 | } else { 30 | access_token = 31 | new_json_property_value(token_response.body, "access_token"); 32 | my_profile_response = get_my_profile(access_token); 33 | if (my_profile_response.status_code != 200) { 34 | printf("Error at retrieve peron: (%d)\n", 35 | my_profile_response.status_code); 36 | } else { 37 | display_name = 38 | new_json_property_value(my_profile_response.body, "displayName"); 39 | printf("%s\n", display_name); 40 | free(display_name); 41 | } 42 | 43 | free(access_token); 44 | free(my_profile_response.body); 45 | } 46 | 47 | free(token_response.body); 48 | return 0; 49 | } 50 | -------------------------------------------------------------------------------- /Ruby/sample.rb: -------------------------------------------------------------------------------- 1 | require 'rubygems' 2 | require 'json' 3 | require 'net/https' 4 | require 'net/http' 5 | require 'pp' 6 | 7 | module Mixi 8 | CONSUMER_KEY = 'YOUR CLIENT ID' 9 | CONSUMER_SECRET = 'YOUR CONSUMER SECRET' 10 | REDIRECT_URI = 'YOUR REDIRECT URI' 11 | 12 | class Client 13 | def self.example 14 | raise 'authcode is mandatory.' if ARGV.empty? 15 | client = Mixi::Client.new 16 | client.authorize! ARGV.first 17 | pp client.call('/people/@me/@self') 18 | end 19 | 20 | def authorize!(auth_code) 21 | params = "grant_type=authorization_code&client_id=#{CONSUMER_KEY}&client_secret=#{ 22 | CONSUMER_SECRET}&code=#{auth_code}&redirect_uri=#{REDIRECT_URI}" 23 | https = Net::HTTP.new('secure.mixi-platform.com', 443) 24 | https.use_ssl = true 25 | https.start do 26 | response = https.post('/2/token', params).body 27 | json = JSON.parse(response) 28 | @access_token = json['access_token'] 29 | @refresh_token = json['refresh_token'] 30 | end 31 | end 32 | 33 | def call(endpoint) 34 | http = Net::HTTP.new('api.mixi-platform.com', 80) 35 | http.start do 36 | response = http.get("/2#{endpoint}", 37 | 'Authorization' => "OAuth #{@access_token}", 38 | 'HOST' => 'api.mixi-platform.com').body 39 | JSON.parse(response) 40 | end 41 | end 42 | end 43 | end 44 | 45 | Mixi::Client.example 46 | -------------------------------------------------------------------------------- /R/lib/mixiGraphAPI.R: -------------------------------------------------------------------------------- 1 | get_token<-function(client_id,client_secret,code,redirect_uri){ 2 | token_raw<-postForm("https://secure.mixi-platform.com/2/token", 3 | grant_type=grant_type, 4 | client_id=client_id, 5 | client_secret=client_secret, 6 | code=code, 7 | redirect_uri=redirect_uri 8 | ) 9 | parser<-newJSONParser() 10 | parser$addData(token_raw) 11 | token <- parser$getObject() 12 | return(token) 13 | } 14 | 15 | 16 | get_people<-function(type,access_token){ 17 | url<-paste("https://api.mixi-platform.com/2/people/@me/",type,sep="") 18 | res_people_raw<-getForm(url,oauth_token=access_token) 19 | parser<-newJSONParser() 20 | parser$addData(res_people_raw) 21 | res_people <- parser$getObject() 22 | return(res_people) 23 | } 24 | 25 | 26 | refresh_token<-function(refresh_token,client_id,client_secret){ 27 | res_raw_token <- postForm("https://secure.mixi-platform.com/2/token", 28 | grant_type="refresh_token", 29 | client_id=client_id, 30 | client_secret=client_secret, 31 | refresh_token=refresh_token 32 | ) 33 | parser<-newJSONParser() 34 | parser$addData(res_raw_token) 35 | res_token=parser$getObject() 36 | return(res_token) 37 | } 38 | 39 | -------------------------------------------------------------------------------- /haskell/show_friend.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE OverloadedStrings #-} 2 | import Text.JSON 3 | import System.Environment 4 | import Network.HTTP.Enumerator 5 | import Data.List (sort) 6 | import Data.ByteString.Char8 hiding (sort, putStrLn) 7 | import qualified Data.ByteString.Lazy.Char8 as L 8 | 9 | data Token = Token { 10 | accessToken :: String, 11 | refreshToken :: String 12 | } deriving Show 13 | 14 | clientId = "B" :: ByteString 15 | clientSecret = "xyzzy" :: ByteString 16 | redirectUri = "https://mixi.jp/connect_authorize_success.html" :: ByteString 17 | 18 | tokenRequest :: Monad m => String -> Request m 19 | tokenRequest code = 20 | urlEncodedBody [("grant_type", "authorization_code"), 21 | ("client_id", clientId), 22 | ("client_secret", clientSecret), 23 | ("code", pack code), 24 | ("redirect_uri", redirectUri)] 25 | $ def { host = "secure.mixi-platform.com", 26 | port = 443, 27 | path = "/2/token", 28 | secure = True } 29 | 30 | peopleRequest :: Monad m => String -> Request m 31 | peopleRequest token = def { 32 | host = "api.mixi-platform.com", 33 | path = "/2/people/@me/@friends", 34 | requestHeaders = [ 35 | ("Authorization", append "OAuth " (pack token)) 36 | ] 37 | } 38 | 39 | parseTokenResponse :: String -> Result Token 40 | parseTokenResponse res = do 41 | json <- decode res 42 | case sort $ fromJSObject json of 43 | [("access_token", JSString acc), 44 | ("expires_in", _), 45 | ("refresh_token", JSString ref), 46 | ("scope", _)] -> 47 | return $ Token { 48 | accessToken = fromJSString acc, 49 | refreshToken = fromJSString ref 50 | } 51 | _ -> fail ("couldn't handle response:" ++ res) 52 | 53 | getAccessToken :: String -> IO (Result Token) 54 | getAccessToken code = do 55 | res <- withManager (httpLbs $ tokenRequest code) 56 | return $ parseTokenResponse (L.unpack $ responseBody res) 57 | 58 | showFriends :: Token -> IO () 59 | showFriends (Token token _) = 60 | withManager (httpLbs $ peopleRequest token) >>= L.putStrLn . responseBody 61 | 62 | main :: IO () 63 | main = do code:_ <- getArgs 64 | token <- getAccessToken code 65 | case token of 66 | Ok token -> showFriends token 67 | Error err -> putStrLn err 68 | -------------------------------------------------------------------------------- /Clojure/test/clj_mixi_graph_api/test/core.clj: -------------------------------------------------------------------------------- 1 | (ns clj-mixi-graph-api.test.core 2 | (:use [clj-mixi-graph-api.core :as m]) 3 | (:use [clojure.test])) 4 | 5 | (deftest test-mk-token 6 | (let [token {"refresh_token" "hoge" 7 | "access_token" "fuga" 8 | "expires_in" "piyo"}] 9 | (is (= {:refresh-token "hoge" 10 | :access-token "fuga" 11 | :expires-in "piyo"} 12 | (m/mk-token token))))) 13 | 14 | (deftest test-mk-person 15 | (let [person {"id" "foo" "thumbnailUrl" "bar" 16 | "displayName" "baz" "profileUrl" "qux"}] 17 | (is (= {:id "foo" :thumbnail-url "bar" 18 | :display-name "baz" :profile-url "qux"} 19 | (m/mk-person person))))) 20 | 21 | (deftest test-get-token 22 | (let [resp {:content "{\"refresh_token\":\"hoge\",\"access_token\":\"fuga\",\"expires_in\":\"piyo\"}"}] 23 | (is (= {:refresh-token "hoge" 24 | :access-token "fuga" 25 | :expires-in "piyo"} 26 | (m/get-token resp))))) 27 | 28 | (deftest test-build-header 29 | (let [headers {"foo" "bar"}] 30 | (is (= "bar" (:foo (build-headers headers)))))) 31 | 32 | (deftest test-get-oauth-error 33 | (let [has-error-header {:WWW-Authenticate "OAuth error='error!'"} 34 | has-expired-error-header {:WWW-Authenticate "OAuth error='expired_token'"}] 35 | (is (= "error!" (m/get-oauth-error has-error-header))) 36 | (is (= "expired_token" (m/get-oauth-error has-expired-error-header))))) 37 | 38 | (deftest test-has-oauth-error? 39 | (let [no-error-header {:foo "bar"} 40 | has-error-header {:WWW-Authenticate "OAuth error='error!'"} 41 | has-expired-error-header {:WWW-Authenticate "OAuth error='expired_token'"}] 42 | (is (not (m/has-oauth-error? no-error-header))) 43 | (is (m/has-oauth-error? has-error-header)) 44 | (is (m/has-oauth-error? has-expired-error-header)))) 45 | 46 | (deftest test-expired? 47 | (let [no-error-resp {:headers {"foo" "bar"}} 48 | has-error-resp {:headers {"WWW-Authenticate" "OAuth error='error!'"}} 49 | has-expired-error-resp {:headers {"WWW-Authenticate" "OAuth error='expired_token'"}}] 50 | (is (not (m/expired? no-error-resp))) 51 | (is (not (m/expired? has-error-resp))) 52 | (is (m/expired? has-expired-error-resp)))) 53 | -------------------------------------------------------------------------------- /objc/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // mixi-objc 4 | // 5 | 6 | #import 7 | 8 | #define kMixiApiUri @"http://api.mixi-platform.com/2/people/@me/@self" 9 | #define kMixiUpgradeUri @"https://secure.mixi-platform.com/2/token" 10 | #define kMixiUpgradeParamsFormat @"grant_type=authorization_code&client_id=%@&client_secret=%@&code=%@&redirect_uri=%@" 11 | #define kMixiClientId @"YOUR CLIENT ID" 12 | #define kMixiClientSecret @"YOUR CLIENT SECRET" 13 | #define kMixiRedirectUri @"YOUR REDIRECT URI" 14 | 15 | // JSONのパース?はいい加減なので参考にしないでください。 16 | NSString* getAccessToken(NSString* json) { 17 | NSRange match = [json rangeOfString:@"\"access_token\":\""]; 18 | if (match.location != NSNotFound) { 19 | match.location += match.length; 20 | match.length = 40; 21 | return [json substringWithRange:match]; 22 | } else { 23 | return nil; 24 | } 25 | } 26 | 27 | int main (int argc, const char * argv[]) 28 | { 29 | 30 | NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; 31 | 32 | if (argc < 2) { 33 | NSLog(@"authcode is mandatory."); 34 | return 1; 35 | } 36 | NSString *code = [[[NSString alloc] initWithCString:argv[1] encoding:NSUTF8StringEncoding] autorelease]; 37 | 38 | NSURL *url = [[[NSURL alloc] initWithString:kMixiUpgradeUri] autorelease]; 39 | NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; 40 | request.HTTPMethod = @"POST"; 41 | request.HTTPBody = [[NSString stringWithFormat:kMixiUpgradeParamsFormat, kMixiClientId, kMixiClientSecret, code, kMixiRedirectUri] dataUsingEncoding:NSUTF8StringEncoding]; 42 | NSData *result = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil]; 43 | NSString *json = [[[NSString alloc] initWithData:result encoding:NSUTF8StringEncoding] autorelease]; 44 | NSString *accessToken = getAccessToken(json); 45 | 46 | url = [[[NSURL alloc] initWithString:kMixiApiUri] autorelease]; 47 | request = [NSMutableURLRequest requestWithURL:url]; 48 | [request setValue:[NSString stringWithFormat:@"OAuth %@", accessToken] forHTTPHeaderField:@"Authorization"]; 49 | result = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil]; 50 | json = [[[NSString alloc] initWithData:result encoding:NSUTF8StringEncoding] autorelease]; 51 | NSLog(@"%@", json); 52 | 53 | [pool drain]; 54 | return 0; 55 | } 56 | 57 | -------------------------------------------------------------------------------- /erlang/mixi.erl: -------------------------------------------------------------------------------- 1 | -module(mixi). 2 | -export([get_token/4, 3 | get_my_friends/1]). 4 | 5 | get_token(AuthorizationCode, 6 | ClientId, 7 | ClientSecret, 8 | RedirectUri) -> 9 | Response = httpc:request( 10 | post, 11 | { 12 | "https://secure.mixi-platform.com/2/token", 13 | [], 14 | "application/x-www-form-urlencoded", 15 | lists:append([ 16 | "grant_type=authorization_code", 17 | "&client_id=", ClientId, 18 | "&client_secret=", ClientSecret, 19 | "&redirect_uri=", edoc_lib:escape_uri(RedirectUri), 20 | "&code=", AuthorizationCode 21 | ]) 22 | }, 23 | [], 24 | []), 25 | parse_response(Response, 26 | fun(Json) -> 27 | { get_property_value("access_token", Json), 28 | get_property_value("refresh_token", Json) } 29 | end 30 | ). 31 | 32 | get_my_friends(AccessToken) -> 33 | Response = httpc:request( 34 | get, 35 | { 36 | "http://api.mixi-platform.com/2/people/@me/@friends", 37 | [ 38 | {"Authorization", lists:append("OAuth ", AccessToken)} 39 | ] 40 | }, 41 | [], 42 | []), 43 | parse_response(Response, 44 | fun(Json) -> 45 | Json 46 | end 47 | ). 48 | 49 | parse_response({ok, {{_, 200, _}, _, Body}}, F) -> 50 | {struct, Json} = mochijson2:decode(Body), 51 | F(Json); 52 | parse_response({ok, {{_, Status, _}, Headers, Body}}, _) -> 53 | case lists:keyfind("www-authenticate", 1, Headers) of 54 | {_, Reason} -> 55 | throw( 56 | { Status, 57 | Reason } 58 | ); 59 | _ -> 60 | {struct, Error} = mochijson2:decode(Body), 61 | throw( 62 | { Status, 63 | get_property_value("error", Error), 64 | get_property_value("error_description", Error) } 65 | ) 66 | end. 67 | 68 | get_property_value(KeyName, Json) -> 69 | case lists:keyfind(list_to_binary(KeyName), 1, Json) of 70 | {_, Value} -> 71 | binary_to_list(Value); 72 | _ -> 73 | [] 74 | end. 75 | -------------------------------------------------------------------------------- /Python/mixi.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | from google.appengine.ext import webapp 5 | from google.appengine.ext.webapp import util 6 | import os 7 | from google.appengine.ext.webapp import template 8 | from google.appengine.ext.webapp.util import run_wsgi_app 9 | from google.appengine.api import urlfetch 10 | import urllib 11 | from django.utils import simplejson 12 | 13 | AUTHORIZATION_URL_BASE = "https://mixi.jp/connect_authorize.pl?" 14 | REDIRECTION_URI = "http://localhost:8080/redirect" 15 | TOKEN_ENDPOINT = "https://secure.mixi-platform.com/2/token" 16 | FRIENDS_TIMELINE_ENDPOINT = "http://api.mixi-platform.com/2/people/@me/@friends" 17 | 18 | CONSUMER_KEY = "*******************" 19 | CONSUMER_SECRET = "**************************************" 20 | 21 | class MainHandler(webapp.RequestHandler): 22 | 23 | def get_access_token(self,auth_code): 24 | 25 | token_params = { 26 | "grant_type":"authorization_code", 27 | "client_id":CONSUMER_KEY, 28 | "client_secret":CONSUMER_SECRET, 29 | "code":auth_code, 30 | "redirect_uri":REDIRECTION_URI, 31 | } 32 | form_data = urllib.urlencode(token_params) 33 | result = urlfetch.fetch(url=TOKEN_ENDPOINT, 34 | payload=form_data, 35 | method=urlfetch.POST, 36 | headers={'Content-Type':'application/x-www-form-urlencoded'}) 37 | 38 | json = simplejson.loads(result.content) 39 | return json['access_token'] 40 | 41 | def get_friends_timeline(self,access_token): 42 | result = urlfetch.fetch(url=FRIENDS_TIMELINE_ENDPOINT, 43 | method=urlfetch.GET, 44 | headers={'Authorization':'OAuth %s'%access_token}) 45 | return simplejson.loads(result.content) 46 | 47 | def get(self, mode=""): 48 | 49 | if mode == "login": 50 | 51 | query = { 52 | "client_id":CONSUMER_KEY, 53 | "response_type":"code", 54 | "scope":"r_profile", 55 | } 56 | url = AUTHORIZATION_URL_BASE + urllib.urlencode(query) 57 | self.redirect(url) 58 | 59 | if mode == "redirect": 60 | 61 | auth_code = self.request.get("code") 62 | access_token = self.get_access_token(auth_code) 63 | 64 | results = self.get_friends_timeline(access_token) 65 | 66 | template_values = {'results': results['entry'],} 67 | path = os.path.join(os.path.dirname(__file__), 'mixi.html') 68 | self.response.out.write(template.render(path, template_values)) 69 | 70 | def main(): 71 | application = webapp.WSGIApplication([('/(.*)', MainHandler)], 72 | debug=True) 73 | util.run_wsgi_app(application) 74 | 75 | if __name__ == '__main__': 76 | main() -------------------------------------------------------------------------------- /Clojure/src/clj_mixi_graph_api/core.clj: -------------------------------------------------------------------------------- 1 | (ns clj-mixi-graph-api.core 2 | (:require [com.twinql.clojure.http :as http]) 3 | (:require [clj-json.core :as json])) 4 | 5 | (def consumer-info 6 | {:key "xxxxxxxxxxxxxxxxxxxx" 7 | :secret "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" 8 | :redirect-uri "https://mixi.jp/connect_authorize_success.html"}) 9 | 10 | (def endpoint 11 | {:token "https://secure.mixi-platform.com/2/token" 12 | :api "http://api.mixi-platform.com/2"}) 13 | 14 | (defstruct token-info :refresh-token :access-token :expires-in) 15 | (defn mk-token 16 | "make token-info structure from json-parsed response of request or refresh token" 17 | [parsed-resp] 18 | (let [{:strs [refresh_token access_token expires_in]} parsed-resp] 19 | (struct token-info refresh_token access_token expires_in))) 20 | 21 | (defstruct person :id :thumbnail-url :display-name :profile-url) 22 | (defn mk-person 23 | "make person structure from people element" 24 | [data] 25 | (let [{:strs [id thumbnailUrl displayName profileUrl]} data] 26 | (struct person id thumbnailUrl displayName profileUrl))) 27 | 28 | (defn post-to-token-with 29 | "post request to token end point with query" 30 | [query] 31 | (http/post (endpoint :token) 32 | :query (assoc query :client_id (consumer-info :key) 33 | :client_secret (consumer-info :secret)) 34 | :as :string)) 35 | 36 | (defn request-access-token [code] 37 | (post-to-token-with 38 | {:grant_type "authorization_code" 39 | :code code 40 | :redirect_uri (consumer-info :redirect-uri)})) 41 | 42 | (defn refresh-access-token [token-info] 43 | (post-to-token-with 44 | {:grant_type "refresh_token" 45 | :refresh_token token-info})) 46 | 47 | (defn get-token 48 | "get token-info structure from response" 49 | [{content :content}] 50 | (mk-token (json/parse-string content))) 51 | 52 | (defn read-people 53 | [{token-info :token 54 | user-id :user-id 55 | group-id :group-id 56 | res-format :format}] 57 | (http/get (str (endpoint :api) "/people/" user-id "/" group-id) 58 | :query {:format res-format 59 | :oauth_token (token-info :access-token)} 60 | :as :string)) 61 | 62 | (defn build-headers [headers] 63 | (reduce 64 | (fn [res header] (assoc res (keyword (first header)) (second header))) 65 | {} 66 | headers)) 67 | 68 | (defn get-oauth-error [{oauth-error :WWW-Authenticate}] 69 | (nth (re-find #"OAuth error='(.+)'" oauth-error) 1)) 70 | 71 | (defn has-oauth-error? [{oauth-error :WWW-Authenticate}] 72 | (not (nil? oauth-error))) 73 | 74 | (defn expired? [resp] 75 | (let [built-headers (build-headers (:headers resp))] 76 | (and 77 | (has-oauth-error? built-headers) 78 | (= "expired_token" (get-oauth-error built-headers))))) 79 | 80 | (defn get-my-friends 81 | "sample of accessing a protected resource" 82 | [token-info] 83 | (let [resp (read-people {:token token-info 84 | :user-id "@me" 85 | :group-id "@friends" 86 | :format "json"})] 87 | (if (expired? resp) 88 | (recur (get-token (refresh-access-token (:refresh-token token-info)))) 89 | (map mk-person (get (json/parse-string (:content resp)) "entry"))))) 90 | -------------------------------------------------------------------------------- /Perl/sample.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use warnings; 5 | 6 | use constant { 7 | CONSUMER_KEY => '[YOUR CONSUMER KEY]', 8 | CONSUMER_SECRET => '[YOUR CONSUMER SECRET]', 9 | REDIRECT_URI => '[YOUR REDIRECT URI]', 10 | 11 | MIXI_TOKEN_ENDPOINT => 'https://secure.mixi-platform.com/2/token', 12 | MIXI_API_ENDPOINT => 'http://api.mixi-platform.com/2' 13 | }; 14 | 15 | use URI::Escape qw/ uri_escape /; 16 | use HTTP::Request; 17 | use LWP::UserAgent; 18 | use JSON::XS; 19 | use Data::Dumper; 20 | 21 | sub request { 22 | my ($method, $url, $data_arr) = @_; 23 | 24 | my $req = HTTP::Request->new( 25 | $method => $url 26 | ); 27 | 28 | if ($method eq 'POST') { 29 | my $data_str = join '&', map { uri_escape($_) . '=' . uri_escape($data_arr->{$_}) } keys %$data_arr; 30 | $req->content_type('application/x-www-form-urlencoded'); 31 | $req->content($data_str); 32 | } 33 | 34 | my $ua = LWP::UserAgent->new(); 35 | my $res = $ua->request($req); 36 | 37 | return $res; 38 | } 39 | 40 | sub get_token { 41 | my $auth_code = shift; 42 | 43 | my %data_arr = ( 44 | 'grant_type' => 'authorization_code', 45 | 'client_id' => CONSUMER_KEY, 46 | 'client_secret' => CONSUMER_SECRET, 47 | 'code' => $auth_code, 48 | 'redirect_uri' => REDIRECT_URI, 49 | ); 50 | 51 | my $res = request('POST', MIXI_TOKEN_ENDPOINT, \%data_arr); 52 | die 'Request failed. ' . $res->status_line unless $res->is_success; 53 | 54 | return decode_json($res->content); 55 | } 56 | 57 | sub get_new_token { 58 | my $refresh_token = shift; 59 | 60 | my %data_arr = ( 61 | 'grant_type' => 'refresh_token', 62 | 'client_id' => CONSUMER_KEY, 63 | 'client_secret' => CONSUMER_SECRET, 64 | 'refresh_token' => $refresh_token, 65 | ); 66 | 67 | my $res = request('POST', MIXI_TOKEN_ENDPOINT, \%data_arr); 68 | die 'Request failed. ' . $res->status_line unless $res->is_success; 69 | 70 | return decode_json($res->content); 71 | } 72 | 73 | sub call { 74 | my ($endpoint, $token) = @_; 75 | 76 | my $url = MIXI_API_ENDPOINT . $endpoint . '?oauth_token=' . uri_escape($token->{'access_token'}); 77 | my $res = request('GET', $url); 78 | 79 | if (defined $res->header('WWW-Authenticate')) { 80 | my $error_msg = $res->header('WWW-Authenticate'); 81 | 82 | if ($error_msg =~ /invalid_request/) { 83 | die 'Invalid request.'; 84 | } elsif ($error_msg =~ /invalid_token/) { 85 | die 'Invalid token.'; 86 | } elsif ($error_msg =~ /expired_token/) { 87 | $token = get_new_token($token->{'refresh_token'}); 88 | $url = MIXI_API_ENDPOINT . $endpoint . '?oauth_token=' . uri_escape($token->{'access_token'}); 89 | return decode_json(request('GET', $url)->{'_content'}); 90 | } elsif ($error_msg =~ /insufficient_scope/) { 91 | die 'Insufficient scope.'; 92 | } 93 | } 94 | 95 | return decode_json($res->content); 96 | } 97 | 98 | my $auth_code = $ARGV[0]; 99 | my $token = get_token($auth_code); 100 | my $json_href = call('/people/@me/@self', $token); 101 | 102 | print Data::Dumper::Dumper($json_href); 103 | 104 | 1; 105 | 106 | -------------------------------------------------------------------------------- /bash/mixi.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | CONSUMER_KEY='****' 4 | CONSUMER_SECRET='****' 5 | REDIRECT_URI='****' 6 | 7 | echo_json() { 8 | local json=$1 9 | 10 | local cmd_json_xs=`which json_xs 2>/dev/null` 11 | if [ $cmd_json_xs ]; then 12 | echo "$json" | $cmd_json_xs 2>/dev/null 13 | local retval=$? 14 | if [ $retval -eq 0 ]; then 15 | return 16 | fi 17 | fi 18 | 19 | echo "$json" 20 | } 21 | 22 | auth() { 23 | local code=$1 24 | local result=`curl -d grant_type=authorization_code \ 25 | -d client_id=$CONSUMER_KEY \ 26 | -d client_secret=$CONSUMER_SECRET \ 27 | -d code=$code \ 28 | -d redirect_uri=$REDIRECT_URI \ 29 | https://secure.mixi-platform.com/2/token \ 30 | 2>/dev/null` 31 | local retval=$? 32 | if [ $retval -ne 0 ]; then 33 | echo "curl error" >&2 34 | return 1 35 | fi 36 | 37 | echo_json "$result" 38 | return 0 39 | } 40 | 41 | refresh() { 42 | local token=$1 43 | local result=`curl -d grant_type=refresh_token \ 44 | -d client_id=$CONSUMER_KEY \ 45 | -d client_secret=$CONSUMER_SECRET \ 46 | -d refresh_token=$token \ 47 | https://secure.mixi-platform.com/2/token \ 48 | 2>/dev/null` 49 | local retval=$? 50 | if [ $retval -ne 0 ]; then 51 | echo "curl error" >&2 52 | return 1 53 | fi 54 | 55 | echo_json "$result" 56 | return 0 57 | } 58 | 59 | people() { 60 | local type=$1 61 | local token=$2 62 | local result=`curl -w "\n%{http_code}" \ 63 | https://secure.mixi-platform.com/2/people/@me/@$type?oauth_token=$token \ 64 | 2>/dev/null` 65 | local retval=$? 66 | if [ $retval -ne 0 ]; then 67 | echo "curl error" >&2 68 | return 1 69 | fi 70 | 71 | local http_code=`echo "$result" | tail -n 1` 72 | if [ $http_code -ne 200 ]; then 73 | echo "ERROR (HTTP CODE = $http_code)" >&2 74 | return 1 75 | fi 76 | 77 | local line_count=`echo "$result" | wc -l` 78 | local content_line_count=`expr $line_count - 1` 79 | local content=`echo "$result" | head -n $content_line_count` 80 | 81 | echo_json "$content" 82 | 83 | return 0 84 | } 85 | 86 | usage() { 87 | echo "Usage: $0 {auth|refresh|people} OPTIONS" >&2 88 | } 89 | 90 | usage_auth() { 91 | echo "Usage: $0 auth CODE" >&2 92 | } 93 | 94 | usage_refresh() { 95 | echo "Usage: $0 refresh REFRESH_TOKEN" >&2 96 | } 97 | 98 | usage_people() { 99 | echo "Usage: $0 people {self|friends} ACCESS_TOKEN" >&2 100 | } 101 | 102 | retval=1 103 | 104 | case "$1" in 105 | auth | refresh) 106 | if [ $# -ne 2 ]; then 107 | usage_$1 108 | retval=1 109 | else 110 | $1 $2 111 | retval=$? 112 | fi 113 | ;; 114 | people) 115 | if [ $# -ne 3 ]; then 116 | usage_people 117 | retval=1 118 | else 119 | case "$2" in 120 | self | friends) 121 | people $2 $3 122 | retval=$? 123 | ;; 124 | *) 125 | usage_people 126 | retval=1 127 | ;; 128 | esac 129 | fi 130 | ;; 131 | *) 132 | usage 133 | retval=1 134 | ;; 135 | esac 136 | 137 | exit $retval 138 | 139 | -------------------------------------------------------------------------------- /c/mixi.c: -------------------------------------------------------------------------------- 1 | #include "utils.h" 2 | #include "http.h" 3 | #include "mixi.h" 4 | 5 | void send_issue_token_request(struct client_credential cc, 6 | char* authorization_code, 7 | char* host, 8 | char* path, 9 | SSL* ssl) { 10 | int ret; 11 | int len; 12 | int digit; 13 | char* post_body; 14 | char* request; 15 | char* post_body_len; 16 | 17 | post_body = 18 | new_concat_strings(8, 19 | "grant_type=authorization_code&client_id=", 20 | cc.client_id, 21 | "&client_secret=", 22 | cc.client_secret, 23 | "&redirect_uri=", 24 | cc.redirect_uri, 25 | "&code=", 26 | authorization_code); 27 | len = (int)(strlen(post_body)); 28 | digit = get_integer_digit(len); 29 | post_body_len = malloc(digit + 1); 30 | sprintf(post_body_len, "%d", len); 31 | request = 32 | new_concat_strings(11, 33 | "POST ", 34 | path, 35 | " HTTP/1.1\r\n", 36 | "Host: ", 37 | host, 38 | "\r\n", 39 | "Content-Type: application/x-www-form-urlencoded\r\n", 40 | "Content-Length: ", 41 | post_body_len, 42 | "\r\n\r\n", 43 | post_body); 44 | send_http_request(HTTPS, request, 0, ssl); 45 | 46 | free(post_body); 47 | free(post_body_len); 48 | free(request); 49 | } 50 | 51 | void send_get_my_profile_request(char* access_token, 52 | char* host, 53 | char* path, 54 | int s) { 55 | char* request; 56 | int ret; 57 | 58 | request = 59 | new_concat_strings(10, 60 | "GET ", 61 | path, 62 | " HTTP/1.1\r\n", 63 | "Host: ", 64 | host, 65 | "\r\n", 66 | "Accept: application/json\r\n", 67 | "Authorization: OAuth ", 68 | access_token, 69 | "\r\n\r\n"); 70 | send_http_request(HTTP, request, s, NULL); 71 | 72 | free(request); 73 | } 74 | 75 | struct http_response issue_token(struct client_credential cc, 76 | char* authorization_code) { 77 | char* host; 78 | char* path; 79 | char* response; 80 | int ret; 81 | int s; 82 | struct ssl_info ssl; 83 | struct http_response result; 84 | 85 | host = "secure.mixi-platform.com"; 86 | path = "/2/token"; 87 | 88 | s = connect_to_server(host, 443, path); 89 | ssl = ssl_initialize(s); 90 | 91 | send_issue_token_request(cc, authorization_code, host, path, ssl.ssl); 92 | response = receive_http_response(HTTPS, 0, ssl.ssl); 93 | 94 | close_connection(HTTPS, s, &ssl); 95 | 96 | result.status_code = get_http_status_code(response); 97 | result.body = new_http_response_body(response); 98 | 99 | free(response); 100 | return result; 101 | } 102 | 103 | struct http_response get_my_profile(char* access_token) { 104 | int s; 105 | char* host; 106 | char* path; 107 | char* response; 108 | struct http_response result; 109 | 110 | host = "api.mixi-platform.com"; 111 | path = "/2/people/@me/@self"; 112 | 113 | s = connect_to_server(host, 80, path); 114 | send_get_my_profile_request(access_token, host, path, s); 115 | response = receive_http_response(HTTP, s, NULL); 116 | 117 | close_connection(HTTP, s, NULL); 118 | 119 | result.status_code = get_http_status_code(response); 120 | 121 | result.body = new_http_response_body(response); 122 | 123 | free(response); 124 | return result; 125 | } 126 | -------------------------------------------------------------------------------- /cs/Main.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text; 3 | using System.Net; 4 | using System.Web.Script.Serialization; 5 | using System.Collections.Generic; 6 | using System.Collections.Specialized; 7 | 8 | namespace MixiGraphAPIExample 9 | { 10 | class MainClass 11 | { 12 | private const string CONSUMER_KEY = "[YOUR CONSUMER KEY]"; 13 | private const string CONSUMER_SECRET = "[YOUR CONSUMER SECRET]"; 14 | private const string REDIRECT_URL = "[YOUR REDIRECT URL]"; 15 | 16 | public static void Main (string[] args) 17 | { 18 | MixiAPIClient client = new MixiAPIClient(CONSUMER_KEY,CONSUMER_SECRET,REDIRECT_URL); 19 | 20 | Console.WriteLine("1. Open this url and allow your application access."); 21 | Console.WriteLine(client.GetAuthorizeUrl()); 22 | 23 | Console.WriteLine("2. Input 'code' parameter value of redirected url."); 24 | string code = Console.ReadLine(); 25 | client.GetToken(code); 26 | 27 | Console.WriteLine("----"); 28 | string resText = client.Call("/people/@me/@self"); 29 | Dictionary result = MixiAPIClient.JsonToDictionary(resText); 30 | Dictionary entry = (Dictionary)result["entry"]; 31 | foreach(string key in entry.Keys){ 32 | Console.WriteLine(key + " : " + entry[key]); 33 | } 34 | } 35 | } 36 | 37 | class MixiAPIClient 38 | { 39 | private const string MIXI_TOKEN_ENDPOINT = "https://secure.mixi-platform.com/2/token"; 40 | private const string MIXI_API_ENDPOINT = "http://api.mixi-platform.com/2"; 41 | private const string MIXI_AUTHORIZE_URL = "https://mixi.jp/connect_authorize.pl"; 42 | 43 | private string consumer_key; 44 | private string consumer_secret; 45 | private string redirect_url; 46 | 47 | public string token = ""; 48 | public string refreshToken = ""; 49 | 50 | public static Dictionary JsonToDictionary(string jsonText) 51 | { 52 | JavaScriptSerializer serializer = new JavaScriptSerializer(); 53 | return serializer.Deserialize>(jsonText); 54 | } 55 | 56 | public MixiAPIClient(string consumer_key, string consumer_secret, string redirect_url) 57 | { 58 | this.consumer_key = consumer_key; 59 | this.consumer_secret = consumer_secret; 60 | this.redirect_url = redirect_url; 61 | } 62 | 63 | public string GetAuthorizeUrl() 64 | { 65 | return MIXI_AUTHORIZE_URL + "?scope=r_profile&client_id=" + consumer_key; 66 | } 67 | 68 | public void GetToken(string authorizationCode) 69 | { 70 | NameValueCollection data = new NameValueCollection(); 71 | data.Add ("grant_type","authorization_code"); 72 | data.Add ("client_id",consumer_key); 73 | data.Add ("client_secret",consumer_secret); 74 | data.Add ("redirect_uri",redirect_url); 75 | data.Add ("code",authorizationCode); 76 | WebClient wc = new WebClient(); 77 | Byte[] resData = wc.UploadValues(MIXI_TOKEN_ENDPOINT, data); 78 | string resText = Encoding.UTF8.GetString(resData); 79 | Dictionary result = MixiAPIClient.JsonToDictionary(resText); 80 | token = result["access_token"].ToString(); 81 | refreshToken = result["refresh_token"].ToString(); 82 | } 83 | 84 | public string Call(string endpoint) 85 | { 86 | string url = MIXI_API_ENDPOINT + endpoint + "?oauth_token=" + token; 87 | WebClient wc = new WebClient(); 88 | byte[] resData = wc.DownloadData(url); 89 | return Encoding.UTF8.GetString(resData); 90 | } 91 | } 92 | } 93 | 94 | -------------------------------------------------------------------------------- /scala/src/main/scala/example02/Main.scala: -------------------------------------------------------------------------------- 1 | package example02 2 | 3 | import scala.annotation.tailrec 4 | import dispatch.json.{Js, JsObject, JsString, JsValue} 5 | import org.apache.commons.httpclient.{HttpClient, HttpMethodBase, HttpStatus} 6 | import org.apache.commons.httpclient.methods.{GetMethod, PostMethod} 7 | 8 | trait Response 9 | case class Ok(body: java.io.InputStream) extends Response 10 | case class Unauthorized(headers: Map[String, String]) extends Response 11 | 12 | object Conversions { 13 | implicit def jsObject2Map(js: JsObject): Map[JsString, JsValue] = js.self 14 | implicit def jsString2String(js: JsString): String = js.self 15 | implicit def string2JsString(value: String): JsString = JsString(value) 16 | 17 | implicit def any2Caster[T](value: T): Caster[T] = new Caster[T](value) 18 | class Caster[T](value: T) { 19 | def as[U<:T:Manifest]: Option[U] = 20 | if (manifest[U].erasure.isInstance(value)) Some[U](value.asInstanceOf[U]) 21 | else None 22 | } 23 | } 24 | 25 | object Main extends App { 26 | import Conversions._ 27 | 28 | val CONSUMER_KEY = "" 29 | val CONSUMER_SECRET = "" 30 | val REDIRECT_URI = "http://mixi.jp/connect_authorize_success.html" 31 | val REQUEST_TOKEN_BASE_PARAMS = Map("client_id" -> CONSUMER_KEY, 32 | "client_secret" -> CONSUMER_SECRET) 33 | 34 | for { 35 | authorizationCode <- args.headOption 36 | tokens <- getTokens(authorizationCode) 37 | friends <- get(tokens, "/people/@me/@friends") 38 | } println(friends) 39 | 40 | def getTokens(authorizationCode: String): Option[(String, String)] = 41 | retrieveTokens(REQUEST_TOKEN_BASE_PARAMS + 42 | ("grant_type" -> "authorization_code") + 43 | ("code" -> authorizationCode) + 44 | ("redirect_uri" -> REDIRECT_URI)) 45 | 46 | def refreshTokens(refreshToken: String): Option[(String, String)] = 47 | retrieveTokens(REQUEST_TOKEN_BASE_PARAMS + 48 | ("grant_type" -> "refresh_token") + 49 | ("refresh_token" -> refreshToken)) 50 | 51 | def retrieveTokens(params: Map[String, String]): Option[(String, String)] = 52 | using(new PostMethod("https://secure.mixi-platform.com/2/token")) { method => 53 | for ((name, value) <- params) method.addParameter(name, value) 54 | for { 55 | response <- executeHttpMethod(method) 56 | Ok(body) <- response.as[Ok] 57 | x <- Js(body).as[JsObject] 58 | refreshToken <- x.get("refresh_token").flatMap(_.as[JsString]) 59 | accessToken <- x.get("access_token").flatMap(_.as[JsString]) 60 | } yield (refreshToken, accessToken) 61 | } 62 | 63 | val OAuthError = """\s*OAuth\s+error='([^']+)'""".r 64 | @tailrec 65 | def get(tokens: (String, String), path: String): Option[JsValue] = { 66 | def _get(accessToken: String, url: String): Either[Symbol, JsValue] = 67 | using(new GetMethod(url)) { method => 68 | method.setDoAuthentication(false) 69 | method.addRequestHeader("Authorization", "OAuth " + accessToken) 70 | executeHttpMethod(method) match { 71 | case Some(Ok(body)) => Right(Js(body)) 72 | case Some(Unauthorized(headers)) => Left( 73 | headers.get("WWW-Authenticate") match { 74 | case Some(OAuthError(reason)) => Symbol(reason) 75 | case _ => 'unauthorized 76 | }) 77 | case _ => Left('other) 78 | } 79 | } 80 | 81 | _get(tokens._2, "http://api.mixi-platform.com/2" + path) match { 82 | case Right(result) => Some(result) 83 | case Left('expired_token) => refreshTokens(tokens._1) match { 84 | case Some(nextTokens) => get(nextTokens, path) 85 | case _ => None 86 | } 87 | case _ => None 88 | } 89 | } 90 | 91 | def executeHttpMethod(method: HttpMethodBase): Option[Response] = 92 | new HttpClient executeMethod(method) match { 93 | case HttpStatus.SC_OK => Some(Ok(method.getResponseBodyAsStream)) 94 | case HttpStatus.SC_UNAUTHORIZED => Some(Unauthorized( 95 | method.getResponseHeaders 96 | .map { x => x.getName -> x.getValue } toMap 97 | )) 98 | case _ => None 99 | } 100 | 101 | def using[A <: HttpMethodBase, B](method: A)(block: A => B): B = 102 | try { block(method) } 103 | finally { method.releaseConnection } 104 | } 105 | -------------------------------------------------------------------------------- /PHP/sample.php: -------------------------------------------------------------------------------- 1 | authorize($auth_code); 15 | } 16 | 17 | private function post($uri, $data) { 18 | $context = array('http' => array ( 19 | 'method' => 'POST', 20 | 'header' => 'Content-Type: application/x-www-form-urlencoded', 21 | 'content' => http_build_query($data, null, '&'), 22 | 'ignore_errors' => true, 23 | )); 24 | $body = file_get_contents($uri, false, stream_context_create($context)); 25 | $header = $this->parseHeader($http_response_header); 26 | if ($this->isHttpFail($header['Status'])) { 27 | throw new UnexpectedValueException('Post Request Fail:'.PHP_EOL.$uri.PHP_EOL.var_export($header, true)); 28 | } 29 | return $body; 30 | } 31 | 32 | private function authorize($auth_code) { 33 | $data = array( 34 | 'grant_type' => 'authorization_code', 35 | 'client_id' => CONSUMER_KEY, 36 | 'client_secret' => CONSUMER_SECRET, 37 | 'code' => $auth_code, 38 | 'redirect_uri' => REDIRECT_URI, 39 | ); 40 | $this->token = json_decode($this->post(self::MIXI_TOKEN_ENDPOINT, $data), true); 41 | } 42 | 43 | private function refreshToken() { 44 | $data = array( 45 | 'grant_type' => 'refresh_token', 46 | 'client_id' => CONSUMER_KEY, 47 | 'client_secret' => CONSUMER_SECRET, 48 | 'refresh_token' => $this->token['refresh_token'], 49 | ); 50 | $this->token = json_decode($this->post(self::MIXI_TOKEN_ENDPOINT, $data), true); 51 | } 52 | 53 | private function parseHeader($headers) { 54 | $statusLine = array_shift($headers); 55 | list(, $result['Status'], ) = explode(' ', $statusLine); 56 | foreach ($headers as $header) { 57 | list($key, $value) = explode(': ', $header); 58 | $result[$key] = $value; 59 | } 60 | return $result; 61 | } 62 | 63 | private function isHttpFail($status) { 64 | return (bool)(empty($status) || ($status >= 400)); 65 | } 66 | 67 | private function isExpired($headers) { 68 | $result = false; 69 | if (array_key_exists('WWW-Authenticate', $headers)) { 70 | if (preg_match('/expired_token/', $headers['WWW-Authenticate'])) { 71 | $result = true; 72 | } 73 | } 74 | return $result; 75 | } 76 | 77 | private function call($location) { 78 | static $retry_count = 0; 79 | 80 | $uri = self::MIXI_API_ENDPOINT . $location . '?oauth_token=' . $this->token['access_token']; 81 | $response = file_get_contents($uri, false, stream_context_create(array('http' => array('ignore_errors' => true)))); 82 | $header = $this->parseHeader($http_response_header); 83 | 84 | if ($this->isHttpFail($header['Status'])) { 85 | if ($this->isExpired($header)) { 86 | if ($retry_count++ > 1) { 87 | throw new RangeException('Token Refresh Too many retry. '.PHP_EOL.var_export($this->token, true).PHP_EOL.var_export($header, true)); 88 | } 89 | 90 | $this->refreshToken(); 91 | $response = $this->call($location); 92 | $retry_count = 0; 93 | } else { 94 | throw new UnexpectedValueException('Invalid API Access:'.PHP_EOL.$uri.PHP_EOL.var_export($header, true)); 95 | } 96 | } 97 | 98 | return $response; 99 | } 100 | 101 | public function execute($endpoint) { 102 | return json_decode($this->call($endpoint), true); 103 | } 104 | 105 | public static function getInstance($auth_code) { 106 | return new self($auth_code); 107 | } 108 | } 109 | 110 | if (debug_backtrace()) return; 111 | if ($_SERVER['argc'] != 2) { 112 | exit("Please input your Authorization Code\n Usage : {$_SERVER['argv'][0]} [YOUR AUTHORIZATION CODE]\n"); 113 | } 114 | 115 | try { 116 | $response = \MixiGraphAPIExample::getInstance($_SERVER['argv'][1])->execute('/people/@me/@self'); 117 | var_dump($response); 118 | } catch (Exception $e) { 119 | var_dump($e->getMessage()); 120 | } 121 | -------------------------------------------------------------------------------- /Java/Mixi.java: -------------------------------------------------------------------------------- 1 | import java.net.URL; 2 | import java.net.HttpURLConnection; 3 | import java.net.URLEncoder; 4 | import java.io.PrintWriter; 5 | import java.io.InputStream; 6 | import java.io.BufferedInputStream; 7 | import java.io.ByteArrayOutputStream; 8 | import java.io.OutputStreamWriter; 9 | import java.io.IOException; 10 | import java.io.UnsupportedEncodingException; 11 | 12 | public class Mixi { 13 | 14 | private static final String CLIENT_ID = "YOUR Client ID"; 15 | private static final String CLIENT_SECRET = "YOUR Client secret"; 16 | private static final String REDIRECT_URI = "YOUR Redirect URI"; 17 | 18 | private String accessToken; 19 | 20 | public void authorize(String authorizationCode) throws IOException { 21 | PrintWriter out = null; 22 | try { 23 | String params = buildParamsForAuthorization(authorizationCode); 24 | URL url = new URL("https://secure.mixi-platform.com/2/token"); 25 | HttpURLConnection connection = (HttpURLConnection)url.openConnection(); 26 | connection.setDoOutput(true); 27 | out = new PrintWriter(new OutputStreamWriter( 28 | connection.getOutputStream(), "UTF-8")); 29 | out.print(params); 30 | out.flush(); 31 | int responseCode = connection.getResponseCode(); 32 | if (responseCode == HttpURLConnection.HTTP_OK) { 33 | String responseBody = readStream(connection.getInputStream()); 34 | accessToken = getPropertyValue(responseBody, "access_token"); 35 | } else { 36 | String responseBody = readStream(connection.getErrorStream()); 37 | throw new IOException(responseCode + ": " + responseBody); 38 | } 39 | } finally { 40 | if (out != null) { 41 | out.close(); 42 | } 43 | } 44 | } 45 | 46 | public String call(String endpoint) throws IOException { 47 | URL url = new URL("http://api.mixi-platform.com/2" + endpoint); 48 | HttpURLConnection connection = (HttpURLConnection)url.openConnection(); 49 | connection.setRequestProperty("Authorization", "OAuth " + accessToken); 50 | int responseCode = connection.getResponseCode(); 51 | if (responseCode == HttpURLConnection.HTTP_OK) { 52 | String responseBody = readStream(connection.getInputStream()); 53 | return responseBody; 54 | } else { 55 | String responseBody = readStream(connection.getErrorStream()); 56 | throw new IOException(responseCode + ": " + responseBody); 57 | } 58 | } 59 | 60 | private String buildParamsForAuthorization(String authorizationCode) { 61 | try { 62 | StringBuilder sb = new StringBuilder(); 63 | sb.append("client_id="); 64 | sb.append(CLIENT_ID); 65 | sb.append("&client_secret="); 66 | sb.append(CLIENT_SECRET); 67 | sb.append("&redirect_uri="); 68 | sb.append(URLEncoder.encode(REDIRECT_URI, "UTF-8")); 69 | sb.append("&code="); 70 | sb.append(authorizationCode); 71 | sb.append("&grant_type=authorization_code"); 72 | return sb.toString(); 73 | } catch(UnsupportedEncodingException e) { 74 | throw new IllegalStateException(e); 75 | } 76 | } 77 | 78 | private String readStream(InputStream in) throws IOException { 79 | ByteArrayOutputStream out = new ByteArrayOutputStream(); 80 | try { 81 | byte[] buf = new byte[1024]; 82 | int len = -1; 83 | BufferedInputStream bis = new BufferedInputStream(in, 1024); 84 | while((len = bis.read(buf, 0, 1024)) != -1) { 85 | out.write(buf); 86 | } 87 | return new String(out.toByteArray(), "UTF-8"); 88 | } finally { 89 | try { 90 | out.close(); 91 | } catch(IOException e) { 92 | throw new IllegalStateException(e); 93 | } 94 | } 95 | } 96 | 97 | private String getPropertyValue(String json, String propertyName) { 98 | String name = "\"" + propertyName + "\":\""; 99 | int pos = json.indexOf(name) + name.length(); 100 | String value = json.substring(pos, json.indexOf("\"", pos + 1)); 101 | return value; 102 | } 103 | 104 | public static void main(String[] args) throws IOException { 105 | if (args.length != 1) { 106 | throw new IllegalArgumentException("Authorization code is mandatory."); 107 | } 108 | String authorizationCode = args[0]; 109 | Mixi mixi = new Mixi(); 110 | mixi.authorize(authorizationCode); 111 | String response = mixi.call("/people/@me/@self"); 112 | System.out.println(mixi.getPropertyValue(response, "displayName")); 113 | } 114 | 115 | } -------------------------------------------------------------------------------- /c/http.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "http.h" 7 | 8 | #define BUF_LEN 256 9 | 10 | char* new_json_property_value(char* json, char* property_name) { 11 | char* property; 12 | int len; 13 | char* base_pos; 14 | char* end_pos; 15 | char* result; 16 | 17 | len = strlen(property_name); 18 | property = malloc(len + 3); 19 | property[0] = '"'; 20 | strncpy(property + 1, property_name, len); 21 | property[len + 1] = '"'; 22 | property[len + 2] = '\0'; 23 | 24 | base_pos = strstr(json, property); 25 | if (base_pos == NULL) { 26 | result = malloc(1); 27 | result[0] = '\0'; 28 | } else { 29 | base_pos += strlen(property) + 2; 30 | end_pos = strstr(base_pos, "\""); 31 | len = (int)(end_pos - base_pos); 32 | 33 | result = malloc(len + 1); 34 | strncpy(result, base_pos, len); 35 | result[len] = '\0'; 36 | } 37 | 38 | free(property); 39 | return result; 40 | } 41 | 42 | int get_http_status_code(const char* response) { 43 | char buf[4]; 44 | 45 | strncpy(buf, response + 9, 3); 46 | buf[3] = '\0'; 47 | return atoi(buf); 48 | } 49 | 50 | char* new_http_response_body(const char* response) { 51 | char* pos; 52 | char* result; 53 | 54 | pos = strstr(response, "\r\n\r\n") + 4; 55 | result = malloc(strlen(pos) + 1); 56 | strcpy(result, pos); 57 | 58 | return result; 59 | } 60 | 61 | int connect_to_server(char* host, int port, char* path) { 62 | int s; 63 | 64 | struct hostent* servhost; 65 | struct sockaddr_in server; 66 | 67 | servhost = gethostbyname(host); 68 | if (servhost == NULL) { 69 | fprintf(stderr, "Failed to change from [%s] to IP address.\n", host); 70 | exit(1); 71 | } 72 | memset((char*)&server, 0, sizeof(server)); 73 | server.sin_family = AF_INET; 74 | memcpy((char*)&server.sin_addr, servhost->h_addr, servhost->h_length); 75 | server.sin_port = htons(port); 76 | s = socket(AF_INET, SOCK_STREAM, 0); 77 | if (s < 0) { 78 | fprintf(stderr, "Failed to create a socket.\n"); 79 | exit(1); 80 | } 81 | if (connect(s, (struct sockaddr*)&server, sizeof(server)) == -1) { 82 | fprintf(stderr, "Failed to connect.\n"); 83 | exit(1); 84 | } 85 | 86 | return s; 87 | } 88 | 89 | struct ssl_info ssl_initialize(int s) { 90 | int ret; 91 | unsigned short rand_ret; 92 | 93 | SSL* ssl; 94 | SSL_CTX* ctx; 95 | 96 | struct ssl_info result; 97 | 98 | SSL_load_error_strings(); 99 | SSL_library_init(); 100 | ctx = SSL_CTX_new(SSLv23_client_method()); 101 | if (ctx == NULL) { 102 | ERR_print_errors_fp(stderr); 103 | exit(1); 104 | } 105 | ssl = SSL_new(ctx); 106 | if (ssl == NULL) { 107 | ERR_print_errors_fp(stderr); 108 | exit(1); 109 | } 110 | ret = SSL_set_fd(ssl, s); 111 | if (ret == 0) { 112 | ERR_print_errors_fp(stderr); 113 | exit(1); 114 | } 115 | RAND_poll(); 116 | while(RAND_status() == 0) { 117 | rand_ret = rand() % 65536; 118 | RAND_seed(&rand_ret, sizeof(rand_ret)); 119 | } 120 | ret = SSL_connect(ssl); 121 | if (ret != 1) { 122 | ERR_print_errors_fp(stderr); 123 | exit(1); 124 | } 125 | 126 | result.ssl = ssl; 127 | result.ctx = ctx; 128 | return result; 129 | } 130 | 131 | char* receive_http_response(enum ePROTOCOL protocol, int s, SSL* ssl) { 132 | int cnt; 133 | int sum; 134 | int read_size; 135 | 136 | char buf[BUF_LEN]; 137 | char* response; 138 | 139 | response = malloc(BUF_LEN); 140 | cnt = 1; 141 | sum = 0; 142 | while(1) { 143 | if (protocol == HTTPS) { 144 | read_size = SSL_read(ssl, buf, sizeof(buf)); 145 | } else { 146 | read_size = read(s, buf, sizeof(buf)); 147 | } 148 | if (read_size > 0) { 149 | if ((sum + read_size + 1) > (BUF_LEN * cnt)) { 150 | response = realloc(response, BUF_LEN * ++cnt + 1); 151 | } 152 | memcpy(response + sum, buf, read_size); 153 | sum += read_size; 154 | } else if (read_size == 0) { 155 | response[sum] = '\0'; 156 | break; 157 | } else { 158 | ERR_print_errors_fp(stderr); 159 | exit(1); 160 | } 161 | } 162 | 163 | return response; 164 | } 165 | 166 | void close_connection(enum ePROTOCOL protocol, int s, struct ssl_info* ssl) { 167 | int ret; 168 | 169 | if (protocol == HTTPS) { 170 | ret = SSL_shutdown(ssl->ssl); 171 | if (ret != 1) { 172 | ERR_print_errors_fp(stderr); 173 | exit(1); 174 | } 175 | SSL_free(ssl->ssl); 176 | SSL_CTX_free(ssl->ctx); 177 | ERR_free_strings(); 178 | } 179 | close(s); 180 | } 181 | 182 | void send_http_request(enum ePROTOCOL protocol, char* request, int s, SSL* ssl) { 183 | int ret; 184 | 185 | if (protocol == HTTPS) { 186 | ret = SSL_write(ssl, request, strlen(request)); 187 | } else { 188 | ret = write(s, request, strlen(request)); 189 | } 190 | if (ret < 1) { 191 | ERR_print_errors_fp(stderr); 192 | exit(1); 193 | } 194 | } 195 | -------------------------------------------------------------------------------- /cpp/sample.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "clx/https.h" 3 | #include "clx/uri.h" 4 | #include "clx/ssl.h" 5 | #include "clx/json.h" 6 | 7 | using namespace std; 8 | 9 | class mixi_client { 10 | public: 11 | mixi_client() { 12 | CLIENT_ID= "YOUR Client ID"; 13 | CLIENT_SECRET = "YOUR Client secret"; 14 | REDIRECT_URI = "YOUR Redirect URI"; 15 | secure_host = "secure.mixi-platform.com"; 16 | api_host = "api.mixi-platform.com"; 17 | token_path = "/2/token/"; 18 | } 19 | 20 | void get_auth_token(string auth_code) { 21 | mapheader; 22 | header.insert(map::value_type( "Content-Type","application/x-www-form-urlencoded" ) ); 23 | 24 | clx::https httpClient(secure_host, 443); 25 | string query = get_auth_token_param(auth_code); 26 | httpClient.post(token_path, query, header); 27 | if (httpClient.code() != 200) { 28 | std::cout << "error" << std::endl << httpClient.body() << std::endl; 29 | return ; 30 | } 31 | clx::json response(httpClient.body()); 32 | access_token = response["access_token"]; 33 | refresh_token = response["refresh_token"]; 34 | } 35 | 36 | clx::json get_people(string access_token, string user, string group, bool do_retry=true){ 37 | mapheader; 38 | string token; 39 | token.append("OAuth ").append(access_token); 40 | header.insert(map::value_type("Authorization", token)); 41 | header.insert(map::value_type("Content-Type", "application/x-www-form-urlencoded")); 42 | string path = "/2/people/"; 43 | path.append(user).append("/") 44 | .append(group).append("/"); 45 | clx::http httpClient(api_host); 46 | httpClient.get(clx::uri::encode(path), header); 47 | if (httpClient.code() != 200) { 48 | if (is_token_expired(httpClient) && do_retry) { 49 | return get_people(excahge_token(refresh_token), 50 | user, group, false); 51 | } 52 | std::cout << "error code:" << httpClient.code() << std::endl 53 | << httpClient.body() << std::endl; 54 | std::exit(-1); 55 | } 56 | clx::json results(httpClient.body()); 57 | clx::json entity(results["entry"]); 58 | return entity; 59 | } 60 | 61 | clx::json get_people(string user, string group){ 62 | return get_people(access_token,user,group); 63 | } 64 | 65 | private: 66 | const char* CLIENT_ID; 67 | const char* CLIENT_SECRET; 68 | const char* REDIRECT_URI; 69 | const char* secure_host; 70 | const char* api_host; 71 | const char* token_path; 72 | string access_token; 73 | string refresh_token; 74 | 75 | string excahge_token(string refresh_token) { 76 | mapheader; 77 | header.insert(map::value_type("Content-Type", "application/x-www-form-urlencoded")); 78 | 79 | clx::https httpClient(secure_host, 443); 80 | string query = get_refresh_token_param(refresh_token); 81 | httpClient.post(token_path, query, header); 82 | clx::json response(httpClient.body()); 83 | access_token = response["access_token"]; 84 | refresh_token = response["refresh_token"]; 85 | return access_token; 86 | } 87 | 88 | bool is_token_expired(clx::http client){ 89 | if (client.code() == 401) { 90 | if (client.head()["WWW-Authenticate"].length()) { 91 | return true; 92 | } 93 | } 94 | return false; 95 | } 96 | 97 | string get_refresh_token_param(string refresh_token) { 98 | ostringstream buff; 99 | buff << "client_id=" << CLIENT_ID 100 | << "&client_secret=" << CLIENT_SECRET 101 | << "&refresh_token=" << refresh_token 102 | << "&grant_type=refresh_token"; 103 | return buff.str(); 104 | } 105 | 106 | string get_auth_token_param(string code) { 107 | ostringstream buff; 108 | buff << "client_id=" << CLIENT_ID 109 | << "&client_secret=" << CLIENT_SECRET 110 | << "&redirect_uri=" << url_encode(REDIRECT_URI) 111 | << "&code=" << code 112 | << "&grant_type=authorization_code"; 113 | return buff.str(); 114 | } 115 | 116 | string url_encode(const string& src) { 117 | ostringstream buff; 118 | buff << std::hex << std::setfill('0'); 119 | typedef string::const_iterator Iterator; 120 | Iterator end = src.end(); 121 | for (Iterator itr = src.begin(); itr != end; ++itr) { 122 | if((*itr >= 'a' && *itr <= 'z') 123 | || (*itr >= 'A' && *itr <= 'Z') 124 | || (*itr >= '0' && *itr <= '9') 125 | || *itr == '-' || *itr == '.' 126 | || *itr == '_' || *itr == '~') { 127 | buff << *itr; 128 | } else { 129 | buff << '%' << std::setw(2) 130 | << static_cast(static_cast(*itr)); 131 | } 132 | } 133 | return buff.str(); 134 | } 135 | }; 136 | 137 | int main(int argc, char* argv[]) { 138 | 139 | mixi_client client ; 140 | if (argc > 1) { 141 | string auth_code = argv[1]; 142 | client.get_auth_token(auth_code); 143 | } 144 | 145 | clx::json entity =client.get_people("@me","@self"); 146 | for (clx::json::iterator pos = entity.begin(); pos != entity.end(); ++pos) { 147 | std::cout << pos->first << " " << pos->second << std::endl; 148 | } 149 | return 0; 150 | } 151 | -------------------------------------------------------------------------------- /scala/src/main/scala/example01/Main.scala: -------------------------------------------------------------------------------- 1 | package example01 2 | 3 | import scala.annotation.tailrec 4 | 5 | import dispatch.json.{Js, JsArray, JsObject, JsString, JsValue} 6 | import org.apache.commons.httpclient.{HttpClient, HttpMethodBase, HttpStatus} 7 | import org.apache.commons.httpclient.methods.{GetMethod, PostMethod} 8 | import sjson.json.{DefaultProtocol, Format, JsonSerialization, Reads} 9 | 10 | case class Tokens(refreshToken: String, expiresIn: Int, accessToken: String) 11 | case class Response(entries: List[Entry]) 12 | case class Entry(id: String, displayName: String, thumbnailUrl: String, profileUrl: String) 13 | 14 | object Protocols extends DefaultProtocol { 15 | implicit val TokensFormat: Format[Tokens] = 16 | asProduct3("refresh_token", "expires_in", "access_token")(Tokens)(Tokens.unapply(_).get) 17 | implicit val EntryFormat: Format[Entry] = 18 | asProduct4("id", "displayName", "thumbnailUrl", "profileUrl")(Entry)(Entry.unapply(_).get) 19 | 20 | implicit object ResponseFormat extends Reads[Response] { 21 | import JsonSerialization.fromjson 22 | def reads(js: JsValue) = js match { 23 | case JsObject(x) => x(JsString("entry")) match { 24 | case y: JsObject => Response(fromjson[Entry](y) :: Nil) 25 | case ys: JsArray => Response(fromjson[List[Entry]](ys)) 26 | case y => sys.error("Require object or array.(%s)".format(y)) 27 | } 28 | case x => sys.error("Require object.(%s)".format(x)) 29 | } 30 | } 31 | } 32 | 33 | object Main { 34 | import JsonSerialization.fromjson 35 | import Protocols._ 36 | 37 | val CONSUMER_KEY = "" 38 | val CONSUMER_SECRET = "" 39 | 40 | val TOKEN_ENDPOINT = "https://secure.mixi-platform.com/2/token" 41 | val API_ENDPOINT_BASE = "http://api.mixi-platform.com/2" 42 | val REDIRECT_URI = "http://mixi.jp/connect_authorize_success.html" 43 | 44 | val REQUEST_TOKEN_BASE_PARAMS = Map("client_id" -> CONSUMER_KEY, 45 | "client_secret" -> CONSUMER_SECRET) 46 | 47 | def main(args: Array[String]) { 48 | args match { 49 | case Array(authorizationCode, _*) => repl(getTokens(authorizationCode)) 50 | case _ => printf("""Usage: sbt run 51 | | please access the following url and get Autohrization Code. 52 | | https://mixi.jp/connect_authorize.pl?client_id=%s&response_type=code&scope=r_profile 53 | |""".stripMargin, 54 | CONSUMER_KEY) 55 | } 56 | } 57 | 58 | def getTokens(authorizationCode: String): Tokens = 59 | retrieveTokens(REQUEST_TOKEN_BASE_PARAMS + 60 | ("grant_type" -> "authorization_code") + 61 | ("code" -> authorizationCode) + 62 | ("redirect_uri" -> REDIRECT_URI)) 63 | 64 | def refreshTokens(tokens: Tokens): Tokens = 65 | retrieveTokens(REQUEST_TOKEN_BASE_PARAMS + 66 | ("grant_type" -> "refresh_token") + 67 | ("refresh_token" -> tokens.refreshToken)) 68 | 69 | def retrieveTokens(params: Map[String, String]): Tokens = 70 | using(new PostMethod(TOKEN_ENDPOINT)) { method => 71 | for ((name, value) <- params) 72 | method.addParameter(name, value) 73 | 74 | new HttpClient executeMethod(method) match { 75 | case HttpStatus.SC_OK => 76 | fromjson[Tokens](Js(method.getResponseBodyAsStream)) 77 | case _ => 78 | sys.error("Failure: %s".format(method.getStatusLine)) 79 | } 80 | } 81 | 82 | val InputFormat = """\A\s*(@me|\w+)\s+(@self|@friends|\w+)\s*\z""".r 83 | @tailrec 84 | def repl(tokens: Tokens) { 85 | 86 | def read = Console.readLine("Input : ") match { 87 | case InputFormat(userId, groupId) => Some((userId, groupId)) 88 | case _ => None 89 | } 90 | 91 | def eval(userId: String, groupId: String): (Tokens, List[Entry]) = 92 | request(tokens, "/people/%s/%s".format(userId, groupId)) match { 93 | case (nextTokens, Some(value)) => (nextTokens, 94 | fromjson[Response](value).entries) 95 | case (nextTokens, None) => (nextTokens, Nil) 96 | } 97 | 98 | def print(entries: List[Entry]) = 99 | for { 100 | Entry(id, displayName, thumbnailUrl, profileUrl) <- entries 101 | text = """Entry(id: %s 102 | | displayName: %s 103 | | thumbnailUrl: %s 104 | | profileUrl: %s)""".stripMargin 105 | .format(id, displayName, thumbnailUrl, profileUrl) 106 | } println(text) 107 | 108 | val nextTokens = for { 109 | (userId, groupId) <- read 110 | (tokens, entries) = eval(userId, groupId) 111 | } yield { 112 | print(entries) 113 | tokens 114 | } 115 | 116 | repl(nextTokens.getOrElse(tokens)) 117 | } 118 | 119 | val ErrorPattern = """\A\s*OAuth\s+.*error='([^']+)'.*\z""".r 120 | @tailrec 121 | def request(tokens: Tokens, path: String): (Tokens, Option[JsValue]) = { 122 | 123 | def _request(accessToken: String, path: String): Either[Any, JsValue] = 124 | using(new GetMethod(API_ENDPOINT_BASE + path)) { method => 125 | method.setDoAuthentication(false) 126 | method.addRequestHeader("Authorization", 127 | "OAuth %s".format(accessToken)) 128 | new HttpClient executeMethod(method) match { 129 | case HttpStatus.SC_OK => Right(Js(method.getResponseBodyAsStream)) 130 | case HttpStatus.SC_UNAUTHORIZED => 131 | method.getResponseHeaders("WWW-Authenticate").map(_.getValue) match { 132 | case Array(ErrorPattern(reason), _*) => Left(Symbol(reason)) 133 | case _ => Left(method.getStatusLine) 134 | } 135 | case _ => Left(method.getStatusLine) 136 | } 137 | } 138 | 139 | _request(tokens.accessToken, path) match { 140 | case Right(js) => (tokens, Some(js)) 141 | case Left('expired_token) => request(refreshTokens(tokens), path) 142 | case Left(reason) => printf("Failure.(reason: %s)\n", reason) 143 | (tokens, None) 144 | } 145 | } 146 | 147 | def using[A <: HttpMethodBase, B](method: A)(block: A => B): B = 148 | try { block(method) } 149 | finally { method.releaseConnection } 150 | } 151 | -------------------------------------------------------------------------------- /golang/mixi.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "errors" 6 | "io/ioutil" 7 | "log" 8 | "net" 9 | "net/http" 10 | "net/http/httputil" 11 | 12 | "net/url" 13 | "strings" 14 | "text/template" 15 | ) 16 | 17 | type friend struct { 18 | DisplayName string 19 | ThumbnailUrl string 20 | ProfileUrl string 21 | } 22 | 23 | type tokens struct { 24 | AccessToken string 25 | RefreshToken string 26 | } 27 | 28 | const ( 29 | AUTHORIZE_URL_BASE = "https://mixi.jp/connect_authorize.pl?response_type=code&scope=r_profile&client_id=" 30 | TOKENS_ENDPOINT = "https://secure.mixi-platform.com/2/token" 31 | FRIEND_LIST_ENDPOINT = "http://api.mixi-platform.com/2/people/@me/@friends" 32 | CONFIG_FILENAME = "config.json" 33 | TOKENS_FILENAME = "tokens.txt" 34 | TEMPLATE = ` 35 | 36 | Friend Lit 37 | 38 |
    39 | {.repeated section Friends} 40 |
  • 41 | 42 | {DisplayName} 43 |
  • 44 | {.end} 45 |
46 | 47 | 48 | ` 49 | ) 50 | 51 | var config map[string]string 52 | var currentTokens *tokens 53 | 54 | func NewTokens(accessToken string, refreshToken string) *tokens { 55 | return &tokens{accessToken, refreshToken} 56 | } 57 | 58 | func RestoreTokens() *tokens { 59 | if bytes, err := ioutil.ReadFile(TOKENS_FILENAME); err == nil { 60 | pair := strings.Split(string(bytes), "\n") 61 | return &tokens{pair[0], pair[1]} 62 | } 63 | return nil 64 | } 65 | 66 | func (t *tokens) store() { 67 | ioutil.WriteFile(TOKENS_FILENAME, []byte(t.AccessToken+ 68 | "\n"+t.RefreshToken), 0666) 69 | } 70 | 71 | func authorizeCode(authCode string) (err error) { 72 | return updateTokens(map[string][]string{ 73 | "grant_type": {"authorization_code"}, 74 | "client_id": {config["client_id"]}, 75 | "client_secret": {config["client_secret"]}, 76 | "code": {authCode}, 77 | "redirect_uri": {"http://localhost:" + config["redirect_port"]}, 78 | }) 79 | } 80 | 81 | func refreshToken() (err error) { 82 | return updateTokens(map[string][]string{ 83 | "grant_type": {"refresh_token"}, 84 | "client_id": {config["client_id"]}, 85 | "client_secret": {config["client_secret"]}, 86 | "refresh_token": {currentTokens.RefreshToken}, 87 | }) 88 | } 89 | 90 | func updateTokens(params map[string][]string) (err error) { 91 | println("Call: " + TOKENS_ENDPOINT) 92 | response, _ := http.PostForm(TOKENS_ENDPOINT, params) 93 | b, _ := ioutil.ReadAll(response.Body) 94 | println(string(b)) 95 | 96 | var responseJson map[string]interface{} 97 | json.Unmarshal(b, &responseJson) 98 | if errorMessage, ok := responseJson["error"]; ok { 99 | return errors.New(errorMessage.(string)) 100 | } else { 101 | currentTokens = &tokens{responseJson["access_token"].(string), responseJson["refresh_token"].(string)} 102 | currentTokens.store() 103 | return nil 104 | } 105 | return errors.New("access_token is null") 106 | } 107 | 108 | func oauthGet(accessToken string, urlString string) (*http.Response, error) { 109 | url_, _ := url.Parse(urlString) 110 | conn, _ := net.Dial("tcp", url_.Host+":80") 111 | 112 | clientConn := httputil.NewClientConn(conn, nil) 113 | header := map[string][]string{"Authorization": {"OAuth " + accessToken}} 114 | request := http.Request{Method: "GET", URL: url_, Header: header} 115 | clientConn.Write(&request) 116 | return clientConn.Read(&request) 117 | } 118 | 119 | func getFriendList() (friends []friend, err error) { 120 | println("Call: " + FRIEND_LIST_ENDPOINT) 121 | response, _ := oauthGet(currentTokens.AccessToken, FRIEND_LIST_ENDPOINT) 122 | if response.StatusCode == 401 { 123 | if err = refreshToken(); err == nil { 124 | return getFriendList() 125 | } 126 | return nil, err 127 | } 128 | b, _ := ioutil.ReadAll(response.Body) 129 | println(string(b)) 130 | 131 | var responseJson map[string]interface{} 132 | json.Unmarshal(b, &responseJson) 133 | entry := responseJson["entry"].([]interface{}) 134 | totalResults := int(responseJson["totalResults"].(float64)) 135 | itemsPerPage := int(responseJson["itemsPerPage"].(float64)) 136 | var itemsCount int 137 | if itemsPerPage < totalResults { 138 | itemsCount = itemsPerPage 139 | } else { 140 | itemsCount = totalResults 141 | } 142 | friends = make([]friend, itemsCount) 143 | for i := 0; i < itemsCount; i++ { 144 | data := entry[i].(map[string]interface{}) 145 | friends[i] = friend{ 146 | DisplayName: data["displayName"].(string), 147 | ThumbnailUrl: data["thumbnailUrl"].(string), 148 | ProfileUrl: data["profileUrl"].(string), 149 | } 150 | } 151 | return friends, nil 152 | } 153 | 154 | func redirect(writer http.ResponseWriter, request *http.Request, redirectUrl string) { 155 | println("Redirect to: " + redirectUrl) 156 | http.Redirect(writer, request, redirectUrl, http.StatusFound) 157 | } 158 | 159 | func handleFriendList(writer http.ResponseWriter, request *http.Request) { 160 | if request.URL.Path == "/favicon.ico" { 161 | return 162 | } 163 | 164 | var ( 165 | friends []friend 166 | err error 167 | ) 168 | 169 | authorizeUrl := AUTHORIZE_URL_BASE + config["client_id"] 170 | parts := strings.Split(request.URL.RawPath, "?code=") 171 | if 2 <= len(parts) { 172 | if err = authorizeCode(parts[1]); err != nil { 173 | redirect(writer, request, authorizeUrl) 174 | } else { 175 | redirect(writer, request, "/") 176 | } 177 | return 178 | } else if currentTokens == nil { 179 | redirect(writer, request, authorizeUrl) 180 | return 181 | } 182 | 183 | if friends, err = getFriendList(); err != nil { 184 | redirect(writer, request, authorizeUrl) 185 | } else { 186 | params := new(struct{ Friends []friend }) 187 | params.Friends = friends 188 | tmpl, _ := template.New("mixi").Parse(TEMPLATE) 189 | tmpl.Execute(writer, params) 190 | } 191 | } 192 | 193 | func main() { 194 | var ( 195 | bytes []byte 196 | err error 197 | ) 198 | 199 | if bytes, err = ioutil.ReadFile(CONFIG_FILENAME); err != nil { 200 | log.Fatal("ioutil.ReadFile:", err) 201 | } 202 | if err = json.Unmarshal(bytes, &config); err != nil { 203 | log.Fatal("json.Unmarshal:", err) 204 | } 205 | currentTokens = RestoreTokens() 206 | 207 | http.Handle("/", http.HandlerFunc(handleFriendList)) 208 | 209 | addr := "localhost:" + config["redirect_port"] 210 | println("Please open http://" + addr + " on a web browser.") 211 | if err = http.ListenAndServe(addr, nil); err != nil { 212 | log.Fatal("http.ListenAndServe:", err) 213 | } 214 | } 215 | --------------------------------------------------------------------------------