2011年7月1日金曜日

12.Default values

リクエストを送る際、日時を指定し、その日時以前に投稿されたノートを取得するようにし、
(on_or_beforeフィールド。タイムスタンプを整数型で受け取り、日時として使用します。)

また、取得するノートの順序を指定できるようにします。(orderフィールド)

limitフィールドは、取得するノートの最大件数を指定します。
もしlimitフィールドが指定されていない場合、defaultキーワードで指定された10が最大件数になります。

11.More fields

postserviceに新しいノートを投稿できるようになりました。
次は、投稿されたノートを取得する、get_notesメソッドを定義してみましょう。

まず、リクエストメッセージを、postservice.pyファイルの、サービスクラス定義より上に書きます。

class GetNotesRequest(messages.Message):
  limit = messages.IntegerField(1, default=10)
  on_or_before = messages.IntegerField(2)
  class Order(messages.Enum):
    WHEN = 1
    TEXT = 2
  order = messages.EnumField(Order, 3, default=Order.WHEN)

10.Testing the service from the command line

これで、サービスのテストが可能になりました。
curlなどのツールでアクセスしてみましょう。

% curl -H \
     'content-type: application/json' \
    -d {"text": "Hello guestbook!"}'\
    http://localhost:8080/postservice.post_note

サーバーが空のJSONレスポンスを返せば、成功です。ノートは投稿されています。
ブラウザでゲストブックアプリケーションを開けば、投稿されたノートを見ることができるでしょう。

http://localhost:8080/

09.Registering the service

ここまでの説明でサービス、メッセージを定義できましたので、
App Engineのwebappフレームワークを利用して、サービスを公開し、
外部からサービスにアクセスできるようにします。

service.pyというファイルをアプリケーションディレクトリに作成してください。
そして、以下のコードを追加します。

from google.appengine.ext import webapp
from google.appengine.ext.webapp import util
from protorpc.webapp import service_handlers
import postservice
# Register mapping with application.
application = webapp.WSGIApplication(
  service_handlers.service_mapping(
      [('/postservice', postservice.PostService)]),
  debug=True)

def main():
  util.run_wsgi_app(application)

if __name__ == '__main__':
  main()


そして、以下のURLハンドラをapp.yamlに追加してください。

- url: /postservice.*
  script: services.py

08.Defining a service

「サービス」は、「Service」(protorpc.remote.Service)を継承したクラスによって定義します。

ゲストブックアプリケーションのチュートリアルで、
ゲストブックの挨拶文は、guestbook.Greetingクラスによって、データストアに保存しました。

Postサービスも、投稿のデータストアへの保存にGreetingクラスを使用することにします。

import datetime
from protorpc import message_types
from protorpc import remote
import guestbook
class PostService(remote.Service):
  @remote.method(Note, message_types.VoidMessage)
  def post_note(self, request):
    if request.when:
      when = datetime.datetime.utcfromtimestamp(request.when)
    else:
      when = datetime.datetime.now()
    note = guestbook.Greeting(content=request.text, date=when)
    note.put()
    return message_types.VoidMessage()

「method」デコレータ(@remote.method)は、2つのパラメータを取ります。
最初のパラメータは、リクエストのデータ型で、
2つ目のパラメータは、レスポンスのデータ型です。

ノートの投稿を受け付けるために、上記の「post_note」メソッドはNoteクラス(メッセージ)のインスタンスをリクエストとして受け取ります。

レスポンスには、「VoidMessage」(protorpc.message_types.VoidMessage)を指定していますが、
これはProtoRPCの組み込み型で、フィールドを持たないメッセージを意味します。

つまり、「post_note」メソッドは、呼び出し側に意味のあるデータを返しません。
エラーが発生しない限り、呼び出し側では、投稿は成功した、と見なします。

Note.whenは、必須フィールドではないので、呼び出し側がセットしているとは限りません。
セットしていない場合、whenにはNoneがセットされています。

「post_note」メソッドは、Noteにタイムスタンプが設定されていない場合、現在時刻を指定したものと見なします。

レスポンスメッセージは、リモートメソッドによってインスタンス化され、戻り値として使われます。

07.Working with messages

「メッセージ」は、ProtoRPCで、クライアントアプリケーションと、
サーバーがやりとりをするためのデータ型です。

「メッセージ」は、「Message」(protorpc.messages.Message)を継承したクラスとして定義します。
データフィールドはクラスの属性に相当します。

例として、ゲストブックアプリケーションでは、ユーザーはノートの投稿ができます。
そのノートを表現するメッセージを作ってみましょう。


from protorpc import messages
class Note(messages.Message):
  text = messages.StringField(1, required=True)
  when = messages.IntegerField(2)

このノートメッセージは、「text」と「when」という、2つのフィールドを持ちます。
それぞれのフィールドは型を持ちます。
textフィールドは文字列(ユニコード文字列)であり、ユーザーがゲストブックに投稿した文章を表します。
whenフィールドは整数であり、ノートが投稿された際のタイムスタンプを表します。

それぞれのフィールドは、一意の数値を持ちます。
(フィールド定義の最初の引数のことです。ノートメッセージの場合、「text」が1で、「when」が2です。)
この数値は、データをネットワークに流す際に、フィールドの識別子として利用されます。
(名前は識別子として使用しません。)

フィールドの値は、Noteクラスのコンストラクタでセットできます。
import time
note_instance = Note(text=u’Hello guestbook!’,
                     when=int(time.time())


これらのフィールドは、通常のPythonクラスの属性と同様に読み書きできます。
例えば、

print note_instance.text
note_instance.text = u‘Good-bye guestbook!’
print note_instance.text

とした場合、この出力は以下のようになります。

Hello guestbook!
Good-bye guestbook!

フィールドは、値の設定を必須にすることも、しないこともできます。
デフォルトは必須ではありませんが、フィールド定義に「required=True」を追加することで、必須になります。

メッセージのインスタンスが初期化済みである、と見なされるためには、必須フィールドが設定されている必要があります。
そして、ProtoRPCサービスは、初期化済みであるとみなされたメッセージのみ、受け取ることができます。

06.The postservice

postserviceモジュールは、ゲストブックアプリケーションのデータにアクセスするための、
以下の2つのリモートメソッドを定義するモジュールです。

post_note:App Engineのデータストアにノートを投稿します。
get_note:投稿されたノートを取得します。

とりあえず、アプリケーションディレクトリに、postservice.pyファイルを作成してください。
ファイルの中身は、順次説明していきます。