Fork me on GitHub

2010/09/16


このエントリーをはてなブックマークに追加
サイボウズLiveにAPIが追加されましたね。
機能追加のお知らせ(API公開、Googleカレンダーとの同期、デザイン変更) | サイボウズLiveマガジン
9月15日のサイトメンテナンスにより、新機能を追加しました。
■APIの公開
外部アプリケーションからサイボウズLiveの情報を取得・操作できるAPIを公開しました。通信方式はREST、認証方式はOAuthです。現在は最新情報の取得、スケジュール情報の取得に限定していますが、順次APIで取得・操作可能な情報を拡充していきます。
APIの公開にあわせて、サイボウズLive Developer Centerを公開しました。
http://magazine.cybozulive.com/2010/09/system_update10.html
API好きとしては、これを放っておく訳にはいきません。
もちろんVimで行きます!

APIはドキュメントによるとAtomを使います。また認証にはTwitterと同じくOAuthが採用されています。
Vimscriptでやるには少し敷居が高いんじゃないの?と思っている貴方!出来るんです!やるんです!

まず先日作った、vim-oauthを使って認証を行いました。
"https://api.cybozulive.com/oauth/initiate" に対してリクエストトークンを要求し、そのリクエストトークンを元に "https://api.cybozulive.com/oauth/authorize" でブラウザ認証を行います。すると数文字のベリファイアが貰えるので、"https://api.cybozulive.com/oauth/token" へアクセストークンを要求します。
これで認証必要な物は揃いました。ここまでをコードにすると以下の様な感じ。
set rtp+=webapi-vim

let config = {}
let configfile = expand('~/.cybozulive')
if filereadable(configfile)
  let config = eval(join(readfile(configfile)""))
else
  let config.consumer_key = input("consumer_key:")
  let config.consumer_secret = input("consumer_secret:")
  
  let request_token_url = "https://api.cybozulive.com/oauth/initiate"
  let auth_url =  "https://api.cybozulive.com/oauth/authorize"
  let access_token_url = "https://api.cybozulive.com/oauth/token"
  
  let [request_token, request_token_secret] = oauth#requestToken(request_token_url, config.consumer_key, config.consumer_secret)
  if has("win32") || has("win64")
    exe "!start rundll32 url.dll,FileProtocolHandler ".auth_url."?oauth_token=".request_token
  else
    call system("xdg-open '".auth_url."?oauth_token=".request_token."'")
  endif
  let verifier = input("PIN:")
  let [access_token, access_token_secret] = oauth#accessToken(access_token_url, config.consumer_key, config.consumer_secret, request_token, request_token_secret, {"oauth_verifier": verifier})
  let config.access_token = access_token
  let config.access_token_secret = access_token_secret
  call writefile([string(config)], configfile)
endif
これで、アクセストークンとアクセストークンシークレットが貰えます。簡単ですね!
さて、肝心のAtomです。このブログでは紹介した事なかったと思いますが、VimでのXMLパーサを実は以前書いた暖めておりました。
mattn's xmlparser-vim at master - GitHub

XML Parser for Vim

http://github.com/mattn/xmlparser-vim
これを使ってパースしました。パースするとDOMが返ります。
let notification_url = "https://api.cybozulive.com/api/notification/V2"
let ret = oauth#get(notification_url, config.consumer_key, config.consumer_secret, config.access_token, config.access_token_secret, {})
let dom = xml#parse(ret.content)
for elem in dom.findAll("entry")
  echo elem.find("updated").value() . " " .  elem.find("title").value()
  echo "  " . elem.find("author").find("name").value()
  let summary = elem.find("summary")
  if !empty(summary)
    echo "  " . substitute(summary.value(), "\n""\n  ""g")
  endif
  echo "\n"
endfor
こんな感じにXMLを処理出来ます。これ、全てPure Vimscriptです。信じれない人や変態な人は、ソース覗いて下さい。
動く物を置いておきます。
mattn's cybozulive-vim at master - GitHub

vim interface to cybozulive

http://github.com/mattn/cybozulive-vim
http 関連、XML関連を纏めて webapi-vim というリポジトリに入れ、cybozulive-vim からは submodule としています。
mattn's webapi-vim at master - GitHub

vim interface to Web API

http://github.com/mattn/webapi-vim
# git submodule init
# git submodule update
として下さい。
以下、cybozulive.vim の全体のソースです。
set rtp+=webapi-vim

