はてなブログAtomPub – Hatena Developer Center

はてなブログAtomPub

はてなブログ AtomPub を利用したプログラムの例

Perlを用いた例 (WSSE認証)

CPANモジュールのXML::Atom::ClientはAtomPubクライアントを実装するための、WSSE認証やリクエスト、レスポンスに必要なXML文書の組み立てなどを抽象化したモジュールです。

XML::Atom::Clientを用いて、はてなブログにエントリを投稿するサンプルコードは以下です。

#!/usr/bin/env perl

use strict

;

use warnings

;

use utf8

;

use

XML::Atom::Entry;

use

XML::Atom::Client;

my

$username

=

shift

or

die

'need username'

;

my

$blog_domain

=

shift

or

die

'need blog_domain'

;

my

$api_key

=

shift

;

my

$PostURI

=

"https://blog.hatena.ne.jp/

$username

/

$blog_domain

/atom/entry"

;

my

$client

= XML::Atom::Client->

new

;

$client

->username(

$username

);

$client

->password(

$api_key

);

my

$entry

= XML::Atom::Entry->

new

;

$entry

->title(

'テストエントリだよー'

);

my

$content

=

"

# マークダウンも書けますよ

- こんな

- ふうに

- ね"

;

$entry

->content(

$content

);

my

$EditURI

=

$client

->createEntry(

$PostURI

,

$entry

)

or

die

$client

->errstr;

print

$EditURI

;

XML::Atom::Client はWSSE認証を抽象化しているため、username/blog_domain/passwordメソッドでそれぞれをセットするだけで認証を通過できます。また、XML文書の組み立てはXML::Atom::Entryインスタンスを生成して行い、それを最後にXML::Atom::Clientインスタンスに渡せば完了です。

このスクリプトはコマンドラインから、

$ perl atompost.pl はてなID ブログドメイン APIキー

として実行できます。

Perl を用いた例 (OAuth認証)

上記の XML::Atom::Client はOAuth認証には対応していません。ここでは、フレームワークとして Mojolicious::Lite、OAuthライブラリとして OAuth::Lite を利用したサンプルコードを紹介します。

以下のスクリプトを oauth-sample.plとして保存して、以下のように実行します。

$ 

CONSUMER_KEY

=

'

<YOUR CONSUMER KEY>

'

\\

CONSUMER_SECRET

=

'

<YOUR CONSUMER SECRET>

'

\\

API_URL

=

'

<YOUR BLOG API ROOT ENDPOINT>

'

\\

perl oauth-sample.pl

daemon

<YOUR CONSUMER KEY>, <YOUR CONSUMER SECRET> には、自分のOAuthアプリケーションの consumer key, consumer secretを設定してください。<YOUR BLOG API ROOT ENDPOINT> には、サービス文章のURIを設定してください。特に、はてなブログ AtomPub APIは、はてなのOAuth認証における、read_private, write_privateの両方を要求することに注意してください。詳しくは、認証についての章を参照してください。

スクリプトが起動したのち、http://localhost:3000へアクセスしてください。

#!/usr/bin/env perl

use strict

;

use warnings

;

use utf8

;

use

Mojolicious::Lite;

use

OAuth::Lite::Consumer;

use

OAuth::Lite::Token;

use

XML::Atom::Feed;

use

Encode;

my

$consumer_key

=

$ENV

{CONSUMER_KEY};

my

$consumer_secret

=

$ENV

{CONSUMER_SECRET};

my

$api_url

=

$ENV

{BLOG_API_ROOT_ENDPOINT};

if

(!(

$consumer_key

&&

$consumer_secret

&&

$api_url

)) {

print

STDERR

<<"ENDUSAGE";

Usage:

CONSUMER_KEY=<YOUR CONSUMER KEY>

\\

CONSUMER_SECRET=<YOUR CONSUMER SECRET>

\\

API_URL=<BLOG API ROOT ENDPOINT>

\\

plackup

$0

ENDUSAGE

exit

1

; }

my

$consumer

= OAuth::Lite::Consumer->

new

