9 月 06 2008

Top / OpenSocial / RESTful API Specification

このページはRESTful API Specification - OpenSocial - Google Codeの翻訳です

2008年5月27日版(リビジョン1031)

RESTful APIはすべてのOpenSocial 0.8に対応したクライアントおよびサーバーに共通のプロトコルとして提供されます。これは2007年11月に発表されたGDataベースのOpenSocial data APIを置き換えるものです。

概要

このAPIはクライアントがウェブページ上のガジェット外部にあるOpenSocialコンテナサーバーとやり取りするための、言語にもプラットフォームにも中立なプロトコルを定義します。プロトコルとしては、どんな言語でも、どんなプラットフォームでも比較的容易に実装可能なように作られています。この仕様は、ウェブページ上のガジェットから、ユーザーデータの同期を行うサーバーまで、様々なクライアントから利用することができます。

このプロトコルは主に、リソースとそのオペレーションについて扱い、HTTPプロトコル上でサーバーから取得や更新を行う標準のHTTPメソッド(GET、POST、PUT、DELETE等)を定義します。

データ表現がひとつだけでは全てのクライアントに対して理想的とは言えません。このプロトコルでは各リソースにつき、JSON RFC4627、Atom/AtomPub RFC4287, RFC5023という2種類の表現方法を汎用的なマッピングルールに則って定義します。このマッピングルールにより、サーバーはプロトコルを2度実装することなく、1つのインターフェースを実装するだけで済ますことができます。

OpenSocialコンテナサーバーは拡張表現を定義して構いませんが、最低限ここで定義されているJSONとAtomを実装する必要があります。

このプロトコルではActivity、People、Group, AppDataのリソースとコレクション(リソースの集合)を定義します。ほとんどのオペレーションはこれらのリソースの取得(GET)、更新(PUT)、作成(POSTまたはPUT)、破棄(DELETE)から成ります。このプロトコルでは、HTTPリクエストの無駄なやり取りを減らすため、複数のリクエストをパイプライン上でバッチ処理する拡張機能を定義します。さらに、ひとつのフィールドを更新するためだけにリソースを大きく占有することを避けるため、部分更新の拡張機能を定義します。

OpenSocial API Backgroundでは下記で利用される背景となるコンセプトを解説しています。この文書ではOpenSocialに必要となる知識があることを前提としています。

データ表現

各リソースはJSON、Atom (XML)の2つの表現形式を取ります。すべてのデータはいずれの形式でも表現可能でなければなりませんが、汎用的なXMLやAtomからJSONへのマッピングは試みません。代わりに、内部データモデルを英語とJSONの文法を使って定義し、その後これとAtom/JSONのマッピングを定義します。

各リソースはエレメントの階層構造で表現されます。エレメントの順番は状況によって重要な場合と、重要でない場合があります。マッピングは内部階層をJSONデータ構造やAtomエントリに変換することで成り立ちます。

各データ型で許可されるフィールドは、OpenSocial 0.8 APIリファレンスに記載されたセットと同様です。フィールドの標準セットはRESTful APIとJS APIで共通です。

AtomとJSONフォーマットのマッピングルールを以下に示します。データ型によっては別のルールが追加される場合があります。

  • Atomフォーマットの全てのデータのデフォルトロケーションはatom:entry/atom:content/datatypeです。datatypeはルートノードで配信されるデータ型(<person>, <group>, <activity>, <appdata>)となります。
  • フィールド名はJavaScriptリファレンスと同様で、キャメルケース(例:'lastName')です。
  • 文字列はどちらのフォーマットでも文字列として表現されます。
  • 日付とタイムスタンプはAtomPub(RFC3339)フォーマットのdate-timeエレメントで表現されます。RFC4287の3.3章をご覧下さい。これらは"XSD Dates"としても知られています。誕生日のような年を除いた日付のみが必要とされる場合、年は0000と表現されなければなりません。
  • Enumは"display value"(ローカライズ、カスタマイズ可能な文字列)と"key"(キー)フィールドを持ったオブジェクトで表現されます。
  • 配列はJSONでは配列として表現され、XMLでは繰り返しフィールドとして表現されます。
  • サブオブジェクトはどちらのフォーマットでもサブエレメントとして表現されます。
  • フィールドはJSONフォーマットではルートオブジェクトとして配置されます。Atomフォーマットでは、デフォルトではatom:content/datatype(例:personデータならatom:content/person)下に配置されます。フィールドによっては標準Atomフィールドに従い、atom:entry下にエイリアスされます。全てのデータ型で3つの標準エイリアスが存在します。
    • atom:entry/atom:idは"id"フィールドをエイリアスします。JSONフォーマットのIDはOpenSocialでグローバルにユニークなIDです。これはコンテナのドメイン(example.org等)、コロン、英数字の文字列から成ります(例:example.org:78gh37261ddfdf)。AtomフォーマットではOpenSocial ID文字列に"urn:guid:"を前置することで、必要なURIデータ型に変換されます。これらのルールはグローバルなユニークさを保ちつつもRESTful APIとJS APIのIDマッピングを素直なものとします。
    • atom:entry/atom:updatedは最終更新日時(Activityの場合POSTED_TIME)または生成日時(他に適当な情報がない場合)のJSONフィールドをエイリアスします。
    • atom:entry/atom:publishedは生成日時(Activityの場合POSTED_TIME)のJSONフィールドをエイリアスします。

