目次


IBM Bluemix を利用して、クラウド内で投資追跡アプリケーションを作成してデプロイする: 第 1 回

オープン API を使用して金融データに接続し、必要なデータを取得する

Comments

この全 2 回からなる連載の第 1 回では、オープン API を使用して金融データに接続し、必要なデータを取得する方法を紹介します。モバイル対応のインターフェース・フレームワークを使用することで、アプリケーションはデスクトップ・コンピューター上でもモバイル端末上でも同じように有効に機能するようになります。さらにアプリケーションを IBM Bluemix 上にホストすることで、信頼性とスケーラビリティーが確保されます。第 2 回では、PHP アプリケーションの中でこの金融データを使用して、投資ポートフォリオを正確かつ即座に評価する方法を紹介します。

この連載で説明しているサンプル・アプリケーションは、ユーザーが株を検索して、オンライン投資ポートフォリオに 1 つ以上の株を追加するために使用することができます。

アプリケーションを作成するために必要となるもの

注: Google+ API を使用するアプリケーションは例外なく、「Google APIs Terms of Service」、「Google+ Platform Developer Policies」、「Google+ Platform Terms of Service」、および「Google プライバシー ポリシー」に従う必要があります。同様に、Quandl API を使用するアプリケーションはいずれも Quandl の「Terms of Use」に従わなければなりません。プロジェクトを開始する前に時間をとってこれらの要求事項を読んで、アプリケーションがすべての要求事項を満たすようにしてください。

サンプル・アプリを実行するアプリのコードを入手する

すべてのコードをダウンロードして試してください!

この連載で実装するすべてのコードは、今回使用する PHP ビルドパックの構成ファイルと併せて、GitHub リポジトリーからダウンロードすることができます。ぜひともコードを入手して、いろいろといじってみてください。また、新しい機能を追加するのも一考です。何も壊れることはありませんので、よい勉強になること請け合いです。お楽しみください!

オープン API によって幅広く金融データにアクセスできるようになっていると、その金融データを利用することにより、ユーザーが自分の金融面での状況を把握するのを支援するモバイル Web アプリケーションを作成するのは簡単です。

ステップ 1. アプリケーション・スタブを作成する

  1. 最初のステップでは、Silex PHP マイクロフレームワークを使用して基本的なアプリケーションを初期化します。それには、カレント・ディレクトリーを Web サーバーのドキュメント・ルート・ディレクトリー (一般に、Linux の場合は /usr/local/apache/htdocs、Windows の場合は C:\Program Files\Apache\htdocs) に変更し、アプリケーション用の新規ディレクトリーを作成します。
    shell> cd /usr/local/apache/htdocs
    shell> mkdir portfolio-tracker

    この新規ディレクトリーは、このチュートリアルを通して $APP_ROOT として参照します。このようになっていれば、アプリケーションには URL http://localhost/portfolio-tracker で直接アクセスすることができます。ただし、アプリケーションを Bluemix にデプロイした後は、アプリケーションの URL が変わることを頭に入れておいてください。

  2. 次に、Composer 構成ファイルを作成します。このファイルは $APP_ROOT/composer.json に保存します。
    {
        "require": {
            "silex/silex": "*",
            "twig/twig": "*",        
            "hybridauth/hybridauth": "2.*",
            "guzzlehttp/guzzle": "*"
        },
        "minimum-stability": "dev",
        "prefer-stable": true
    }
  3. 上記の Composer 構成ファイルは Silex、Twig、HybridAuth、Guzzl をインストールします。これらはいずれも、アプリケーションを作成するために必要なコンポーネントです。以下のように、Composer を使用して、これらのコンポーネントをダウンロードしてインストールします。
    shell> cd /usr/local/apache/htdocs/portfolio-tracker
    shell> php composer.phar install

