目次


Google App Engine をベースに Eclipse を使用して作成するマッシュアップ

第 1 回 アプリケーションを作成する

Comments

コンテンツシリーズ

このコンテンツは全#シリーズのパート#です: Google App Engine をベースに Eclipse を使用して作成するマッシュアップ

このシリーズの続きに乞うご期待。

このコンテンツはシリーズの一部分です:Google App Engine をベースに Eclipse を使用して作成するマッシュアップ

このシリーズの続きに乞うご期待。

この連載について

この連載では、GAE (Google App Engine) を使い始める方法を紹介します。この第 1 回でまず焦点とするのは、GAE で実行するアプリケーションの作成を開始できるように開発環境をセットアップすることです。その後、Eclipse を利用してアプリケーションの開発とデバッグを容易にする方法を説明します。第 2 回では、Eclipse を使って Ajax マッシュアップを構築し、そのマッシュアップを GAE にデプロイします。そして最終回の第 3 回目で、アプリケーションに RESTful なサービスを作成することによってエコシステムに還元し、他の開発者もこのアプリケーションを使ってそれぞれ独自のマッシュアップを作成できるようにします。

GAE は、Web アプリケーションを作成するためのプラットフォームです。GAE で使用するのは Python (現在のバージョンは、Python V2.5.2) であることから、GAE を使うにはこのプログラミング言語についての知識があることが最大の前提条件となります。この連載を読むにあたっては、ある程度の一般的な Web 開発スキル (HTML、JavaScript、CSS の知識) があると役立ちます。GAE 対応の開発を行うには、以下の 3 つのソフトウェア・パッケージをダウンロードする必要があります。