let config = {}
let configfile = expand('~/.cybozulive')
if filereadable(configfile)
  let config = eval(join(readfile(configfile)""))
else
  let config.consumer_key = input("consumer_key:")
  let config.consumer_secret = input("consumer_secret:")
  
  let request_token_url = "https://api.cybozulive.com/oauth/initiate"
  let auth_url =  "https://api.cybozulive.com/oauth/authorize"
  let access_token_url = "https://api.cybozulive.com/oauth/token"
  
  let [request_token, request_token_secret] = oauth#requestToken(request_token_url, config.consumer_key, config.consumer_secret)
  if has("win32") || has("win64")
    exe "!start rundll32 url.dll,FileProtocolHandler ".auth_url."?oauth_token=".request_token
  else
    call system("xdg-open '".auth_url."?oauth_token=".request_token."'")
  endif
  let verifier = input("PIN:")
  let [access_token, access_token_secret] = oauth#accessToken(access_token_url, config.consumer_key, config.consumer_secret, request_token, request_token_secret, {"oauth_verifier": verifier})
  let config.access_token = access_token
  let config.access_token_secret = access_token_secret
  call writefile([string(config)], configfile)
endif

let notification_url = "https://api.cybozulive.com/api/notification/V2"
let ret = oauth#get(notification_url, config.consumer_key, config.consumer_secret, config.access_token, config.access_token_secret, {})
let dom = xml#parse(ret.content)
for elem in dom.findAll("entry")
  echo elem.find("updated").value() . " " .  elem.find("title").value()
  echo "  " . elem.find("author").find("name").value()
  let summary = elem.find("summary")
  if !empty(summary)
    echo "  " . substitute(summary.value(), "\n""\n  ""g")
  endif
  echo "\n"
endfor
実行結果貼っておきますね。
2010-09-16T03:33:00Z サイボウズLiveアプリを作る!
  松本 泰弘
  [登録] 2010年9月16日(木)

2010-06-30T14:42:20Z tw.pptx
  竹迫 良範

2010-09-15T02:40:58Z mattnさんとオフする
  松本 泰弘
  大阪に出張に逝ったときとか

2010-06-18T01:27:21Z 竹迫 良範 さんが参加しました
  竹迫 良範

2010-02-26T03:59:58Z test
  hasegawa yosuke
  EF BB BF C0 AF 2F
  (添付ファイルがあります。)

mattn the pure vimscripter.
Posted at 15:54 in ソフトウェア::vim
Tagged as: API, Atom, OAuth, vim, xml
Bookmarks: add to hatena add to hatena | add to delicious.com | add to livedoor.clip add to livedoor.clip

2007/11/06


このエントリーをはてなブックマークに追加
Blogging APIは何処に行こうとしているのか...

先日は、XMLRPCについてのお話をさせて頂きました。
今日はその中で出てきたBlogging APIについて。
著名なブログツールの多くは、リモートからブログが更新出来る仕組みを提供しています。
その中でも、一般的な物が先日お話した「XMLRPC」をベースにした「Blogger API」や「metaWeblog API」、「MovableType API」があります。
※現在ではBloggerはXMLRPCではなく、Atompubを使用しています。
それとは別に、Atomフィードを使用したAtomPub APIがあります。
XMLRPCの場合は、リモートメソッドとしてXMLを生成してブログの投稿、削除等を行いますが、AtomPubの場合は送受信されるXMLの単位自身が文書になります。
この文書をHTTPのGET/POST(PUT)およびDELETEメソッドを使用して文書(ブログ)を更新します。
AtomPubではAtomフィードにひもづけられた登録用URIに対して文書をPOST(PUT)する事で新規エントリ、既存エントリにひもづけられた編集用URIに対してPOST(PUT)する事でエントリ更新、そして既存エントリの編集用URIに対してDELETEメソッドを送信する事でエントリ削除という動作になります。
一部のサーバではDELETEメソッドを受け付けない物もあるので、「X-Http-Method-Override: DELETE」というヘッダでDELETEメソッドと同じ処理が行える様になっているサーバもあります。

この2つのAPIの大きな違いとして、文書形式と認証方法が挙げられます。

XMLRPCの場合は、各メソッドに対してユーザIDおよびパスワードを渡す事になります。
またXMLRPCでは送信されるXML自身はメソッドパラメータが含まれ、その中にはユーザIDやパスワードも含まれてしまいます。二次利用する事は出来ません。