ステップ 2. 基本的なユーザー・インターフェースを作成する

  1. このアプリケーションのインターフェースは、できる限りシンプルにする必要があるため、2 つの主要な画面で構成されるようにします。一方の画面ではユーザーが株を検索して追加できるようにし、もう一方の画面では、ユーザーがポートフォリオに含まれる各株の現在の株価を表示できるようにします。この構成に従った基本的なタブ付きインターフェースを、以下のコードによってセットアップします。このコードを $APP_ROOT/views/index.twig というファイルにコピーして保存してください。
    <!DOCTYPE html>
    <html>
      <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jquerymobile/1.4.5/jquery.mobile.min.css">
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
        <script src="https://ajax.googleapis.com/ajax/libs/jquerymobile/1.4.5/jquery.mobile.min.js"></script>    
        <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
      </head>
      <body>
    
        <div data-role="page">
    
          <div data-role="header">
            <h1>Portfolio Tracker</h1>
          </div>
    
          <div data-role="content">
            <div data-role="tabs">
            
              <div id="navbar" data-role="navbar">
                <ul>
                  <li><a id="tab-search" href="#search" data-theme="a" class="ui-btn-active">Search</a></li>
                  <li><a id="tab-manage" href="#manage" data-theme="a" class="">Manage</a></li>
                </ul>
              </div>
              
              <div id="search">
                <!-- search tab -->
              </div>
    
              <div id="manage">
                <!-- manager tab -->          
              </div>
    
            </div>        
          </div>
    
          <div data-role="footer">
          </div>
    
        </div>
          
      </body>
    </html>
  2. このページは、Google CDN にホストされている jQuery、jQuery Mobile、AngularJS をセットアップして、基本的な jQuery Mobile ページを定義します。上記のコードを見るとわかるように、このページには現在、ヘッダーと 2 つのタブ、そしてフッターが含まれています。2 つのタブは今のところ空ですが、このチュートリアルを進めていくと、どちらのタブもたちまちコンテンツで満たされることになります。サーバーでは、Silex が //index などの URL ルートに対するリクエストを検出すると、このテンプレートのレンダリングを行います。そのためのコードは以下のとおりです。このコードは、$APP_ROOT/index.php に保存する必要があります。
    <?php
    // use Composer autoloader
    require 'vendor/autoload.php';
    
    // load classes
    use Silex\Application;
    
    // initialize Silex application
    $app = new Application();
    
    // register Twig template provider
    $app->register(new Silex\Provider\TwigServiceProvider(), array(
      'twig.path' => __DIR__.'/views',
    ));
    
    // register URL generator
    $app->register(new Silex\Provider\UrlGeneratorServiceProvider());
    
    // index page handlers
    $app->get('/', function () use ($app) {
      return $app->redirect($app["url_generator"]->generate('index') . '#search');
    });
    
    $app->get('/index', function () use ($app) {
      return $app['twig']->render('index.twig');
    })
    ->bind('index');
    
    $app->run();

    上記のスクリプトは、このアプリケーションのメイン制御スクリプトです。このスクリプトはまず、すべての必須クラスをロードして、新しい Silex アプリケーション・オブジェクトを初期化します。初期化プロセスの一環として、Twig テンプレート・エンジン、テンプレート・ディレクトリーの場所、および URL ジェネレーター・サービスもアプリケーションに登録されます。

    Silex は、HTTP メソッドとエンドポイントに対し、ルーター・コールバックを定義することで動作します。そのために必要なことは、該当するメソッド (例えば、GET リクエストの場合は get()、POST リクエストの場合は post()、等々) を呼び出すことのみです。そのメソッドの 1 番目の引数としては、突き合わせの対象となる URL ルートを渡し、2 番目の引数としては、関数を渡します。この関数では、受信されたリクエストの宛先が、メソッドに渡された URL ルートと一致したときに実行されるアクションを指定します。

    上記のコード・リストでは、/index ルートに対するルーター・コールバックをセットアップし、受信されたリクエストの宛先がこのルートと一致したときに呼び出される関数を定義しています。このスクリプトの /index コールバックで行っている処理は、メインとなるアプリケーション・ページの上記テンプレートをレンダリングすることだけです。このスクリプトは / ルート用のルーター・コールバックもセットアップします。このコールバックは /index ルートにリダイレクトするに過ぎません。注目すべき点は、Silex URL ジェネレーターを使用していることです。このジェネレーターは、サーバー上の現在のアプリケーション・パスを考慮した後、指定されたルートの正しい URL を自動的に生成します。

    Silex は、わかりやすい URL への URL リライティングを利用するので、この機会に、Web サーバーの URL リライティング・ルールを構成しておきましょう。最終的にはアプリケーションを Apache Web サーバーにデプロイするので、$APP_ROOT/.htaccess ファイルを作成して、以下の内容を含めます。

    <IfModule mod_rewrite.c>
        Options -MultiViews
        
        RewriteEngine On
        RewriteCond %{REQUEST_FILENAME} !-f
        RewriteRule ^ index.php [QSA,L]
    </IfModule>
  3. http://localhost/portfolio-tracker/index でアプリケーションにアクセスすると、前にセットアップした jQuery Mobile ページ・テンプレートが表示されるようになります。jQuery Mobile テンプレートのスクリーン・キャプチャー