Eclipse Classic
この連載では Eclipse Classic V3.3.2 を使用しました。これ以降のバージョンでも有効です。
Google App Engine SDK
GAE サイトに、公式ドキュメントと SDK のダウンロード・リンクが用意されています。
PyDev
Eclipse を Python IDE に変身させる PyDev は、Eclipse 内で更新サイト (http://pydev.sourceforge.net/updates/) を指定してインストールすることができます。

最後の 2 つのソフトウェア・パッケージをインストールする方法については、この後詳しく説明します。Eclipse を使用するのが初めての方は、まずは「参考文献」を参照してください。

GAE のセットアップ方法

ある程度の Web アプリケーションの開発経験があれば、新しいアプリケーション・スタックに取り掛かる際にライブラリー、Web サーバー、データベースをダウンロードする作業には慣れていることでしょう。場合によっては、これらの作業のすべてをインストーラーにバンドルし、ファイルを適切に配置し直すといった作業を多少なりとも簡単にできるようになっていることもあります。通常はすべてを所定の位置に配置した後、お気に入りの開発環境で操作できるようにするための厄介な作業をさらに行わなければなりませんが、GAE を使う場合にはその限りではありません。早速、GAE をセットアップする方法、そして Eclipse と連動させる方法を見ていくことにしましょう。

GAE をセットアップするために最初に必要な作業は、SDK をダウンロードすることです。SDK には Microsoft® Windows® 用、Mac OS X 用、Linux® 用があり、Windows 用と Mac OS X用の SDK はインストーラーとして提供されます。このインストーラーはシステムに SDK をインストールするだけでなく、いくつかの重要な実行可能スクリプトもすぐに使えるようにあらかじめパスに配置してくれます。SDK のディレクトリー構造は、図 1 に示すようになります。

図 1. GAE SDK ディレクトリー構造
GAE SDK ディレクトリー構造
GAE SDK ディレクトリー構造

ディレクトリーのルートを見ると、2 つの Python スクリプト、appcfg.py と dev_appserver.py があります。dev_appserver.py は、開発アプリケーション・サーバーを起動するために使用するスクリプトです。アプリケーションの開発およびテストに個別のインストール、デプロイメントは必要ありません。もう一方の appcfg.py スクリプトは、アプリケーションを GAE にデプロイする準備が整ったときに使用します。

Google ディレクトリーには GAE プラットフォームの基礎となるすべての API があり、必然的に、このディレクトリーにあるクラスを使用および継承することになります。したがって、何かから GAE アプリケーション・コードを実行する場合には、このディレクトリーについて把握している必要があります。GAE アプリケーション・コードを実行するには、そのコードが使用する API を把握していなければならないからです。その一例として、GAE コードを開発するための Eclipse をセットアップする方法を説明します。

Eclipse のセットアップ方法

Eclipse は、Java™ プログラミング言語のアプリケーションを開発する際の代表的な IDE として知られています。しかし、Eclipse は Java 開発者だけのものではありません。C++、PHP、Ruby、そして Python など、他の多くの言語にも使用されています。実際、Eclipse を Python IDE に変換する Eclipse プラグインはいくつも用意されています。なかでも最もよく使用されているのは、PyDev です。PyDev は Eclipse の更新サイト (http://pydev.sourceforge.net/updates/) からインストールすることができます。

PyDev をインストールしたら、今度は PyDev を構成する必要があります。Eclipse を開いて、Preferences > PyDev に進んでください。

図 2. PyDev の構成
PyDev の構成
PyDev の構成

PyDev には Python のインストール場所を指定する必要があるので、上記のように Interpreter > Python の順に進んで New をクリックします。Python V2.5+ インストールまでナビゲートするだけで、後の作業は Eclipse が行ってくれます。OK をクリックすれば、Eclipse で Python を開発できるようになります。

アプリケーションを作成する

まずは、Eclipse で新しい PyDev を作成するところから始めます。それには、Windows > Open Perspective > Other を選択し、使用可能なパースペクティブのリストから PyDev を選んで PyDev パースペクティブに切り替えます。

図 3. PyDev パースペクティブの表示
PyDev パースペクティブの表示
PyDev パースペクティブの表示

これで、File > New > PyDev Project を選択すれば、新規アプリケーションの作成に取り掛かれます。この例ではソース・コード用に別個の src フォルダーを作成することにしますが、これはオプションで、ほとんど好みの問題です。今まで行ってきた作業はすべて Eclipse での Python 開発に一般的なことでしたが、ここからは GAE 特有の作業に入ります。

GAE テンプレート・プロジェクト

GAE プロジェクトはレイアウトの点では単純で、ディレクトリーは 1 つしかなく、サブディレクトリーはありません。必要なファイルは、app.yaml、index.yaml、main.py の 3 つです。このうち、最初の app.yaml ファイルを以下に記載します。

リスト 1. app.yaml
application: aggrogator
version: 1
runtime: python
api_version: 1

handlers:
- url: .*
  script: main.py

これは、GAE アプリケーションの主要な構成ファイルです。このファイルに含まれるほとんどの項目は 1 度設定すればよいだけで、例えばアプリケーションの名前、バージョン、そしてアプリケーションの作成に使用した GAE API のバージョンなどがこれに該当します。それよりも作業量が多くなる部分は handlers のセクションです。handlers セクションでは HTTP リクエストの URL とプロジェクト内の Pythonスクリプトを対応付けます。上記の例では、すべての HTTP リクエストの URL が同じ 1 つの main.py スクリプトにマッピングされています。この main.py ファイルでさらにルーティングを行って、URL をメソッドに一致させることができます。

もう 1 つの YAML ファイル、index.yaml は GAE がデータを効率的にフェッチできるようにするためのファイルです。実際のところ、このファイルがなくても支障はありません。ファイルが用意されていなければ、GAE が自動的に生成するからです。今のところ、このファイルで必要な作業は何もないので、リスト 2 にはブランク状態のファイルを記載します。

リスト 2. index.yaml
indexes:

# AUTOGENERATED

# This index.yaml is automatically updated whenever the dev_appserver
# detects that a new type of query is run.  If you want to manage the
# index.yaml file manually, remove the above marker line (the line
# saying "# AUTOGENERATED").  If you want to manage some indexes
# manually, move them above the marker line.  The index.yaml file is
# automatically uploaded to the admin console when you next deploy
# your application using appcfg.py.

いよいよ、アプリケーションの核心部分、main.py スクリプトです。app.yaml の内容と矛盾しない限り、このファイルにはどんな名前を付けても構いません。一般的に使用される名前は main.py なので、ここではこの名前を使用します。このファイルを検討する前に、これから作成するアプリケーションのタイプについて説明しておきます。

aggroGator

このサンプル・アプリケーションの名前は、aggroGator です。このアプリケーションでは、ユーザーがすでに使用している各種の Web サービスにユーザー自身を関連付けることができます。すると、アプリケーションはこれらのサービスからデータ・フィードを取得して、時系列で集約します。このアプリケーションでフィードの構文解析に使用するのは、評判の高い FeedParser ライブラリーです。さらに、Google を介して GAE の組み込み ID 管理機能を使用するため、独自の登録/ログイン/ログアウト機能を作成する必要はありません。ユーザーは単純に Google ID を使ってログインします。これらの点を念頭に、main.py を見てみましょう。

リスト 3. main.py
def main():
  application = webapp.WSGIApplication(
                                       [('/', MainPage),
                                        ('/add', AddService)],
                                       debug=True)
  wsgiref.handlers.CGIHandler().run(application)

if __name__ == "__main__":
  main()

見てのとおり、これは単なるスクリプトの main メソッドに過ぎません。このスクリプトが実行することは、追加のルーティングをセットアップするだけです。この例では、「/」に対するリクエストの場合は MainPage というクラスにルーティングし、「/add」に対するリクエストの場合は AddServiceというクラスにルーティングします。以下に、MainPage クラスを記載します。

リスト 4. MainPage
class MainPage(webapp.RequestHandler):
  def get(self):
    user = users.get_current_user()

    if users.get_current_user():
      url = users.create_logout_url(self.request.uri)
      url_linktext = 'Logout'
    else:
      url = users.create_login_url(self.request.uri)
      url_linktext = 'Login'
      
    updates = []
    account = None
    if user:
        account_query = Account.all()
        account_query.filter('user = ', users.get_current_user())
        result_set = account_query.fetch(1)
        if len(result_set) > 0:
            account = account_query.fetch(1)[0]
        
        if account:
            updates = []
            for service in account.dynamic_properties():
                url = getattr(account, service)
                feed = GenericFeed(url, service)
                updates.extend(feed.entries())
        else:
            account = Account()
            account.user = user
            account.put()
        updates.sort(key=attrgetter('timestamp'), reverse=True)

    template_values = {
      'account': account,
      'updates': updates,
      'url': url,
      'url_linktext': url_linktext,
      }

    path = os.path.join(os.path.dirname(__file__), 'index.html')
    self.response.out.write(template.render(path, template_values))

このクラスはアプリケーションのメイン・コントローラーであるため、その実行内容は盛りだくさんです。まず注目する点として、このクラスには get メソッドしかありません。つまり、このクラスがサポートするのは HTTP GET リクエストのみで、[/」に対する POST はエラーになります。次にこのクラスが行うのは、ID のチェックです。users クラスは GAE SDK の API で、この API では Google の ID 管理機能を利用します。ここでは、この機能を使用してユーザーがログインしているかどうかをチェックするため、ユーザーがログインしている場合には、そのユーザーが誰であるのか (つまり、そのユーザーの Google ID) がわかるというわけです。続いて、ユーザーがログインしているかどうかに応じて、ログインまたはログアウト・リンクを作成します。ユーザーがログインしていなければ単にログイン・リンクを表示し、ログインしていれば、アカウントを参照して処理を続けます。Account クラスは、このアプリケーションのために作成したもう 1 つのクラスです。以下を参照してください。

リスト 5. TheAccount クラス
class Account(db.Expando):
    user = db.UserProperty()

このクラスが利用するのは Google のデータ・ストレージ API (Google の有名な Bigtable データ・ストア) です。Account エンティティーは User プロパティーを持ち、Expando モデルとなっています。そのため、動的プロパティーの作成、つまり各サービスの URL ごとにプロパティーを作成することができます。サービスごとのエントリーのリストを取得するには、以下に示す GenericFeed クラスを使用します。

リスト 6. GenericFeed クラス
class GenericFeed:
    def __init__(self, url, name):
        self.url = url
        self.name = name
    def entries(self):
        result = urlfetch.fetch(self.url)
        updates = []
        if result.status_code == 200:
            feed = feedparser.parse(result.content)
            for entry in feed['entries']:
                x = Entry()
                x.service = self.name
                x.title = entry['title']
                x.link = entry['link']
                if entry.summary:
                    x.content = entry.summary
                else:
                    x.content = entry['title']
                x.timestamp = entry.updated_parsed
                updates.append(x)
        return updates

これが、FeedParser ライブラリーを使用するクラスです。このライブラリーを使用する前には、GAE API の別のクラス、urlfetch を使用します。このクラスは HTTP リクエストを許容しますが、ただし、ポート 80 および 443 (セキュアなリクエスト用) に限ります。このクラスを使用する目的は、保存されたURL で HTTP GET を実行することだけで、実行結果は FeedParser ライブラリーに渡します。それに続いて作成するのは、以下に記載する Entry クラスのインスタンスです。

リスト 7. Entry クラス
class Entry:
    def __init__(self=None, title=None, link=None, timestamp=None, 
content=None, service=None):
        self.title = title
        self.link = link
        self.content = content
        self.service = service
        self.timestamp = timestamp
    def printTime(self):
        return strftime('%B %d,%Y at %I:%M:%S %p',self.timestamp)

このクラスの大部分は単純なデータ構造でしかありません。このクラスの唯一のロジックは、タイムスタンプを出力するためのメソッドの部分です。GenericFeed クラスは、ユーザーに関連付けられたサービスごとに Entry インスタンスのリストを返します。これらの Entry インスタンスは、タイムスタンプを基準に降順でソートします (最新の Entry が先頭)。次に MainPage に戻って、いくつかのオブジェクト、ユーザーの Account、ソートされた Entry のリスト、そしてログイン/ログアウト・リンクをテンプレートに渡します。GAE が使用するテンプレート・システムは、人気の Python フレームワーク、Django が使用するものと似ています。この例では、index.html という名前のテンプレートにデータを渡します。

リスト 8. index.html テンプレート
<html>
  <body>
    <a href="{{ url }}">{{ url_linktext }}</a>
    <ol>
    	{% for update in updates %}
    		<li>
    			From {{update.service}}: 
    			<a href="{{update.link}}">{{update.content}}</a>
    			posted at: {{update.printTime}}
    		</li>
    	{% endfor %}
    </ol>
    {% if account %}
	    <form action="/add" method="post">
	    	<label for="service">Service: </label>
	    	<select name="service">
	    		<option>twitter</option>
	    		<option>del.icio.us</option>
	    		<option>last.fm</option>
	    		<option>YouTube</option>
	    	</select><br/>
	    	<label for="username">Username: </label>
	    	<input type="text" name="username"/>
	    	<input type="submit" value="Add"/>
	    </form>
    {% endif %}
  </body>
</html>

これは単純なテンプレートで、その大部分は HTML でしかありませんが、動的な部分がいくつかあります。まず、該当するログイン/ログアウト・リンクを作成する部分。次にエントリーのリストを繰り返し処理して、ユーザーにエントリーを表示する部分。そして最後に、ユーザーがログインしている場合に、ユーザーがサービスを追加するためのフォームを作成する部分です。このフォームは /add URL に対して HTTP POST を実行します。リスト 3 で説明したように、リクエストは AddService コントローラー・クラスにルーティングされます。

リスト 9. AddService コントローラー
class AddService(webapp.RequestHandler):
    def post(self):
        # check if user already exists
        account_query = Account.all()
        account_query.filter('user = ', users.get_current_user())
        result_set = account_query.fetch(1)
        if len(result_set) > 0:
            account = account_query.fetch(1)[0]
        else :
            account = Account()
            account.user = users.get_current_user()
        service = self.request.get('service')
        username = self.request.get('username')
        if service == 'twitter':
            service = 'http://twitter.com/statuses/user_timeline/'+username+'.rss'
            account.twitter = service
        if service =='del.icio.us':
            service = 'http://del.icio.us/rss/' + username
            account.del_icio_us = service
        if service == 'last.fm':
            service = 'http://ws.audioscrobbler.com/1.0/user/'+username+
			                                           '/recenttracks.rss'
            account.last_fm = service
        if service == 'YouTube':
            service = 'http://www.youtube.com/rss/user/'+username+'/videos.rss'
            account.you_tube = service
        account.put()
        self.redirect('/')

このクラスはユーザーのアカウントを参照し、使用されたサービスに応じて適切な URL を作成します。そしてこの URL を、Expando プロパティーを使ってアカウントのサービスに追加した後、すべてを Bigtable に保存します。そして最後に、MainPage にリダイレクトします。

アプリケーションのコードはこれですべて説明したので、いよいよこのアプリケーションを実行する番です。アプリケーションの実行も、同じく Eclipse によって容易になります。

ローカル側でのテスト方法

GAE SDK には、プロジェクトをローカルで実行するためのコマンドライン・ツールが用意されています。ただし、ここでは Eclipse の利点を生かしたいので、Eclipse 内からアプリケーションを実行します。それによって、後で説明するようにアプリケーションのデバッグが可能になります。アプリケーションを実行する際の最初のステップは、PYTHONPATH をプロジェクトに合わせて編集することです。その最も簡単な方法として、プロジェクトを右クリックして Properties を選択してください。すると、プロジェクトのプロパティーが表示されます。

図 4. プロジェクトのプロパティー
プロジェクトのプロパティー
プロジェクトのプロパティー

上記の図に示されているように、まず左側のメニューで PyDev - PYTHONPATH を選択します。次に Add source folder をクリックして、GAE SDK がインストールされている場所までナビゲートします。この場所は使用している OS によって異なりますが、カスタマイズすることができます。Windowsでのデフォルト (インストーラーによる設定) は C:\Program Files\Google\AppEngine で、OS X でのデフォルトは /usr/local/google_appengine です。Linux を使用している場合、あるいはOS 固有のインストーラーではなく ZIP をダウンロードした場合には、SDK を配置する場所は任意に選択されているはずです。この場所はどこでも構いませんが、Eclipse が場所を認識できるようにしてください。ここでは、この場所を $APP_ENGINE_HOME と呼ぶことにします。

これで、後はプロジェクトを実行すればよいだけとなりました。プロジェクトを実行するには Run プロファイルを作成する必要があります。Run > Open Run ダイアログを選択してください。

図 5. Run ダイアログ
Run ダイアログ
Run ダイアログ

この Run プロファイルには aggroGator という名前を指定します。Main Module で、$APP_ENGINE_HOME をブラウズして dev_appserver.py スクリプトを選択してください。これは、GAE 実動環境を模倣する Python アプリケーション・サーバーです。次に、Arguments タブに進みます (図 6 を参照)。

図 6. Arguments タブ
Arguments tab
Arguments tab

Program arguments ボックスに、${project_loc}/src を入力します。Eclipse 変数 ${project_loc} は現行プロジェクトの物理ロケーションを指すだけに過ぎません。/src とあるのは、dev_appserver.py スクリプトにアプリケーションのディレクトリーを渡す必要があるためです。コードを置いてあるのが src ディレクトリーでない場合は、該当するディレクトリーに変更してください。

これで、アプリケーションを実行する準備ができました。Run をクリックすると、Eclipse コンソールにリスト 10 の出力が表示されるはずです。

リスト 10. コンソールの出力
INFO     2008-06-08 05:00:29,236 appcfg.py] Server: appengine.google.com
INFO     2008-06-08 05:00:29,283 appcfg.py] Checking for updates to the SDK.
WARNING  2008-06-08 05:00:29,581 datastore_file_stub.py] Could not read datastore data 
 from /var/folders/oo/ooKE4ln2HqC9exSMWxwprk+++TI/-Tmp-/dev_appserver.datastore
