Web APIの次世代標準プロトコル「Atom Publishing Protocol」

第2回AtomPubにおけるリソース操作 - CRUD

おさらい

それでは、Atomの詳細を解説していきたいとおもいます。

前回Atomの基本部分は二つの仕様から構成されていることをご紹介しました。

一つはAtomフィードと呼ばれるサーバから配信されるデータフォーマットに関する仕様で、二つめはサーバへコンテンツを登録したりそのデータを編集したりするためのプロトコル仕様です。

前者はAtom Syndication Format、後者はAtom Publishing Protocolというのが正式名称です。本稿では、それぞれAtomフィード、AtomPubという呼び方を使うことにします。

AtomフィードはRSSフィードがあるにも関わらず、新しく作られました。

これについては、RSSを使うべきだったという否定的な意見もありますし、RSSではできないことがあるからこそ作ったという肯定的な意見もあります。

いずれにせよAtomフィードは、RSSフィードとともに使われていくことになるでしょう。それぞれのフィードはよく考えられた仕様であり、シンプルにできていますので、両方に対応することはさほど難しくありません。並存することのデメリットについて、あまり目くじらをたてる必要もないでしょう。

また、よくRSSとの違いを聞かれますが、RSSはAtomのようにサーバ側に向かう方向の仕様がありません。サーバからの情報配信に利用することはできても、クライアントからサーバへWebリソースを登録・更新・削除する際にRSSを利用することはできません。

Atomフィード

本稿ではAtomPubを中心に説明する予定ですので、Atomフィードのフォーマットについてはあまり深く説明をしません。しかし、AtomPubでもこのフォーマットを利用しますので、かいつまんで紹介します。既にご存知の方は、読み飛ばして「AtomPub:Webリソースの操作」からお読みください。

Atomフィードは情報のリストであり、XML文書で表現されます。フィードはエントリと呼ばれる一つ一つの情報から構成されています。それぞれentry要素、feed要素で表現されます。RSSをご存知の方は、item要素がentry要素に相当し、channel要素がfeed要素に相当するとお考えください。

フィードは後で説明するコレクションのXML表現に相当し、エントリはメンバのXML表現に相当します。

フィードフォーマット

次に示すコードはAtomフィードの一例です。フィード自身のタイトルや作者の情報、そしてidが記述されています。このidはフィード固有のもので、何らかの法則で割り振られます。

フィードは情報のリストですので、0個以上のentry要素を子要素として持つことができます。以下の例では一つのエントリがリストアップされています。

Atomフィードの例(RFC4287より抜粋)
<feed xmlns="http://www.w3.org/2005/Atom">

    <title>Example Feed</title>
    <link href="http://example.org/"/>
    <updated>2003-12-13T18:30:02Z</updated>
    <author>
        <name>John Doe</name>
    </author>
    <id>urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6</id>

    <entry>
        <title>Atom-Powered Robots Run Amok</title>
        <link href="http://example.org/2003/12/13/atom03"/>
        <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
        <updated>2003-12-13T18:30:02Z</updated>
        <summary>Some text.</summary>
    </entry>

</feed>

