Reflex Tagging Service

概要

これは何?

  • Reflex Tagging Serviceは、リソース志向の階層型CMS&ワークフローエンジンです。リソースから様々なReflex(反射像)を取り出すためのフレームワーク「Reflex」を基に開発されています。
  • ReflexではリソースがJSON/XMLなどに変換されても構造が崩れない統一したEntityモデルを扱います。Tagging Serviceでは統一EntityモデルとしてATOM Feedを採用しています。
  • Reflex Tagging Serviceは、統一したEntityモデルとシンプルなREST APIにより、Datastoreなどの下位のレイヤーをアプリケーションから隠蔽します。
  • また、アプリケーションをRESTfulに設計することで、各サービス間を疎結合とすることを推奨しています。こうすることで、スケーラブルなシステムを構築することができます。
  • Reflex Tagging Serviceは、現在はGoogle App Engine上で動作しますが、将来的にはCassandraなどのKey/ValueストレージやRDBにも対応する予定です。また、Reflex BDBのサービス層としても使用します。 統一したEntityモデルと共通のREST APIにより高い可搬性をもち、どのようなプラットフォームにおいてもアプリケーションを変更することなしに動作させることができます。
tsxml

主な機能

  • Reflex Tagging Serviceは、様々なコンテンツをATOM Feedとして管理し、URLによる階層型のリソース管理を行います。
    • ATOM FeedはXMLとJSONの2つの形式で表現できる
    • URLで指定されたリソースをATOM Feed形式でGET,POST,PUT,DELETEできる
  • REST APIによる容易なアクセス手段を提供し、1つのリソースから様々な表現(HTML,XML,JSON,BLOBなど)で取り出すことが可能です。
    • HTMLやXML、JavaScriptなどのコンテンツを直接、ATOM entryのcontentとして格納できる
    • Blobstoreにイメージデータなどを格納できる
    • 格納したHTMLやJavaScriptなどのコンテンツは直接ブラウザで表示できる
    • entryの個数を取得できる
    • 取得件数を指定できる(ページング機能)
    • 履歴管理
    • BulkCopy機能でデータを大量同時にインポートできる
  • リソースに複数の検索項目や別名をつけて検索できます。また、OpenIDで階層ごとにACLを設定できます。
    • リソースに対して複数のproperty(検索項目)を付けて検索することができる
    • 格納したリソースのalias(別名アドレス)を付けられる
    • OpenIDに対応している
    • リソースの階層ごとにACLを設定できる
    • WSSE認証に対応している
    • Datastore登録において、ドメインごとのNamespaceをセットしており、マルチテナントに対応している。
  • WebHook機能により他サービスとの連携ができます。また、Server Side Script機能によりサーバサイドでJavaScriptを実行できます。
    • CRUD操作に応じて起動するWebHookを設定できる
    • リソースとして格納したJavascriptをサーバサイドで実行できる
    • イベント駆動型のアプリケーションを作成することができる。
    • アクセスログを管理できる
    • 動的ページをJavaScriptで作成できるためJSPやJavaプログラムをデプロイする必要がない

機能説明(1/5)

リソースの階層管理とREST API

Reflexにおけるリソースの概念

  • リソースは自己完結したデータの集合
  • リソースはデータ構造(ATOM Feed)をもち公開できる
  • リソースに対してCRUDで操作する
  • リソースは特定できるアドレス(URI)をもつ
  • リソースに対して1UOWで操作する

リソースの階層構造について

  • リソースは一意になるようにURLにマッピングされます。また、URLで指定されたリソースに対してATOM Feed形式でCRUD(GET,POST,PUT,DELETE)できます。 これは、 GData Protocolによく似ていますが、Tagging Serviceではリソースの階層を表現することが可能で、例えば、/foo/barとすると、foo entryの子にあたるbar entryを示すことができます。 階層は1000階層まで持つことができ、子entryは無限に持つことができます。