ステップ 3. ユーザー認証を追加する

このアプリケーションは、それぞれに固有のポートフォリオを保有する複数のユーザーをサポートするように意図されています。これは、ユーザーがお互いのデータにアクセスできないよう、認証層で対策を取る必要があることを意味します。そこで最初に、その対策を講じることにします。

HybridAuth は、Facebook、Google+、LinkedIn、Twitter、その他多くの広範なソーシャル・ネットワークおよびサービスに対してユーザーを認証するために使用できる、オープンソースの PHP ライブラリーです。HybridAuth を使用すると、サービスでの認証および承認の核心部分が抽象化されるため、OAuth トランザクションとアクセス・トークンの複雑な部分に対処することなく、簡単にソーシャル・サインオンを PHP アプリケーションに追加できるようになります。このアプリケーションでは HybridAuth を使用して、ユーザーが Google+ に対して自身を認証できるようにすることで、ユーザー認証を単純化します。

  1. HybridAuth では認証に OAuth を使用するため、Web アプリケーションを Google に登録して、認証用の Google+ API にアプリケーションがアクセスできるようにする必要があります。それには、Google アカウントの資格情報を入力して Google にログインし、Google Developers Console にアクセスします。新規プロジェクトを作成してプロジェクト名を割り当てた後、そのプロジェクトの「APIs (API)」セクションで Google+ API へのアクセスを有効にします。Google+ API を示す画面のスクリーン・キャプチャー
    Google+ API を示す画面のスクリーン・キャプチャー
  2. 同じくプロジェクトのページで、このアプリケーション用として「Credentials (認証情報)」セクションに表示されている OAuth 2.0 のクライアント ID とシークレットを取得します。これらの値は HybridAuth に必要になるので、書き留めておいてください。
  3. OAuth のクライアント ID とシークレットを取得する際に、アプリケーションのリダイレクト URL を設定します。OAuth 認証プロセスが完了すると、Google は、この設定された URL にクライアント・ブラウザーをリダイレクトします。今のところはローカルで開発しているので、URL を localhost ドメインに設定し、その後に以下の特別なパスを続けます。
    /callback?hauth.done=Google
    つまり、例えば以下のような URL になります。
    http://localhost/portfolio-tracker/callback?hauth.done=Google.

    この特別な /callback ルートは、後ほどアプリケーション内で定義されます。アプリケーションを Bluemix にデプロイする段階になったら、リダイレクト URL を変更して該当する Bluemix ドメインを正しく反映させる必要があります。

    URL を示す画面のスクリーン・キャプチャー
    URL を示す画面のスクリーン・キャプチャー
  4. 準備はすべて終わったので、コードの作成に取り掛かります。まずは、アプリケーション内に HybridAuth を構成するために、以下の行を $APP_ROOT/index.php ファイルに追加します。
    <?php
    // use Composer autoloader
    require 'vendor/autoload.php';
    require 'config.php';
    
    // load classes
    use Symfony\Component\HttpFoundation\Request;
    use Symfony\Component\HttpFoundation\Response;
    use Silex\Application;
    
    // initialize Silex application
    $app = new Application();
    
    // load configuration from file
    $app->config = $config;
    
    // add configuration for HybridAuth
    $app->config['hybridauth']  = array(
      "base_url" => 'http://' . $_SERVER['HTTP_HOST'] . rtrim(dirname($_SERVER['SCRIPT_NAME']), '/') . '/callback',
      "providers" => array (
      "Google" => array (
        "enabled" => true,
        "keys" => array (
          "id" => $app->config['oauth_id'],
          "secret" => $app->config['oauth_secret']
        ),
        "scope" => "https://www.googleapis.com/auth/userinfo.email"
    )));
    
    // register Twig template provider
    $app->register(new Silex\Provider\TwigServiceProvider(), array(
      'twig.path' => __DIR__.'/views',
    ));
    
    // register URL generator
    $app->register(new Silex\Provider\UrlGeneratorServiceProvider());
    
    // start session
    session_start();
    
    // initialize HybridAuth client
    $auth = new Hybrid_Auth($app->config['hybridauth']);
    
    // other handlers – snipped!
    
    $app->run();
  5. 上記のコードは新しい HybridAuth クライアントを初期化します。この新規クライアントには、$auth オブジェクトを介してアクセスすることができます。OAuth のクライアント ID とシークレットは、既に前のステップでこのアプリケーション用に生成してあるので、この時点でこれらの認証情報を構成ファイルに追加する必要があります。この構成ファイルは、アプリケーションの構成情報を格納するのにもってこいの場所です。Quandl API キーとデータベース・アクセス資格情報も (後で) ここに格納します。構成ファイルの内容は、以下のようになります。
    <?php
    // config.php
    $config = [
      'quandl_key'    => 'YOUR-QUANDL-API-KEY',
      'oauth_id'      => 'YOUR-OAUTH-ID',
      'oauth_secret'  => 'YOUR-OAUTH-SECRET',
      'db_uri'        => 'YOUR-CLOUDANT-DB-URI',
      'db_name'       => 'YOUR-DB-NAME'
    ];

    このファイルを更新して、Google Developers Console から取得した OAuth クライアント ID とシークレットを反映してください。
  6. 次は、ログインとログアウトそれぞれのルートを、OAuth 認証に必要となる特別な /callback ルートと併せて以下のように追加します。
    <?php
    
    // application initialization and other routes – snipped!
    
    // login handler
    // check if authenticated against provider
    // retrieve user email address and save to session
    $app->get('/login', function () use ($app, $auth) {
      $google = $auth->authenticate("Google");
      $currentUser = $google->getUserProfile();
      $_SESSION['uid'] = $currentUser->email;
      return $app->redirect($app["url_generator"]->generate('index') . '#search');
    })
    ->bind('login');
    
    // logout handler
    // log out and display logout information page
    $app->get('/logout', function () use ($app, $auth) {
      $auth->logoutAllProviders();
      session_destroy();
      return $app['twig']->render('logout.twig');
    })
    ->before($authenticate);
    
    // OAuth callback handler
    $app->get('/callback', function () {
      return Hybrid_Endpoint::process();
    });
    
    $app->run();