(

consumer_key

=>

$consumer_key

,

consumer_secret

=>

$consumer_secret

,

site

=>

q{https://www.hatena.com}

,

request_token_path

=>

q{/oauth/initiate}

,

access_token_path

=>

q{/oauth/token}

,

authorize_path

=>

q{https://www.hatena.ne.jp/oauth/authorize}

, ); get

'/'

=>

sub

{

my

$self

=

shift

;

$self

->stash(

access_token

=>

$self

->session(

'access_token'

) ||

''

); } =>

'root'

; get

'/oauth'

=>

sub

{

my

$self

=

shift

;

$self

->stash(

consumer

=>

$consumer

);

my

$request_token

=

$consumer

->get_request_token(

callback_url

=>

q{http://localhost:3000/callback}

,

scope

=>

'read_private,write_private'

, )

or

die

$consumer

->errstr;

$self

->session(

request_token

=>

$request_token

->as_encoded);

$self

->redirect_to(

$consumer

->url_to_authorize(

token

=>

$request_token

, ) ); }; get

'/callback'

=>

sub

{

my

$self

=

shift

;

$self

->stash(

consumer

=>

$consumer

);

my

$verifier

=

$self

->param(

'oauth_verifier'

);

my

$request_token

= OAuth::Lite::Token->from_encoded(

$self

->session(

'request_token'

));

my

$access_token

=

$consumer

->get_access_token(

token

=>

$request_token

,

verifier

=>

$verifier

, )

or

die

$consumer

->errstr;

$self

->session(

request_token

=>

undef

);

$self

->session(

access_token

=>

$access_token

->as_encoded);

$self

->redirect_to(

'/'

); } =>

'callback'

; get

'/list'

=>

sub

{

my

$self

=

shift

;

$self

->stash(

consumer

=>

$consumer

);

my

$access_token

= OAuth::Lite::Token->from_encoded(

$self

->session(

'access_token'

))

or

return

;

my

$res

=

$consumer

->request(

method

=>

'GET'

,

url

=>

$api_url

.

'/entry'

,

token

=>

$access_token

,

params

=> {}, )

or

die

$consumer

->errstr;

my

$xml

=

$res

->content;

my

$entries

= [

map

{

my

(

$link

) =

map

{

$_

->href }

grep

{

$_

->rel

eq

'alternate'

}

$_

->

link

; +{

title

=> ( decode_utf8(

$_

->title) ||

''

),

link

=> (

$link

||

''

) } } XML::Atom::Feed->

new

(

\$xml

)->entries ];

$self

->stash(

entries

=>

$entries

); } =>

'list'

; app->start;

Ruby を用いた例

Ruby gemsで公開されているatomutilというモジュールもXML::Atom::Clientと同様に、AtomPubクライアントを実装するための、WSSE認証やリクエスト、レスポンスに必要なXML文書の組み立てなどを抽象化したモジュールです。

atomutilを用いて、はてなブログにエントリを投稿するサンプルコードは以下です。

#!/usr/bin/env ruby

require

'

atomutil

'

USERNAME

=

ARGV

[

0

]

BLOG_DOMAIN

=

ARGV

[

1

]

API_KEY

=

ARGV

[

2

]

POST_URI

=

"

https://blog.hatena.ne.jp/

#{USERNAME}

/

#{BLOG_DOMAIN}

/atom/entry

"

auth =

Atompub

::

Auth

::

Wsse

.new( username:

USERNAME

, password:

API_KEY

) client =

Atompub

::

Client

.new(auth: auth) entry =

Atom

::

Entry

.new( title:

"

テストエントリ

"

.encode(

'

BINARY

'

,

'

BINARY

'

), content: <<

'ENDOFCONENT'

.encode(

'

BINARY

'

,

'

BINARY

'

))

*もちろん

- はてな記法も

- 書けます

ENDOFCONENT

p client.create_entry(

POST_URI

, entry);

このスクリプトはコマンドラインから、

$ ruby atompost.rb はてなID ブログドメイン  APIキー

として実行できます。

Scala を用いた例

ここではJavaのモジュールであるApache Abderaを用いた記事の投稿を、Scalaで実装した例を紹介します。

はてなブログにエントリを投稿するサンプルコードは以下の通りです。

import

java.util.Date

import

org.apache.abdera.Abdera

import

org.apache.abdera.protocol.client.AbderaClient

import

org.apache.abdera.ext.wsse.WSSEAuthScheme;

import

org.apache.commons.httpclient.UsernamePasswordCredentials;

object

AtomPubEntryPost {

def

main(args:

Array

[

String

]): Unit = {

val

username =

""

;

val

blogDomain =

""

;

val

apiKey =

""

;

val

abdera =

new

Abdera

val

abderaClient =

new

AbderaClient(abdera) WSSEAuthScheme.register(abderaClient,

true

); abderaClient.addCredentials(

"https://blog.hatena.ne.jp"

,

null

,

"WSSE"

,

new

UsernamePasswordCredentials(username, apiKey));

val

factory = abdera.getFactory

val

entry = factory.newEntry entry.setTitle(

"タイトル"

) entry.setUpdated(

new

Date()) entry.addAuthor(username) entry.setContent(

"本文"

)

val

response = abderaClient.post(s

"https://blog.hatena.ne.jp/$username/$blogDomain/atom/entry"

, entry) println(

"STATUS CODE : "

+ response.getStatus) } }

依存モジュールは、sbtを用いた場合には、以下のような記述を加えてください。

libraryDependencies ++= Seq (
  

"org.apache.abdera"

%

"abdera-bundle"

%

"1.1.3"

, )