WARNING  2008-06-08 05:00:29,582 datastore_file_stub.py] Could not read datastore data 
 from /var/folders/oo/ooKE4ln2HqC9exSMWxwprk+++TI/-Tmp-/dev_appserver.datastore.history
INFO     2008-06-08 05:00:29,606 dev_appserver_main.py] Running application aggrogator 
 on port 8080: http://localhost:8080

この出力には、アプリケーションが http://localhost:8080 で実行中であることが示されています。以下のように、ブラウザーでこの場所にアクセスしてみてください。

図 7. aggroGator のウェルカム画面
aggroGator welcome screen
aggroGator welcome screen

Login をクリックすると、図 8 の画面が表示されます。

図 8. ログイン画面
Login screen
Login screen

もちろんこれは、偽のログイン画面です。Google 認証サービスに実際にアクセスすることにはならないため、どんな E メール・アドレスを使用しても構いません。実際、test@example.com というアドレスでもまったく問題ありません。ログインした時点から、サービスの追加を開始できます。

図 9. サービスの追加
サービスの追加
サービスの追加

ここからは、サービスを追加してアプリケーションをいろいろと試してみることができます。リスト 8 の AddService コントローラーをもう一度見ると、このクラスには、さまざまなサービスに対するフィードの URL がハード・コーディングされています。当然、この内容は将来変更される可能性があり、その場合にはエラーを受け取ることになります。そのような場合に重宝するのが、デバッガーです。次のセクションでは、この GAE プロジェクトで Eclipse デバッガーを使用する方法を説明します。