このコードは、以下の 3 つの新規ルート・ハンドラーを追加します。

  • /login ルート・ハンドラーは前に初期化した HybridAuth クライアントの authenticate() メソッドを使用して、Google+ API に対してユーザーを認証します。ユーザーが認証されると、そのユーザーの基本プロファイル情報 (e-メール・アドレスを含む) が Google+ API から取得されて、$_SESSION['uid'] という名前のセッション変数に格納されます。このセッション変数は、データベースのレコードを保存または表示する際にユーザーのポートフォリオを識別するために使用されます。
  • /logout ルート・ハンドラーは HybridAuth クライアントの logoutAllProviders() メソッドを使用して、すべての OAuth プロバイダーとの接続を切断し、ユーザーをアプリケーションからログアウトさせます。ただし、注意すべき重要な点として、アプリケーションからログアウトしても、Google OAuth セッションはアクティブなままです。そのため /logout コールバックはさらに、接続されている Google アカウントからユーザーがログアウトされるようにするとともに OAuth トークンおよびセッションが完全に失効状態となるような追加オプションを提供する、ログアウト・ページをレンダリングします。このログアウト・ページ・テンプレートについては、アプリケーションのソース・コード・リポジトリーの $APP_ROOT/views/logout.twig で確認することができます。
  • /callback ルート・ハンドラーは、Google OAuth プロセッサーからのリダイレクトを処理するために使用されます。このエンドポイントに対するリクエストを扱う処理は、Hybrid_Endpoint::process() メソッドによって抽象化されます。