AtomPubの場合は、上で説明した通り送受信されるXML自身が文書である為に二次利用も可能です。
また認証方法は一般的にはBasic認証か、WSSE認証が用いられています。

巷のブログサービスは以下の様なAPI実装を行っています。
ブログサービス提供APIフォーマットエントリポイント
teacupXMLRPCHTMLhttp://white.ap.teacup.com/applet/[username]/postmsgrpc
EGOISTブログXMLRPCHTMLhttp://[blogid].ebsystems.jp/xmlrpc.php
自分のブログサイトの先頭に付いているblogid
FC2ブログXMLRPCHTMLhttp://blog.fc2.com/xmlrpc.php
JUGEMXMLRPCHTMLhttp://[blogid].jugem.jp/admin/xmlrpc.php
JustBlogAtompubHTMLhttp://app.justblog.jp/t/atom/weblog/blog_id=[blogid]
Livedoor BlogAtompubHTMLhttp://cms.blog.livedoor.com/atom/blog_id=[blogid]
MSN SpaceXMLRPCHTMLhttps://storage.msn.com/storageservice/MetaWeblog.rpc
NetLaputaXMLRPCHTMLhttp://blog.netlaputa.ne.jp/rpc/mt-xmlrpc.cgi
News HandlerXMLRPCHTMLhttp://blog.nettribe.org/xmlrpc.php
SeesaaブログXMLRPCHTMLhttp://blog.seesaa.jp/rpc/
WordPressXMLRPCHTMLhttp://faq.wordpress.com/xmlrpc.php
Yahoo!ブログXMLRPCHTMLhttp://api.my.yahoo.co.jp/RPC2
BloggerAtompubHTMLhttp://[blogid].blogspot.com/feeds/posts/default
BloggerXMLRPCHTMLhttp://blog.goo.ne.jp/xmlrpc.php
pwBlogXMLRPCHTMLhttp://www.pwblog.com/xmlrpc
VoxAtompubHTMLhttp://[blogid].vox.com/library/posts/atom.xml
はてなブックマークAtomPubTEXThttp://b.hatena.ne.jp/[username]/atom/
はてなダイアリーAtompubはてな記法http://d.hatena.ne.jp/[blogid]/edit
アメーバブログAtompubHTMLhttp://ameblo.jp/servlet/_atom/blog/[blogid]
ココログXMLRPCHTMLhttp://app.f.cocolog-nifty.com/t/api
ドリコムXMLRPCHTMLhttp://blog.drecom.jp/api/xmlrpc
ブログ人XMLRPCHTMLhttp://app.blog.ocn.ne.jp/t/api/
PLAYLOGXMLRPCWikihttp://playlog.jp/_atom/blog/[blogid]
ちなみに、アメーバブログはWSSEヘッダを作成する際、パスワードをMD5した値でSHA1/NONCEを作成する必要があります。
これは正直言ってしまうと、バグとしか思えません...汗
Atompubの場合、実際には上記エントリポイントを直接参照するのではなく、ブログページからオートディスカバリする事が推奨されます。
例えば、私のVoxのサイトのHTMLを参照してみると
<link rel="EditURI" type="application/rsd+xml" href="http://mattn.vox.com/rsd.xml" title="RSD" />
というヘッダがあるのが分かるかと思います。
次にこのhrefを参照すると
<?xml version="1.0"?>
<rsd version="1.0" xmlns="http://archipelago.phrasewise.com/rsd">
    <service>
        <engineName>Vox</engineName>
        <engineLink>http://www.vox.com/</engineLink>
        <homePageLink>http://mattn.vox.com/</homePageLink>
        <apis>
            <api name="Atom" preferred="true"
                apiLink="http://www.vox.com/services/atom" />
        </apis>
    </service>
</rsd>
このようなXMLが戻ります。ここまでは認証無しに参照出来ます。
このapiノードに記述されているapiLinkにX-WSSEヘッダを付けて要求すると、以下の様な登録/編集用URIが記述されたXMLが返されます。
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://purl.org/atom/ns#">
  <link rel="service.post" href="http://www.vox.com/services/atom/svc=post/collection_id=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" title="matt'n roll" type="application/x.atom+xml"/>
  <link rel="alternate" href="http://mattn.vox.com/" title="matt'n roll" type="text/html"/>
  <link rel="service.feed" href="http://www.vox.com/services/atom/svc=asset/XXXXXXXXXXXXXXXXXX" title="matt'n roll" type="application/atom+xml"/>
  <link rel="service.upload" href="http://www.vox.com/services/atom/svc=asset" title="matt'n roll" type="application/atom+xml"/>
  <link rel="replies" href="http://www.vox.com/services/atom/svc=asset/XXXXXXXXXXXXXXXXXX/type=Comment" title="matt'n roll" type="application/atom+xml"/>