GET

  • EC商品検索 DEMO( http://cloudec-mock.appspot.com/goods.html#/Men/Tops/Sweater/it/p,1/u,20/s,ASC ) のCRUD例では、商品情報はカテゴリ別に管理されており、Men>トップス>セーター>トップスU のように格納されています。 トップスの下のカテゴリに何が入っているかを調べたいときは、トップスまでのURL(/Men/Tops)を指定してGET実行します。
  • 取得結果は、URLパラメータに何も付けないとJSON、?xmlでXMLになります。 また、?atomでATOM Feedになります。?xmlとの違いは、xmlns="http://www.w3.org/2005/Atom"が付くこと、feed.generatorタグとfee.titleタグが付くことです。 これにより、Feed Readerなどのアプリで正しくAtomを読み込めるようになります。
    /Menの子entry(JSON)を含むFeedを取得
    GET http://tagging-service.appspot.com/d/cloudec/Men
    
    /Men/Topsの子entry(JSON)を含むFeedを取得
    GET http://tagging-service.appspot.com/d/cloudec/Men/Tops
    
    &xmlを付けることでXML表現で取得
    GET http://tagging-service.appspot.com/d/cloudec/Men/Tops?xml
    
    &countを付けることで件数を取得
    http://tagging-service.appspot.com/d/cloudec/Men/Tops?xml&count
    
    /Men/Topsの自身のentryを取得
    GET http://tagging-service.appspot.com/d/cloudec/Men/Tops?entry&xml
    
    /Men/Topsの特定のリビジョン(r=2)を取得
    GET http://tagging-service.appspot.com/d/cloudec/Men/Tops?r=2&xml
    
    /Men/Topsの履歴すべてを取得
    GET http://tagging-service.appspot.com/d/cloudec/Men/Tops?history&xml
    
    &atomを付けることでATOM Feedで取得
    GET http://tagging-service.appspot.com/d/cloudec/Men/Tops?atom
    
  • パラメータにlを指定することで、取得件数の上限を指定できます。
    • l=取得件数上限
    • 検索結果が取得件数の上限に達した場合、link rel="next"タグにcursor文字列が返されますので、次の検索においてパラメータpを使ってcursor文字列を渡してください。

      o p=カーソル文字列

      上限を3件として検索
      http://tagging-service.appspot.com/d/cloudec/Men/Tops?xml&l=3
      
      次のページを表示するにはpにcursor文字列を指定する
      http://tagging-service.appspot.com/d/cloudec/Men/Tops?xml&l=3&p=E9oBgwF0YWdnaW5nLXNlcnZpY2UAi5JFbnRyeQCiL2Nsb3VkZWMvTWVuL1RvcHMvQ2FyZGlnYW4AjIuSRW50cnkAoi9jbG91ZGVjL01lbi9Ub3BzL0NhcmRpZ2FuLDAAjICLkkVudHJ5AKIvY2xvdWRlYy9NZW4vVG9wcy9DYXJkaWdhbgCMgOABABQ
      
  • パラメータに&callback=function名を指定することでJSONPを実行できます。
    JSONPで実行
    GET http://tagging-service.appspot.com/d/cloudec/Men/Tops?callback=foo
    

POST

  • トップスの下に新たなentryを追加したい場合にはPOSTを実行します。
  • POSTでは、entryのURL(selfid)を、entry内のlink rel="self"のhrefに指定することで、任意のentryを作成することができます。 ただし、既に同じ名前のselfidが存在した場合は重複登録エラーが発生しますので注意が必要です。
  • link rel="self"を省略すると13桁のUNIX Timestamp番号が自動的に付与されます。この場合、POST先のURLには親entryを指定します。なお、自動採番は階層で一意となります。
  • POST時にはupdated項目とAuthor項目(created)、IDが自動的に付与されます。IDはPUTの際に必要となります。
    POST http://tagging-service.appspot.com/d/
    
    <entry>
      <link href="/cloudec/Men/Tops" rel="self" /> 
      <title>トップス</title> 
    </entry>
    

    あるいは、

    POST http://tagging-service.appspot.com/d/cloudec/Men/
    
    <entry>
      <title>トップス</title> // この場合、selfidは自動採番される
    </entry>
    

PUT

  • entryを更新したい場合にはPUTを実行します。これは部分更新であり、存在するタグの項目だけを更新して残りはそのままとなります。
  • 空の値で更新すると空タグ(例えば、subtitle /など)にはなりますが、タグそのものを消すことはできません。そうしたい場合は、DELETEしてPOSTしなおす必要があります。
  • idタグで更新前のRevision番号を付けなければなりません。各entryは、Versioningされており、更新対象のRevisionが異なれば楽観的排他エラーが発生します。
  • 更新処理が成功するとrevisionの値が一つ増えます。過去のentryは履歴として保存されており、&historyパラメータを付けることで全て取得することができます。(GETの例を参照)
  • idタグにaliasのidを指定することで、aliasを更新することもできます。
  • PUTが使用できない場合は、POSTを送り、HTTPヘッダーに「X-HTTP-Method-Override: PUT」をセットすることで代用できます。
  • PUT時にはupdated項目とAuthor項目(updated)が自動的に付与されます。
    PUT http://tagging-service.appspot.com/d/
    
    <entry>
      <id>/cloudec/Men/Tops,3</id> 
      <link href="/cloudec/Men/Tops" rel="self" /> 
      <title>トップス</title> 
    </entry>
    

DELETE

  • DELETEではrevisonを指定して実行します。これは論理削除であり実行後もDatastoreに実体は残っています(entityに削除フラグが付与されるだけです)
  • DELETEが使用できない場合は、POSTを送り、HTTPヘッダーに「X-HTTP-Method-Override: DELETE」をセットすることで代用できます。
    DELETE http://tagging-service.appspot.com/d/cloudec/Men/Tops?r=1
    

FeedをBatch登録する機能

  • 複数のentryをもつfeedをPUTまたはPOSTすることで一度に大量のデータを登録更新できます。(MAX1000件) ただし、30秒を超えるとタイムアウトエラーが発生しますので、時間内に終わらないような場合は非同期実行にする必要があります。
  • Tagging ServiceにPOSTする際に、notifyパラメータをつけて実行することで非同期実行が可能です。
    • &notify=http://foo/bar&txid=001 (txidはリクエストを識別するIDでクライアント側で付与する)
  • Tagging ServiceはPOSTを受け付けると実行完了を待たずに200 OKを返します。また同時にMemcacheにPOST(feedの中身)を記録してTaskQueueを起動します。
  • Taskの実行完了で、成功/失敗のStatusを含むWebHookを、notifyアドレスに対して実行します。
    • {"status" : {"code" : 409, "txid" :001, "errorentry" : "/xxx/001","message" : "XXXXX."}}
  • 部分成功を許容しており、feedのなかのすべてのentryが登録更新成功しなくても、全体がロールバックされることはありません。 エラーのあった個々のentryについてはロールバックされます。エラーの種類は次の通りです。
    • 入力エラー(レスポンスコード400)
    • 権限エラー(レスポンスコード403)
    • Conflictエラー(レスポンスコード409)
    • その他のエラー(GAEメンテナンス中、データストアエラーなど)
  • タイムアウト時(DeadlineExceededException : レスポンスコード408)における再実行処理はTaskQueue内で処理します。30秒後にTask登録することで再実行されます。

BulkCopy機能

  • BulkCopy機能は大量データ登録時におけるパフォーマンス向上のためのオプションです。 POST時にURLパラメータに&bulkcopyが指定されている場合、トランザクション処理を実行しないため、大量データを高速に登録することができます。(MAX1000件) 登録する内容はFeedのBatch登録と同じで、EntryをFeedに詰めたものをセットできます。ただし、以下のような制限があります。
    • 自動採番は不可
    • Alias指定不可
    • WebHookについて、自分に指定・親階層に指定のどちらの場合も処理を行わない
    • Bulkcopy実行中はPOST、PUT、DELETEが受付不可となる。(423 Locked) (MemcacheにBulkcopy処理中フラグを立てる)
  • Bulkcopy処理中にエラーが発生すると10分後に再起動されます。
  • bulkcopyの処理フロー
    1. 入力値のチェック
    2. 件数チェック(1000件以上はエラー)
    3. URL(link self)が指定されているか、URL重複チェック、カテゴリ名チェック、Aliasチェック(指定不可)
    4. MemcacheにBulkcopy処理中フラグを立てる
    5. 各URLに対し権限チェックを行う。親階層でチェックを行うので、一度チェックした階層と同じ親であればスキップする。各URLに対し親階層存在チェックを行う。
    6. 各URLに対しデータ存在チェックを行う。(batch get)
    7. 登録する。(200件ごとにbatch put) author、updatedをセットする。
    8. MemcacheのBulkcopy処理中フラグを削除する。

    >> 次へ