$_SESSION['uid'] 変数はユーザーが正常に認証された場合にしか存在しないことから、以下のコードに示すように、この変数を使用すれば、他のアプリケーションのルートへアクセスできないようにすることが可能です。

<?php
// register authentication middleware
$authenticate = function (Request $request, Application $app) use ($config) {
  if (!isset($_SESSION['uid'])) {
    return $app->redirect($app["url_generator"]->generate('login'));
  }    
};

上記の $authenticate 関数は Silex の「ミドルウェア」であり、リクエストが処理される前に自動的に実行されます。これは、before() メソッドを使用して、リクエストをそのリクエストに対応するルート・ハンドラーに関連付けることで実現しています。このようにすることで、アクセスを制限することが可能となり、認証済みユーザーのみがアプリケーションのさまざまなルートにリクエストを送信できるようになります。この仕組みを実現するために、セッション内で $_SESSION['uid'] 変数が存在するかどうかのチェックが行われます。存在しない場合は、ユーザーを /login にリダイレクトして再ログインを強制します。

ユーザーがログインに成功すると、そのユーザーの e-メール・アドレスが $_SESSION['uid'] 変数に格納されるので、この変数をページ・テンプレートの中で使用できるようになります。従って、例えばユーザーの e-メール・アドレスをメインのアプリケーション・インターフェースに表示するとしたら、/index ルート・ハンドラーに変更を加えた以下のコードに示すように、$_SESSION['uid'] 変数を index ページのテンプレートに渡すだけで表示できるようになります。

<?php

// application initialization and other routes – snipped!

$app->get('/index', function () use ($app) {
  $uid = $_SESSION['uid'];
  return $app['twig']->render('index.twig', array('uid' => $uid));
})
->before($authenticate)
->bind('index');

このルートに新たに関連付けられた before() メソッドは、前述の $authenticate ミドルウェアを実行することに注意してください。これにより、ユーザーが認証されてからでないと、index ページは表示されないようになります。

以下に更新後の index ページのテンプレートを記載します。更新後のテンプレートには、ログイン・ユーザーの e-メール・アドレスを表示するサブヘッダーと、/logout ルートを指す個別の「Sign out (サイン・アウト)」ボタンが追加されています。

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jquerymobile/1.4.5/jquery.mobile.min.css">
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/jquerymobile/1.4.5/jquery.mobile.min.js"></script>    
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
  </head>
  <body>

    <div data-role="page">

      <div data-role="header">
        <h1>Portfolio Tracker</h1>
        <a data-ajax="false" href="{{ app.request.basepath }}/logout" data-role="button" class="ui-btn-right">Sign out</a>
        <div class="ui-bar ui-bar-a" style="text-align: center">
          {{ uid }}
        </div>
      </div>

      <div data-role="content">
        <div data-role="tabs">
        
          <div id="navbar" data-role="navbar">
            <ul>
              <li><a id="tab-search" href="#search" data-theme="a" class="ui-btn-active">Search</a></li>
              <li><a id="tab-manage" href="#manage" data-theme="a" class="">Manage</a></li>
            </ul>
          </div>
          
          <div id="search">
            <!-- search tab -->
          </div>

          <div id="manage">
            <!-- manager tab -->          
          </div>

        </div>        
      </div>

      <div data-role="footer">
      </div>

    </div>
      
  </body>
</html>