デバッグ方法

Eclipse のような IDE を使用する上での大きな利点は、複雑な Web アプリケーションでさえも、アプリケーションのデバッグが遥かに簡単になることです。GAE プロジェクトでデバッグを行うためには、まず Debug プロファイルを作成する必要があります。このプロファイルを作成するには、Run プロファイルと同じく、単にプロジェクトを選択し、Run > Open Debug ダイアログをクリックするだけです。

図 10. Debug ダイアログ
Debug ダイアログ
Debug ダイアログ

Eclipse の賢い機能により、このダイアログは前に作成した Run 設定にデフォルト設定されます。変更する必要はなく、単に Debug をクリックするのみです。Eclipse コンソールには、リスト 11 のような出力が表示されます。

リスト 11. デバッグの出力
pydev debugger: warning: psyco not available for debugger speedups
pydev debugger: starting
INFO     2008-06-08 05:18:37,704 appcfg.py] Server: appengine.google.com
INFO     2008-06-08 05:18:37,755 appcfg.py] Checking for updates to the SDK.
INFO     2008-06-08 05:18:38,196 dev_appserver_main.py] Running application aggrogator 
 on port 8080: http://localhost:8080

最初の 2 行に、pydev デバッガーからの出力が示されます。これで、プロジェクト内にブレーク・ポイントを設定してデバッグを開始することができます。図 11 でデバッグしているのは、AddService コントローラーです。

図 11. AddService のデバッグ
Debugging AddService
Debugging AddService

これで、コードをステップスルーして変数を検査できます。サービスのいずれかが変更された場合、あるいは新しいサービスを追加する必要がある場合には、この方法で簡単にバグを見つけて修正することができます。

まとめ

今回の記事では、アプリケーションの作成を一から始めて瞬く間に完成させました。Google App Engine SDK をインストールして Eclipse に接続したことによって、コードの作成、テスト、デバッグが簡単に行えるようになりました。この記事では、URL ルーティング、URL を取得することによる外部サイトとのやりとり、表示テンプレートの使用、そして Bigtable の操作をはじめ、GAE プロジェクトでの数々の重要な概念についても説明しました。サンプル・アプリケーションは GAE にデプロイする段階にまで来たので、第 2 回ではその方法を説明します。


ダウンロード可能なリソース


関連トピック


コメント

コメントを登録するにはサインインあるいは登録してください。

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Open source
ArticleID=337109
ArticleTitle=Google App Engine をベースに Eclipse を使用して作成するマッシュアップ: 第 1 回 アプリケーションを作成する
publish-date=08052008