主なデータ型の例は下記に示します。各例では、JSON, Atomいずれのフォーマットも示しています。

コレクション

コレクションはデータ型がperson, group, activity, application dataに関わらず、複数のものを汎用的に扱う際に便利です。こちらもAtom形式とJSON形式が存在しています。Atom形式は、上記で定義したentry型のひとつから成るAtom feedです。デフォルトJSONコレクション形式は上記で定義したJSONオブジェクトのリストを持ったentryスロットを含むJSONオブジェクトです。コレクションではOpenSocial convensionsを使ってtotalResults(ページ上に出てこない総数), 現在のページのstartIndex, itemsPerPageをレポートします。

例:

  • application/json形式:
  • application/atom+xml形式:

注意: 標準の"next"リンクによって、フルランダムアクセスをサポートすることなくコレクションのページングを可能としています。コレクションはqueryパラメータに寄ってランダムアクセスが可能な場合もあります。

Activity streamコレクションはデフォルトでは、最新のActivityを先頭に、時系列に並びます。その他の並び順に関しては、クエリパラメータを使ってリクエストすることができます。

Person

Personはひとりの人物についてのソーシャルネットワークにまつわる情報を持ちます。同じレコードがコンタクト/フレンド/プロフィールで利用されます。

Personで利用可能なフィールド一覧はPerson Fields API docをご覧下さい。一般的なマッピングルールについてもご覧下さい。

最低限のPerson例:

  • application/json形式:
  • application/atom+xml形式:

注意: 一般的には、クライアントはすべてのフィールド、サブフィールドを持ったリソースの完全形、もしくは部分形を、クエリパラメータを使って要求することができます。詳細は下記をご覧下さい。

注意: atom:summaryエレメントは、contentエレメント内の構造化されたテキストまたはHTMLデータを表現する場所として適しています。atom:titleエレメントはname.unstructuredのようにエントリの短い名前をコピーしてくる場所として適しています。サーバーはこれら、もしくは他のフィールドを追加することができ、汎用アグリゲータやツールに対してフィードを有効活用することができます。

Group

OpenSocial GroupはPeopleに所有され、友人や友人との関係をカテゴライズしたり、タグ付けしたりするため使用されます。RESTful APIではユーザーが利用しているグループを問い合わせ可能にしています。Groupはコレクションとして返され、各Groupは表示名および、そのPersonによって所有されるGroupないでユニークなID、URLリンクを持ちます。

Groupの例:

  • application/json形式:
  • application/atom+xml形式:

GroupはGroupコレクション中にのみ表示され(下記参照)、Personごとに利用可能なグループのリストを取得するために使用されます。

Activity

OpenSocial Activityはタイムスタンプ付きでイベントの記録や通知を表し、より詳細な情報へのポインタを持っています。

Activityで利用可能なフィールド一覧はActivity Fields API docをご覧下さい。Activityは標準的なフィード処理コードとの互換性を最大限に保つため、広範囲なhoistingルールを持ちます。

  • atom:entry/atom:title は"title"をエイリアス
  • atom:entry/atom:summary は"body"をエイリアス
  • atom:entry/atom:link@rel="self" は"url"をエイリアス
  • atom:entry/atom:icon は"faviconUrl"をエイリアス
  • atom:entry/atom:source/atom:title は"streamTitle"をエイリアス
  • atom:entry/atom:source/atom:link@rel="self" は"streamUrl"をエイリアス
  • atom:entry/atom:generator/atom:uri は"appId"をエイリアス
  • atom:entry/atom:author/atom:uri は"userId"をエイリアス