更新後のテンプレートがどのように動作するかを確認するには、http://localhost/portfolio-tracker/index でアプリケーションの index ページをブラウズしてみてください。まず、Google アカウントにログインするよう促されます。ログインすると、自分のプロファイル情報へのアクセスをアプリケーションに許可するかどうかを尋ねられます。

Google ログイン・プロンプトを示す画面のスクリーン・キャプチャー
Google ログイン・プロンプトを示す画面のスクリーン・キャプチャー

アプリケーションがプロファイル情報にアクセスすることにユーザーが同意すると、OAuth プロセスが完了し、ユーザーはアプリケーションの index ページにリダイレクトされます。このページには、アカウントの e-メール・アドレスが表示され、ヘッダー・バーに「Sign out (サイン・アウト)」ボタンが表示されるようになっているはずです。以下に、このページの表示例を示します。

「Sign out (サイン・アウト)」ボタンを示す画面のスクリーン・キャプチャー
「Sign out (サイン・アウト)」ボタンを示す画面のスクリーン・キャプチャー

ステップ 4. Quandl API について理解する

次のステップでは、アプリケーションの検索インターフェースをセットアップします。この検索インターフェースの大半は、Quandl API によって駆動されます。

無料で使用できる Quandl API では、オープン金融データベースと有料の金融データベースの両方にアクセスすることができます。Quandl API は HTTP リクエストに対し、要求されたデータを格納した JSON レスポンスで応答します。返されたデータを構文解析すれば、サーバー・サイド・プログラミング言語 (PHP や Perl など) とクライアント・サイドのツール (jQuery や AngularJS など) の両方で使用することができます。

Quandl API は何千ものデータセットをサポートしていますが、このチュートリアルで必要となるのは無料の Wiki データセットのみです。このデータセットは、コミュニティーによって監督されている、米国企業 3,000 社の株価終値と配当額のリストです。このデータセットには無料でアクセスできますが、API キーがなければ、呼び出しは 1 日あたり 50 回未満に制限されます。登録して API キーを取得すると、1 日あたりの呼び出し回数は 50,000 にまで増えます。

すでに Quandl API アカウントにサインアップして有効な API キーを取得しているという前提で、IBM の株価情報を取得することによって、この API を試してみます。IBM の株価情報は、ブラウザーで https://www.quandl.com/api/v3/datasets/WIKI/IBM.json?api_key=[自分の API キー] にアクセスするだけで取得することができます (API キーのプレースホルダーは、忘れずに実際の API キーに置き換えてください)。以下のようなレスポンスが表示されるはずです。

IBM 株価情報の検索結果のスクリーン・キャプチャー
IBM 株価情報の検索結果のスクリーン・キャプチャー

上記の画像に示されているように、Quandl API はリクエストに対し、企業名、コード、固有 ID、株価の詳細を記載した JSON ドキュメントで応答します。株価の情報はデータ配列の中に編成されており、配列の各要素が単一の取引日を表しています。取引日ごとに提供される情報には、始値、高値、安値、終値、出来高、配当落ち価格などがあります。

もちろん、これはデータセットの 1 つに過ぎません。Quandl はこのようなデータセットを、無料のもの、営利目的のものを含め、数多く提供しています。例えば、インドの株式市場に興味があるとしたら、無料の NSE データセットを使用することができます。また、米国の利率を追跡したければ、無料の US Federal Reserve データセットを使用することができます。

また、特定のデータセットで、検索条件と一致する項目を検索することもできます。例えば、キーワード「inc」と一致するすべての株を検索するとします。その場合、URL として https://www.quandl.com/api/v2/datasets.json?api_key=[自分の API キー]&source_code=WIKI&query=inc にリクエストを送信すると、Wiki データベースが照会されて、以下のようにキーワード「inc」と一致するすべての株の情報が結果として返されます。

名前に「inc」が含まれる株の情報の検索結果のスクリーン・キャプチャー
名前に「inc」が含まれる株の情報の検索結果のスクリーン・キャプチャー