表1はatom:feed(接頭辞はRFC 4287で規定されている名前空間 http://www.w3.org/2005/Atom の意味で使用しています)に出現できる主な子要素の一覧です。子要素の順番については意味がないと定義されていますので出現順序は任意となっています。

表1 atom:feedに出現できる子要素(表中の「出現ルール」は、*:0個以上、?:1個または0個、1:1個出現するという意味で使用している)
要素出現ルール内容
atom:author*[注1]著者情報
atom:category*カテゴリを表す
atom:contributor*貢献した人
atom:generator?生成したソフトウエア等の情報
atom:icon?このフィードに対するアイコン
atom:id1フィードを一意に識別する識別子
atom:link*[注2]web リソースに対するリンク(意味が与えられる場合があります)
atom:logo?フィードに対するロゴイメージ
atom:rights?権利情報
atom:subtitle?人間が理解できる説明または副題
atom:title1人間が理解できるタイトル
atom:updated1(重要でない更新を除く)最新更新時刻
atom:entry* 

基本的には表中の出現ルールに従いますが、以下の条件がつきます。

  • [注1]子要素のatom:entryが全くatom:authorを含まない場合は1個以上のatom:authorが出現する必要があります。
  • [注2]自分自身のフィードを取得するためのURIをrel属性値がselfである要素として一つだけ含むべきです。
  • [注2]rel属性値がalternateである要素において、type属性値とhreflang属性値の組み合わせが同じような要素を複数出現させることはできません。

エントリフォーマット

次に示すコードはAtomエントリの一例です。エントリのメタ情報とともにcontent要素内にその情報が記載されています。フィードと同様、エントリ固有のidがあります。更新された時刻についてはupdated要素で知ることができます。

Atomエントリの例
<entry xmlns="http://www.w3.org/2005/Atom">
  <title>今日は紅葉を見に行きました</title>
  <link rel="alternate" type="image/jpeg" href="http://example.com/2007/11/10/fall.html"/>
  <link rel="enclosure" type="image/jpeg" length="133731" href="http://example.com/images/20071110fall.jpg"/>
  <id>tag:example.com,2007:1.2397</id>
  <updated>2007-11-11T12:29:29Z</updated>
  <published>2007-11-10T08:29:29-04:00</published>
  <author>
    <name>朝倉 浩志</name>
    <uri>http://example.com/</uri>
    <email>hirosh-a@example.com</email>
  </author>
  <content>
    今日は秋ということで紅葉を見に行っていました。なかなか綺麗に写真
もとれたと思います。
  </content>
</entry>

表2はatom:entryに出現できる主な子要素の一覧です。子要素の順番についてはatom:feedと同じく意味がないと定義されていますので出現順序は任意となっています。

表2 atom:entryに出現できる子要素(表中の「出現ルール」は、*:0個以上、?:1個または0個、1:1個出現するという意味で使用している)
要素出現ルール内容
atom:author*[注1]著者情報
atom:category*カテゴリを表す
atom:content?エントリの内容を表す(リンクを使って表現することも可能)
atom:contributor*貢献した人
atom:id1エントリを一意に識別する識別子
atom:link*
[注2]
webリソースに対するリンク(意味が与えられる場合があります)
atom:published?リソースが作成されたもしくは利用できるようになった日付時刻
atom:rights?人間が可読な権利情報
atom:source?エントリを複製する際に元のメタ情報を格納できる
atom:summary?[注3]エントリの要約
atom:title1エントリのタイトル
atom:updated1変更された日付時刻
app:edited?エントリが編集された最終時刻

※接頭辞appは、名前空間http://www.w3.org/2007/appの意味で使用しています。

  • [注1]一つ以上のatom:author要素を含む必要があります。ただしatom:author要素を含むatom:source要素を含む場合はこの限りではありません。また、フィード文書に出現しているエントリの場合で、そのatom:feed要素自体がatom:author要素を含む場合は、この限りではありません(要するにどこかでatom:authorが出てきていれば良いということです⁠⁠。
  • [注2]atom:content要素を含まない場合は、rel="alternate"であるatom:link要素が少なくとも一つは必要です。
  • [注2]rel="alternate"であるatom:link要素において、type属性値とhreflang属性値の組み合わせが同じような要素を複数出現させることはできません。
  • [注3]atom:contentがsrc属性を含んで外部のリソースを参照している場合やatom:contentの内容がbase64でエンコードされている場合などは、content自体がこの要素内で分かりませんので、atom:summary要素が必須と規定されています。

atom:link要素

ここで、フィードとエントリ内で使われるatom:link要素について説明しておきます。atom:link要素は、entry要素またはfeed要素内からwebリソースへの参照を示すために使われます。この要素はrel属性をもつことができ、リンクの関係性を表すことができます。Atomではこれらをうまく使うことにより表現をより豊かにしています。

また、atom:content要素でもsrc属性を使ってリンクを表現することが可能となっており、rel="alternate"と近い意味で使われることがありますが、今回は紙面の都合上詳しくは触れません。

表3 atom:link要素における、rel属性の意味
rel属性値意味
rel属性が出現しないrel="alternate"と解釈する
alternateそのエントリ、フィードの別バージョンを示します(よく使われるのは,そのエントリ、フィードを Web ブラウザで見られるページを示します⁠⁠。
relatedそのエントリ、フィードで説明されるリソースに関連するリソースを示します(具体的には関連するものであれば何でも良いようです⁠⁠。
selfそのエントリ、フィードと等価なリソースを示します。
enclosure関連するリソースを指し示しますが、サイズが大きい可能性があって特別な処理を必要とすることを意味します(具体的にはそのリソースに含まれる画像などが対象となるようです⁠⁠。
via情報源のリソースを示します。
editメンバリソースを操作するためのURIを示します(後述⁠⁠。
edit-mediaメディアリソースを操作するためのURIを示します(後述⁠⁠。

AtomPub:Webリソースの操作

リソースのCRUD操作

さて、いよいよAtompubにおけるWebリソースの操作をみていくことにしましょう。

前回説明したように、AtomPubのデータモデルは簡単に言うと、⁠コレクション」と呼ばれるWebリソースの集合と、その中に入る「メンバリソース」から構成されています。一般的にはサーバ側に複数のコレクションがあり、それぞれのコレクションにはURI[1]が割り当てられるでしょう。また、コレクションの中にあるメンバリソースの一つ一つにもURIが割り当てられます。コレクションおよびメンバリソースを操作する際には対応するURIに対してHTTPメソッドを適用することになります。

次からメンバリソースの取得・追加・更新・削除のそれぞれについて解説します。これらの操作は、Create, Read, Update, Deleteのそれぞれの頭文字をとってCRUDと呼ばれます。

一覧の取得

メンバリソースの一覧を取得するためにはコレクションURIに対してGETメソッドを適用します。メンバリソース(のうち後述するエントリリソースのみ)がリストとなって帰ってきます。これをフィード文書と呼びます。

図1 コレクションからメンバリソースの一覧を取得する
図1 コレクションからメンバリソースの一覧を取得する
取得

メンバリソースを取得するためにはメンバURIに対してGETメソッドを適用します。指定したメンバリソースの内容がエントリとなって帰ってきます。これをエントリ文書と呼びます。

図2 コレクションからメンバリソースを取得する
図2 コレクションからメンバリソースを取得する
追加

メンバリソースを追加するためにはコレクションURIに対してPOSTメソッドを適用します。このとき追加したい内容のエントリ文書を送ります。その内容で新しいメンバリソースが生成されます。

図3 コレクションにメンバリソースを追加する
図3 コレクションにメンバリソースを追加する
更新

メンバリソースを更新するためにはメンバURIに対してPUTメソッドを適用します。このとき更新したい内容のエントリ文書をつけて送ります。

図4 メンバリソースを更新する
図4 メンバリソースを更新する
削除

メンバリソースを削除するためにはメンバURIに対してDELETEメソッドを適用します。

図5 メンバリソースを削除する
図5 メンバリソースを削除する

メディアリソースの操作

メンバリソースの中でもXML形式のエントリで表現できないようなデータ(典型的な例は画像データ)はメディアリソースと呼ばれます表4⁠。

表4 メンバリソースの種類
メンバリソースの種類内容
エントリリソースAtom Entryで表現されるデータ
メディアリソース(通常は)Atom Entryで表現できないデータ

メディアリソースを扱う場合、リソースをエントリとして表現するために「メディアリンクエントリ」と呼ばれるエントリリソースが用意されます。

そしてこのエントリリソースからはメディアリソースへのリンクが張られます(atom:linkエントリで表現され、メディアリンクエントリ内に保持されます⁠⁠。

以下にCRUD操作を紹介しますが、いずれも図中の点線でかかれているリソースがメディアリソース、実線のリソースがエントリリソース(メディアリンクエントリ⁠⁠、伸びている矢印はメディアリンクエントリ内にあるatom:link要素を表現しています。

取得

メディアリソースをGETした場合は、エントリ文書以外のメディアタイプで実際のリソースを取得することができるでしょう。

図6 メディアリソースを取得する
図6 メディアリソースを取得する
追加

コレクションに対してメディアリソースをPOSTした場合は、メディアリソースおよびメンバエントリ(メディアリンクエントリ)が作成されます。メディアリンクエントリはメディアリソースのメタ情報を表現するメンバリソースとなります。

図7 メディアリソースを追加する
図7 メディアリソースを追加する
更新

メディアリソースを更新したい場合は、メディアリソースのURIを、メタ情報を更新したい場合は、メディアリンクエントリのURIに対してPUTを適用します。

図8 メディアリソースを更新する
図8 メディアリソースを更新する
図9 メディアリンクエントリを更新する
図9 メディアリンクエントリを更新する
削除

エントリリソース(メディアリンクエントリ)を消去した場合は、対応するメディアリソースも削除されるべきであると規定されています。このため多くのサーバではメディアリソースも同時に削除されてしまうことになるでしょう。図中の /member/1 を削除した場合は同時に /member/2 も削除されてしまうでしょう。

また、メディアリソースを削除した場合は、メディアリソースが削除されます。このとき対応するエントリリソース(メディアリンクエントリ)も多くの場合、削除されるでしょう(厳密に言えばこの場合も実装依存になっています⁠⁠。

図10 メディアリンクエントリを削除する
図10 メディアリンクエントリを削除する
図11 メディアリソースを削除する
図11 メディアリソースを削除する

サービス文書

それではどのように、Webリソースを操作するURIを取得するのでしょうか?

それを解決してくれるのがサービス文書です。サービス文書を取得することがクライアントにとってAtomサーバの提供しているサービスを知ることができる唯一の方法です。

通常、クライアント側にはサービス文書を取得するためのURI(サービス文書URI)をなんらかの方法によって伝えます。このURIをGETすることによってクライアント側は様々なURIを知ることになります。

では実際にどのようなものかみてみましょう。

サービス文書の例(RFC 4287より抜粋)
<?xml version="1.0" encoding='utf-8'?>
<service xmlns="http://www.w3.org/2007/app" xmlns:atom="http://www.w3.org/2005/Atom">
  <workspace>
    <atom:title>Main Site</atom:title>
    <collection href="http://example.org/blog/main">
      <atom:title>My Blog Entries</atom:title>
      <categories href="http://example.com/cats/forMain.cats" />
    </collection>
    <collection href="http://example.org/blog/pic">
      <atom:title>Pictures</atom:title>
      <accept>image/png</accept>
    </collection>
  </workspace>
</service>

サービス文書は、ルート要素がapp:service要素である文書です。

app:service要素は一つ以上のapp:workspace要素から構成されています。

app:workspace要素には、atom:title要素が必ず一つ含まれています。またapp:collection要素が0個以上含まれています。workspaceについてはcollectionを束ねるものとしか定義されておらず、あまり意味はありません。ここではcollectionに注目していきます。

app:collection要素のhref属性は、そのコレクションのURIを表現しています。

ここに記載されているURIに対してPOSTやGETができます。

app:collection要素はapp:accept要素を持つことができます。app:accept要素は、そのコレクションがPOSTを受け付けることができるファイルタイプを示しており、RFC 2616で定義されているmedia-rangeの内容を指定できます。

この要素が省略された場合はAtomエントリ文書のみが受け付け可能と解釈されるべきであると規定されています。また、空要素(<accept></accept>)のみが現れている場合は、何も受け付けられないと解釈するべきであると規定されています。

全てのファイル形式が受け付け可能な場合は<accept>*/*</accept>という表現が利用できます。

上記の例では、My Blog Entriesコレクションに対しては、エントリ文書を登録することができます。また、Picturesというコレクションに対してはPNG形式の画像ファイルのみが登録できると解釈することができます。

さて、次回はこのサービス文書を手がかりに、リソースへのCRUD操作を追っていくことにしましょう。

おすすめ記事

記事・ニュース一覧