最低限のActivity例:

  • application/json形式:
  • application/atom+xml形式:

AppData

AppDataはアプリケーションによって保存されたkey/valueペアです。AppDataの標準的な単位は、ユーザーのためにアプリケーションが保存したkey/valueペアの全てです。ただし、APIは異なるタイプのクエリもサポートしています(詳細は下記)。フィールドのサブセットを取得するには、セレクタfields=を利用します(詳細は下記)。

独立したAppDataの例

最初の例はあるアプリケーションとユーザーのkey/valueペアの集合を表しています:

  • application/json形式:
  • application/atom+xml形式:

AppDataコレクションの例

この例では、クライアントが複数のユーザーをまたがるデータコレクションをリクエストした場合を表しています。結果はデフォルトでは、ユーザーをデータにマッピングする特別なJSON形式のコレクションになります。クエリパラメータの指定により、汎用的な配列の形式で取得することも可能です。

  • application/jsonの配列形式
  • application/json形式(indexBy=id):
  • application/atom+xml形式:

コレクションのデフォルト形式は単純にJSON形式のレコードのリスト([ {...}, {....}, ...])です。特別なタイプである"index"はindexフィールドを使ったマッピングを行うことを意味します。queryパラメータに"indexBy"を指定することでリクエスト可能です(詳細は下記)。

各フィールド内のデータはJSONフォーマットが想定されており、そうでない場合でも変換はされません。

オペレーション

OpenSocialでは標準のHTTPメソッドが使用されます。GETは取得、PUTは更新、POSTは新規作成、DELETEは破棄を行います。POSTは特殊で、コレクションを扱い、コレクション中に新しいActivityやPerson、AppDataを新規作成し、AtomPub仕様に従い、生成したリソースのベースURLをLocation: headerに返します。

PUTやDELETEが使えないといった制限されたクライアント、もしくは制限されたクライアントの向こう側にいるクライアントは、PUTまたはDELETEをX-HTTP-Method-Override:ヘッダを追加してPOSTに変換する必要があります。

POST /... HTTP/1.1
...
X-HTTP-Method-Override: PUT

サーバーはPOSTとX-HTTP-Method-Overrideを実際の処理が送信されてきたものとして扱わなければなりません。

注意: OpenSocial0.8はクロスドメインのJSONP(コールバックを付加したGET)をサポートしませんが、サーバーによっては拡張としてサポートする場合があります。そういったサーバーでは適切なセキュリティと認証処理の実装が推奨されます。

リクエストの認証と認可のコンテキスト

各RESTfulのリクエストでは、通常認証/認可情報を必要とします。コンテキスト情報にはよく、リクエスト者のID(リクエストを発生させたユーザー)と、アプリケーションID(ユーザーのエージェントの役割を果たすアプリケーションかそれに類するもの)が含まれます。コンテナ特有の情報を含む場合もあります。

コンテナはOAuth Core 1.0のサービスプロバイダ(OAuthを介してアクセス可能なウェブアプリケーション)でなければなりません。コンテナはリクエストを確立するのに他の方法を提供することも可能です。また、コンテナはエンドユーザーが直接認証しないConsumer Request OAuth拡張をサポートしなければなりません。アプリケーションは明示的であれ、暗示的であれ、ユーザーが前もって処理に同意していることを保証しなければなりません。ただし、Consumer Request OAuthを利用するためには、コンテナが事前にアプリケーションによる信用の確立を必要としている場合があります。

コンシューマがユーザーIDを持ち、その特定のユーザー向けに処理を行うことを示したい場合は、OAuthの署名パラメータに、拡張としてxoauth_requestor_idパラメータを提示する必要があります。コンシューマは明示的であれ、暗示的であれ、ユーザーが事前にこの処理に同意した場合のみこれを提供しなければなりません。サービスプロバイダであるコンテナは、これらのパラメータを正当なものとして引き受ける、またはなかったものとして無視しなければなりません。