ステップ 5. 検索インターフェースを有効にする

  1. Quandl API がどのように機能するかがわかったところで、早速アプリケーションの作成を開始します。最初のステップは、基本的なページ・テンプレートを検索フォームで更新して、ユーザーが検索条件と一致する株の情報を検索できるようにすることです。$APP_ROOT/views/index.twig ページを、以下のような内容のコードで更新します。
    <!DOCTYPE html>
    <html>
      <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jquerymobile/1.4.5/jquery.mobile.min.css">
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
        <script src="https://ajax.googleapis.com/ajax/libs/jquerymobile/1.4.5/jquery.mobile.min.js"></script>    
        <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
      </head>
      <body>
    
        <div data-role="page">
    
          <div data-role="header">
            <h1>Portfolio Tracker</h1>
            <a data-ajax="false" href="{{ app.request.basepath }}/logout" data-role="button" class="ui-btn-right">Sign out</a>
            <div class="ui-bar ui-bar-a" style="text-align: center">
              {{ uid }}
            </div>
          </div>
    
          <div data-role="content">
            <div data-role="tabs">
            
              <div id="navbar" data-role="navbar">
                <ul>
                  <li><a id="tab-search" href="#search" data-theme="a" class="ui-btn-active">Search</a></li>
                  <li><a id="tab-manage" href="#manage" data-theme="a" class="">Manage</a></li>
                </ul>
              </div>
              
              <div id="search" ng-app="myApp" ng-controller="myAppController">
                <h2 class="ui-bar ui-bar-a">Stock Search</h2>
                <div class="ui-body">
                    <input type="search" name="query" ng-model="items.query" />
                    <button ng-click="search()">Search</button>
                </div>      
                <h2 class="ui-bar ui-bar-a">Search Results</h2>   
                <div class="ui-body">
                  <ul data-role="listview" data-split-theme="d">
                    <li ng-repeat="r in items.results">
                    {% verbatim %}
                      <a>{{r.name}}</a>
                    {% endverbatim %}
                      <a href="{{ app.request.basepath }}{% verbatim %}/add/{{r.code}}{% endverbatim %}" data-ajax="false" data-inline="true" data-role="button" data-icon="plus" data-theme="a">Add</a>                
                    </li>
                  </ul>                    
                </div>          
              </div>
    
              <div id="manage">
              </div>
    
            </div>        
          </div>
    
          <div data-role="footer">
          </div>
    
        </div>
          
      </body>
    </html>

    更新後のテンプレートでは、検索タブが myAppController という名前の AngularJS コントローラーにリンクされ、検索入力フィールドで items という名前の AngularJS モデルを使用していることに注目してください。「Search (検索)」ボタンをクリックすると、search() という AngularJS メソッドが呼び出されます。このメソッドの役目は、Ajax クエリーを実行することです。これにより、最終的にユーザーのクエリーと一致する株のリストが返されます。

    上記のテンプレートに含まれる ng-repeat ディレクティブは、クエリーによって返された株の情報を jQuery Mobile のリスト・ビューに合わせたフォーマットにし、それぞれの株の横に「Add (追加)」ボタンを追加してビューを完成させます。/add ルートにリンクされている「Add (追加)」ボタンにより、銘柄記号が URL に組み込まれます。Twig と AngularJS で変数を挿入する際には {{...}} 記号を使用することから、上記のテンプレートでも AngularJS プレースホルダーを明示的に識別するために Twig の {% verbatim %} タグを使用しています。

  2. 以上でテンプレートは完成です。次は、AngularJS コントローラーに取り掛かります。これによって、全体像が完成します。以下のコードを、$APP_ROOT/views/index.twig</head> 終了要素の前に追加してください。
     <script>      
      var myApp = angular.module('myApp', []);
      
      myApp.controller("myAppController", function ($scope, $http) {
        $scope.items = {};
        $scope.items.results = [];
        $scope.items.query = '';
        
        $scope.search = function() {
          if ($scope.items.query != '') {
            $http({
                method: 'GET',
                url: '{{ app.request.basepath }}/search/' + $scope.items.query,
              }).
              success(function(data) {
                $scope.items.results = data.docs;
              });
          } else {
            $scope.items.results = [];
          }
        };
      });
    </script>