</feed>
service.feedにはAtomフィードURIが、service.postは新規エントリポスト用のURIが格納されています。
Voxの場合は画像ファイル等のアップロード(service.upload)に対応しているようですね。
また、service.feedから取得したフィード自身にはrel属性とtype属性で指定されたlink要素も付与されていますから
<entry xmlns:default="http://www.sixapart.com/ns/atom/privacy" xmlns:default1="http://www.w3.org/1999/xhtml">
  <id>tag:vox.com,2007-11-03:asset-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX</id>
  <title>スケスケ</title>
  <published>2007-11-03T09:25:46Z</published>
  <updated>2007-11-03T09:25:46Z</updated>
  <link rel="alternate" href="http://mattn.vox.com/library/post/%E3%82%B9%E3%82%B1%E3%82%B9%E3%82%B1.html" title="スケスケ" type="text/html"/>
  <privacy xmlns="http://www.sixapart.com/ns/atom/privacy">
    <allow policy="http://www.sixapart.com/ns/atom/permissions#read" name="Everyone" ref="http://www.sixapart.com/ns/atom/groups#everyone"/>
  </privacy>
  <link rel="alternate" href="http://www.vox.com/services/atom/svc=asset/XXXXXXXXXXXXXXXXXX/XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" type="application/atom+xml"/>
  <link rel="replies" href="http://www.vox.com/services/atom/svc=comment/xid=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" type="application/atom+xml"/>
  <author>
    <name>mattn</name>
    <uri>http://mattn.vox.com/</uri>
  </author>
  <category term="携帯から" label="携帯から"/>
  <content xmlns:default="http://www.w3.org/1999/xhtml" type="xhtml">
    <div xmlns="http://www.w3.org/1999/xhtml">
      <p>今日、とある遊園地の横を通り過ぎた時に嫁が「この遊園地スケスケやなぁ」って言って来た。少し考えた後「うん」と答えた。どうやら嫁は「この遊園地スカスカやなぁ」と言いたかったらしい。ところで「スケスケ遊園地」って、ちょっとエッチ…</p>
    </div>
  </content>
</entry>
このエントリフィードの、type="application/atom+xml"であるlink要素のhrefに対してPOST(PUT)すれば更新、DELETEすれば削除となります。
POST時に送信する文書は、feedからentryのみを抜き取った、丁度上のようなXMLを送信する事になります。
前回、今回とブログサービスが提供するAPIについてお話して来ましたが、最近はAtomPubの方が活発だったりします。
XMLRPCの場合は特に決められたXMLネームスペースが存在していない為、貧祖なXMLパーサでもクライアントを実装でき、それ程敷居は高くないかと思います。
※但し、XMLRPCのパラメータは各サービスによって型が統一されていない場合があります。汎用的に作るのならば苦労するかもしれません。

それに比べAtomPubでは仕様が結構キッチリと決められている為、各サービス毎に異なる仕様で苦しめられる事はあまりありませんが、XMLネームスペース/スキーマを意識してXMLを操作しなければならなくなります。
幾分AtomPubを使ったクライアント実装の方が敷居が高い気もします。
※参考にするならばVoxが良いと思います。

今後、ブログAPIの主流としては、AtomPubがリードして行くと私は思っていますが、クライアントアプリがXMLRPCもAtomPubも対応しなければならない時代は、早く消え去った方が良いのでは?と切に願うばかりです。

ちなみに...
私のサイトではblosxomというブログツールを使用しています。blosxomをXMLRPCで操作しようというライブラリは既に存在しており私も使ってはいるのですが、AtomPubで実装した物はありませんでした。
昨日からですが、少しずつ作り始める事にしました。
ある程度出来上がったらCodeReposに上げる予定です。

追記
id:teahutさんから、ご指摘頂きました。
確かにAtomPub(app)という点で、Voxは参考にならないかもしれません。
app要素の入った新しいAtomPubについては、こちらに仕様書の日本語訳があります。
Posted at 13:37 in web
Tagged as: API, Atom, XMLRPC
Bookmarks: add to hatena add to hatena | add to delicious.com | add to livedoor.clip add to livedoor.clip