このようにリクエスト時は、通常リクエストを行うアプリケーション(コンシューマ)が、まれにリクエストしたいユーザーが、oauth_tokenを使って暗示的に、もしくはxoauth_requestor_idを使って明示的に含まれます。また、拡張や他のチャネル(Cookie, URLパラメータ, クライアントSSL証明書等)を使って、さらなる追加情報が含まれる場合もあります。なお、コンテナは公開情報に対してのリクエストであれば、認証/認可情報を持たないリクエストを受け付ける場合があります。認可情報がないリクエストの場合は、(例えばプロフィールの)公開できる情報のみを提供する場合があります。

RESTful URLに提供されるデータは、リクエスト者やアプリケーションごとに変化することに注意してください。そのため、与えられたURIリソースの意味は「現在のリクエスト者/アプリケーションの組み合わせに対して許可された情報のビュー」となります。認証が行われず情報が提供できない場合は、HTTP 401 Unauthorizedレスポンスがクライアントに対して返されなければなりません。また、 情報の一部のみが返される場合は、200ステータスと共に、別の認可コンテキストならば追加情報があることを示す標準OAuth WWW-Authenticate:ヘッダを付加して返されなければなりません。

ディスカバリー

コンテナはサポートしているコレクションと機能を宣言し、ディスカバリドキュメントを使ってそれを発見するためのテンプレートを提供します。クライアントはコンテナのURL(example.org等)を起点にディスカバリプロセスを開始します。処理の完全な流れはhttp://xrds-simple.net/core/1.0/をご覧ください。要約すると:

  1. クライアントが{container-url}に対してAccept: application/xrds+xmlヘッダを含んだGETリクエストを投げます。
  2. コンテナはディスカバリドキュメントを指すX-XRDS-Location:ヘッダか、ドキュメントそのものを返します。
  3. クライアントはX-XRDS-Location:ヘッダを受け取った場合、それに従いディスカバリドキュメントを取得します。

ディスカバリドキュメントはhttp://xrds-simple.net/core/1.0/で定義されている、OpenIDやOAuthディスカバリで利用されているのと同じフォーマットのXMLファイルです:

Serviceはコンテナが提供するそれぞれのサービスを告知します。各コンテナはサービスTypeをサポートしなければならず、他のものについてもサポートしている場合は、ディスカバリドキュメントに記述します。各ServiceはURI Template(1つの場合はURI)で定義されたリソースセットで構成されます。クライアントはURIを追跡し、必要なリソースで処理を行うためTemplateを展開します。(URI Templateの文法はhttp://www.ietf.org/internet-drafts/draft-gregorio-uritemplate-03.txtに文書化されています)

代理変数のセットは各サービスのTypeによって決まっています。主なサービスのTypeと代理変数の組み合わせは下記に記述します。OpenSocialへの拡張は、代理変数を文書化する必要があります。可読な文書の置き場は名前空間のURIが理想的であることに注意してください。

コアとなるOpenSocialサービスタイプ

この章ではすべてのOpenSocialコンテナがサポートしなければならないコアとなるType、そのXRDS形式と意味を定義します。特に指定されていない限り、すべてのHTTP処理はどのURIエンドポイントにも許可されています。許可されている処理を指定したいコンテナは、各リソースのHTTPヘッダにAllow:を提供する必要があります。

People

XRDS Type
http://ns.opensocial.org/people/0.8
guid
Peopleデータのオーナーを表す、コンテナを跨いでユニークなユーザーID、またはリクエスト者を表す@me
selector
下記のいずれか
  • グループで選択する(コレクション)場合は、ユーザー定義のローカルグループ名
  • guidのPersonレコードを選択する場合は@self
  • 全てのコンタクトを選択する(コレクション)場合は@all
  • コンタクトのサブセットである友達を選択する(コレクション)場合は@friends
pid
コレクションを選択している場合、その中からひとりのPersonレコードを取り出す。pid値はコレクションに対して相対的な場合がある。

People URIの例:

/people/{guid}/@all        ユーザー{guid}と繋がりのある全てのPeopleのコレクション
/people/{guid}/@friends    ユーザー{guid}と繋がりのある全ての友達のコレクション(@allのサブセット)
/people/{guid}/{groupid}   ユーザー{guid}と繋がりがあり、グループ{groupid}に含まれる全てのPeopleのコレクション
/people/{guid}/@all/{pid}  ユーザー{guid}と繋がりのある特定の人の個別のPersonレコード。ユーザー{guid}の視点で見た情報{pid}
/people/{guid}/@self       ユーザー{guid}のプロフィールレコード
/people/@me/@self          リクエスト者のプロフィールレコード

コンテナによっては下記のようなURI形式を使う場合があることに注意してください:

/people.cgi?guid={guid}&groupid={groupid}

これはXRDSディスカバリ文書が、パラメータを具体的なURIにマッピングできるようクライアントに適切に与えられていれば、正式なURIパターンとなります。

フレンドは適切なコレクション(例:/people/{guid}/@friends)にPOSTすることで追加することができます。コンテナは追加されたフレンドをコレクションに追加する前に2通りのオプトイン処理を必要とし、この場合、リクエストが受け入れられ、最終的に成功するかどうかは別として202 Acceptedレスポンスを返す必要があります。

Groups

XRDS Type
http://ns.opensocial.org/groups/0.8
guid
Peopleデータのオーナーを表すコンテナ上でユニークなユーザーID、またはリクエスト者を表す@me

Groups URIの例:

/groups/{guid}             ユーザー{guid}に関連付けられたグループのコレクション

Activities

XRDS Type
http://ns.opensocial.org/activities/0.8
guid
Peopleデータのオーナーを表すコンテナ上でユニークなユーザーID、またはリクエスト者を表す@me
selector
下記のいずれか
  • グループ内のActivityを選択する(コレクション)場合、ユーザー定義のローカルグループ名
  • guidユーザーのActivityを選択する(コレクション)場合は@self
  • 友達のActivityのみ選択する(コレクション)場合は@friends

Activity URIの例:

/activities/{guid}/@self               指定されたユーザーによって生成されたActivityのコレクション
/activities/{guid}/@friends            指定されたユーザーの友達のActivityコレクション
/activities/{guid}/{groupid}           指定されたユーザーのグループ{groupid}のActivityコレクション
/activities/{guid}/@self/{activityid}  個別のActivityリソース(通常コレクションから発見される)

AppData

XRDS Type
http://ns.opensocial.org/appdata/0.8
guid
Peopleデータのオーナーを表すコンテナ上でユニークなユーザーID、またはリクエスト者を表す@me
selector
下記のいずれか
  • グループ内のAppDataを選択する(コレクション)場合、ユーザー定義のローカルグループ名
  • guidユーザーのみのAppDataを選択する(コレクション)場合は@self
  • 友達のAppDataのみ選択する(コレクション)場合は@friends

Appdata URIの例:

/appdata/{guid}/@self/{appid}              ユーザー{guid}かつアプリ{appid}の全てのAppData
/appdata/{guid}/@friends/{appid}           ユーザー{guid}の友達かつアプリ{appid}の全てのAppData(読み込みのみ)
/appdata/{guid}/@self/{appid}?fields=count ユーザー{guid}かつアプリ{appid}のcountフィールド

標準クエリパラメータ

これらのクエリパラメータは上記URLいずれでも利用することができる追加のqueryパラメータです。startIndexとcountパラメータはOpenSearch仕様に基づき解釈されます。

format={format}                    好みの形式。atomまたはjson(デフォルト)
fields={field+}                    結果に含めたいフィールドのリスト
startIndex={startIndex}            ページコレクションのインデックス
count={count}                      ページコレクションのページサイズ
networkDistance={networkDistance}  @friendsなどのグループ系リクエストを、友達を辿って{networkDistance}分先の人までのリクエストに変更します。コンテナによってはサポートされません。 
indexBy={fieldname}                コレクションで、他のフィールドに対して名前の付けられたフィールド(ユニークなキーであること)を使ったJSONマッピングを返します。
orderBy={fieldname}                コレクションで、与えられたフィールドでソートされたエントリを返します。

セキュリティの考慮

コンテナは慎重にセキュリティについて考えるべきです。コンテナはOAuthのサポートが必須ですが、コンシューマごと、ユーザーごとに許可される処理を決めるに当たり、適切なポリシーを用いるべきです。OAuthの仕様に従えば、コンテナはoauth_tokenを取得するためコンシューマがどのようにしてユーザーをコンテナウェブページに誘導するかを文書化しなければなりません。これはユーザーが信用情報を入力する必要があるため、フィッシングが行われる可能性があることに注意してください。

コンテナは、OAuth自体が暗号化やメッセージ本文の内容確認を行わないため、重要なデータにはSSL接続をサポートするべきです。コンテナは利用されているクライアントの種類に従ってセキュリティに関する判断を行うべきです。例えば一般的なデスクトップクライアントの場合、各クライアントごとにインストールされたConsumer Secretを保護する効果的な方法がありません。ただ、パートナーとなるサービスとのコミュニケーションにおけるセキュリティは、そのサービスのセキュリティに関する手順の効率とは別問題です。コンテナはリスクを軽減するため、未知のクライアントからのリクエスト数を制限したり、登録制にしたりする場合があります。

コンテナはoauth_tokenをできるだけ狭くスコープするべきです(クライアントが読み込みのみ行う場合は書き込みさせないなど)。

同時処理制御 (オプション)

この機能により、複数のコンテナが互いのデータを上書きしないよう、コンテナとクライアントの協力が可能になります。これはETag(詳しくは[RFC5023]の9.5章を参照)を利用した標準HTTP/AtomPubの楽観的同時処理メカニズム(optimistic concurrency mechanism)を利用します。PUTのボディについても、データ形式に関わらず同じメカニズムが適用されます。

すべてのリソースはHTTP/AtomPub ETagベースの楽観的同時処理メカニズムを利用しています。サーバーは取得要求に応じてリソースにETagを発行、クライアントは変更処理が行われるとIf-Match:ヘッダにEtagを発行します。最初の取得と更新の間にリソースが変更されると、更新はコンフリクトを知らせるHTTPコードを返し、エラーとなります。
楽観的同時処理を行いたくないサーバーでは、応答時にETagを省いてください。

ディスカバリ

同時処理制御はリソースごとに利用可能です。更新可能なリソースが同時処理制御をサポートする場合、コンテナはクライアントに情報を提供すると同時に、リソースの現在の状態をエンコードしたETagを提供すべきです。リソースが楽観的な同時処理をサポートしない場合は、更新リクエストに対して403 Not Implementedエラーと共に、If-Match:ヘッダを含む応答を返さなければなりません。

楽観的な同時処理をサポートしないサーバーは、更新可能なリソースの応答時にETagを省略すべきです。クライアントはETagがなければ、楽観的同時処理が利用できないことを想定すべきです。

セマンティック

クライアントはETagを与えられると、後続の更新のIf-Match:ヘッダにそのETagを提供することができます。このセマンティクスは、クライアントは新しい表現と前回のETagを提供するということです。(The semantics are that the client can supply the new representation and the previous ETag; )サーバーは現在のリソースの状態を確認し、クライアントが提供したETagと一致する場合(他の更新は挟まれなかったことを意味する)は更新、一致しない場合は409 Conflictエラーと共に新しいETagを返します。クライアントはこれを受けて、衝突を解消するための適切な処理を行うか、処理を終了することができます。クライアントは上書きによる問題を意識することなく、いつでもPUTで新しい状態を上書きすることもできます。

部分更新がサポートされる場合(下記参照)、サーバーは基本となるリソース、または連続したPUTにより想定されるリソースへのETagを受け付けなければなりません。これは、ひとつのフィールドのみPUTしたい場合でも、GETでリソースの完全な表現を取得した際に受信したETagを与えることはルールに反しないことを意味します。ひとつのフィールドを上書きしたいだけの場合は、ETagを送りません。

バッチ処理 (オプション)

クライアントがサーバーに同じ処理を複数回行いたいけれども、HTTPリクエストを何度も送るオーバーヘッドを回避したい場合があります。例えば最初に新しい友達を追加し、5ページ目の友達一覧(現在のビュー)を取得したいガジェットなどがそうです。サーバーにとってこれはアドホックな2つのリクエストですが、省力化するため、ガジェットからのリクエストをまとめてレイテンシーを最小化することができます。または、リクエストとレスポンスは異なるデータタイプ(Activitiy、People、Persitence)かつ/または異なるサーバー向けの場合もあります。コンテナへのローカルなリクエストと一緒に行われるサードパーティーサーバーへのリクエスト(例:"phone home"リクエスト)等、どんなリクエストもまとめることができれば便利です。この場合、コンテナはプロキシの役割を果たします。

このオプション機能は、サーバーとクライアント間で一回のHTTPのやり取りのみで、リクエスト/レスポンスセット全体における任意の処理シーケンスの受信を可能にします。

ディスカバリ

コンテナがバッチ処理をサポートする場合、ディスカバリドキュメントに"batch-proxy"Serviceが告知されます。

メソッドはPOSTまたはBATCHの場合があります。コンテナは可能であればBATCHをサポートすべきですが、POSTメソッドもサポートしなければなりません。クライアントはBATCHメソッドをサポートすべきですが、POSTメソッドでも利用可能でなければなりません。

セマンティクス

このプロポーザルにおける一括処理リクエストセットは、同じリクエストを個別に送信するのと全く同じ意味を持ちます。個別では、サーバーはひとつひとつについて保証を行いません。(In particular, the server does not provide any atomicity guarantees.)サーバーはクライアント側に影響を及ぼさないことが保証されない限り、処理の順序を変更したり、並列処理したりすることが許可されていません。最も単純なサーバーの実装方法は、リクエストをループしてクライアントに返すレスポンスに応答を追加しながら順番に処理を行うことです。

OpenSocialでバッチ処理インターフェースはオプションとなります。サーバーがバッチ処理をサポートしない場合、クライアントは同義の処理を個別のリクエストとレスポンスで行います。場合によっては一括処理よりも、並列処理やキャッシュ処理が可能な個別のリクエストを行う方が効率が良い場合があります。このAPIのゴールはこれら2つのメカニズムを簡単に使い分け、意義を維持することにあります。

この終端まで、バッチ処理リクエストはバッチ処理を行うプロキシリソースに送信されるエンベロープHTTPリクエストによって表現されます。クライアントは下記をプロキシURIにPOSTします。処理が行われると(成功したか否かに関わらず)200 OKとレスポンスシーケンスドキュメントを返します。

リクエストとレスポンスシーケンスドキュメントは標準のmultipart/mixedドキュメントで表現されます。個別のリクエストとレスポンスは標準のapplication/http;version1.1ドキュメント(RFC2616の19.1章参照)で表現されます。これらのドキュメントは標準のスタンドアローンなHTTPリクエストにまとめられます。2つの部分を持った例を示します:

POST /batch_proxy HTTP/1.1 
Host: api.example.org
Authorization: OAuth ...request auth[nz] context elided...
Content-Type: multipart/mixed; boundary=batch-a73hdj3dy3mm347ddjjdf

-batch-a73hdj3dy3mm347ddjjdf
Content-Type: application/http;version=1.1
Content-Transfer-Encoding: binary
 
POST /people/@me/@all HTTP/1.1
Host: api.example.org
Content-Type: application/json
 
...新しいPersonは省略...
 
-batch-a73hdj3dy3mm347ddjjdf
Content-Type: application/http;version=1.1
Content-Transfer-Encoding: binary
 
GET /people/@me/@friends?startPage=5&count=10&format=json
Host: api.example.org
If-None-Match: "837dyfkdi39df"

レスポンスの例:

HTTP/1.1 200 OK
Content-Type: multipart/mixed; boundary=batch-a73hdj3dy3mm347ddjjdf
 
-batch-a73hdj3dy3mm347ddjjdf
Content-Type: application/http;version=1.1
Content-Transfer-Encoding: binary
 
201 Created
Location: http://api.example.org/people/example.org:38ge838389993/@all/api.example.org:5ea3gh838kjk34834
ETag: "993hhhgjgkkd"
 
-batch-a73hdj3dy3mm347ddjjdf
Content-Type: application/http;version=1.1
Content-Transfer-Encoding: binary
 
304 Not Modified
ETag: "837dyfkdi39df"

この場合、友達の追加は成功し、友達リストの5ページ目の取得のレスポンスに変更がなかった(友達はページの最後のエントリよりも後ろに追加された)ことを示しています。リソースが変更された場合は、もちろんレスポンス中に友達リストが返されます。

キープアライブやコンテントの転送エンコーディングといったすべてのリクエストに共通する項目はトップレベルのリクエストのみが指定可能です。トップレベルリクエストのレスポンスコードは: Only the top level request can specify overall request related things such as keepalives and content transfer encoding. The top level request response code is:

  • 部分的でも処理が行われると200を返します。
  • バッチドキュメントそのものに不正があり処理できない(個別の処理が行われる前にドキュメントの不正が見つからない場合もあるため、クライアントはサーバーを文法確認に利用することはできません)場合、4xxエラーを返します。ドキュメントがmultipart/mixed形式ではない場合が例として挙げられます。
  • プロキシバッチサービスそのものに障害がある場合は5xxエラーを返します。

各レスポンスには個別に実行された場合と同様のHTTPレスポンスコードが使用されます。リクエストとレスポンスは位置で一致され、サーバーはレスポンスを返す場合、n番目のレスポンスがn番目のリクエストに対する応答であることを保証します。しかし、リクエストの数とレスポンスの数が一致することは保証しません。特に、ネットワーク障害でレスポンスドキュメントが途切れたり、コネクションが切断されたりした場合、クライアントは残りのレスポンス部分について知るすべがありません。サーバーはリクエストの一部がタイムアウトし、成功したか失敗したか分からない場合、'X-Batch-Status:504 Gateway Timeout'を使って問題を認識している旨を示すべきです。504レスポンスを返されたクライアントは、リクエストがタイムアウトする前に完了した可能性があることも想定する必要があります。

コンテナは外部サーバーに対してプロキシの役割(Host:ヘッダを使用)も果たすことができることに注意してください。ただし、これはサーバーの必須条件ではありませんし、クライアントもこれを前提とすべきではありません。

一般的に、HTTPフィールドはエンベロープリクエストかサブリクエストに追加することができます。例えば、クライアントはエンベロープリクエスト(プロキシサービスに認可を行う)とサブリクエスト(外部サービスに認可を行う)のどちらにもAuthorization:ヘッダを追加することができます。

(この拡張はAstoriaでも使用されるセマンティクスであるhttp://www.snellspace.com/wp/?p=788のプロポーザルに従っています。)

部分更新 (オプション)

部分更新は、特にPeopleとAppDataに関して、完全なデータ更新内容を記述する必要がなくなります。主な用途としては、クライアントが完全なデータを取得した後、一部だけ更新したい場合が挙げられます。大抵の場合、クライアントは部分的な更新(例:たくさんのコンタクト情報のタグを変更する)をリソースのところどころに行い、同時処理の制御も行う必要があります。こういった場合、汎用化された部分更新/パッチングのメカニズムが必要となります。バッチ処理のメカニズムはサーバーのオプションであり、サポートされていない場合、クライアントは完全なデータを送ることで対応が可能です。

文法については、現時点では残課題となります。

メッセージング (オプション)

ソーシャルネットワークサービスによってはユーザー間で短いメッセージのやり取りを行うメカニズムを提供したい場合があります。この機能とポリシーはJS APIのrequestSendMessageと一致します。

ディスカバリ

コンテナはメッセージングをサポートする場合、ディスカバリドキュメントに"messages"Serviceを提示します。

セマンティクス

メッセージを作成しキューイングするには、クライアントはXRDSドキュメントでディスカバリすることのできる"outbox"コレクションリソースにメッセージをPUTします:

PUT /messages/{guid}/outbox/{msgid}

outboxは送信もとユーザーにより所有されます。outboxにメッセージを置くことで、ひとりまたは複数の受信者に対しての送信がリクエストされます。コンテナは自身のポリシー(セキュリティまたは負荷による制限)に従い、メッセージをフィルタまたは変更する自由が与えられています。

メッセージのフォーマットはActivityと同様ですが、受信者のセット(osapi:recipient)が追加されます:

{msgid}はクライアントによって生成され、グローバルにユニークであるべきです。クライアントが失敗した場合を考慮していない場合、/messages/{source-uid}/outboxに対して標準のAtomPub POSTを使用し、IDの生成をコンテナに委ねることができます。どちらの場合でも成功した場合のレスポンスは201 Createdとなります。

サポートされていない場合、レスポンスコードは403 Not Implementedです。

典型的には、コンテナはリクエスト者のIDと{guid}が一致するoutboxに対するPUTのみを許可しますが、これはコンテナのポリシーが決定する事項です。コンテナによってはスパムを防ぐため、友達同士などに制限する場合があります。