AngularJS に馴染みが深ければ、上記のコードに極めて複雑な部分はないことが、すぐにわかるはずです。ユーザーが「Search (検索)」ボタンをクリックすると、search() コントローラー・メソッドが /search エンドポイントに対して Ajax クエリーを実行し、items モデルに結果を取り込みます。前述のとおり、ng-repeat ディレクティブは、jQuery Mobile リストを使用してこれらの結果をフォーマット設定したものを表示します。

注意すべき重要な点として、/search エンドポイントは Quandl API エンドポイントではなく、アプリケーション自体によって管理される仲介 API エンドポイントです。このエンドポイントは、以下に示すように、$APP_ROOT/index.php ファイル内で Silex コールバックとして定義されています。

<?php
// use Composer autoloader
require 'vendor/autoload.php';
require 'config.php';

// load classes
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\JsonResponse;
use Silex\Application;

// initialize application – snipped!

// initialize HTTP client
$guzzle = new GuzzleHttp\Client();

$app->get('/search/{query}', function ($query) use ($app, $guzzle) {
  // execute search on Quandl API
  // specify search scope and required response fields
  $response = $guzzle->get('https://www.quandl.com/api/v2/datasets.json?api_key=' . $app->config['quandl_key'] . '&source_code=WIKI&query='.urlencode($query));
  $result = $response->getBody();
  // remove unwanted trailing strings
  $result = str_replace(' Prices, Dividends, Splits and Trading Volume', '', $result);
  if ($result) {
    return new Response($result, Response::HTTP_OK, array('content-type' => 'application/json'));
  } else {
    return new Response(null, Response::HTTP_NOT_FOUND);  
  }
})
->before($authenticate);

$app->run();

AngularJS コントローラーによって送信された Ajax 検索リクエストは、/search コールバックによって処理されます。このコールバックは検索語を受け入れてから、Guzzle HTTP クライアントを使用して Quandl API に対するリクエスト URL を作成します (ステップ 4 を参照)。この URL から返されるレスポンスは、簡単に整えられた後 (不要な文字を削除するなど)、JSON ドキュメントとしてアプリケーションのフロント・エンドに返されます。すると、前に説明したように AngularJS がレスポンス・データをスコープにバインドします。

指摘するに値する点として、AngularJS を使用して、アプリケーションのフロント・エンドから直接 Ajax リクエストを実行することもできます。しかしその場合、個人の Quandl API アプリケーション・キーがエンド・ユーザーに公開されてしまうため、この方法は一般にアクセス可能なアプリケーションにはお勧めできません。アプリケーションではなくサーバー・サイドのスクリプトにリクエストを実行させると、ある程度のオーバーヘッドが追加されるものの、より強力なセキュリティーが実現されます。

  1. すべてのコードを追加したら、ブラウザーで再びアプリケーションにアクセスしてみてください。今度は、検索フォームが表示されて、検索フィールドに検索語を入力すると、一致する検索結果のリストが表示されるはずです。検索結果のそれぞれには、その結果に対応する固有の銘柄記号が示され、/add ルートにリンクされた「Add (追加)」ボタンが表示されます。株の情報の検索フォームのスクリーン・キャプチャー
    株の情報の検索フォームのスクリーン・キャプチャー

Conclusion

今回は、基本的なアプリケーションとユーザー・インターフェースを初期化する方法、Google+ API を使用して認証を有効にする方法、そしてそのアプリケーションを Quandl API に接続する方法を紹介しました。第 2 回では、投資ポートフォリオの詳細を保管し、Quandl API で取得したデータを使用してリアルタイムの評価レポートを生成する方法を紹介します。


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


関連トピック


コメント

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

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Cloud computing, Mobile development, Web development
ArticleID=1027457
ArticleTitle=IBM Bluemix を利用して、クラウド内で投資追跡アプリケーションを作成してデプロイする: 第 1 回
publish-date=02252016