0 follower

ウェブサービス

ウェブサービスとは ネットワーク越しに、マシン同士の相互運用性をサポートする仕組みのことです。 ウェブアプリケーションにおいては、多くの場合インターネットを介して、 リモートホストから呼び出して利用できるAPI群をウェブサービスと呼びます。

たとえば、Flex-basedクライアントはサーバで動いている、PHPのウェブアプリケーションに実装された関数を呼び出すことがあります。 ウェブサービスはコミュニケーションプロトコルスタックの基礎部分をSOAP に依存しています。

YiiはCWebServiceCWebServiceActionを提供することで、 ウェブアプリケーションでウェブサービスを提供する作業を簡単にします。 APIはサービスプロバイダと呼ばれるクラス群にまとめられます。 Yiiはそれぞれのクラスについて、WSDLスペックファイルを生成し、 どのAPIが利用可能で、どのように呼び出すことができるのかを記述します。

クライアントによってAPIが呼び出されると、Yiiが対応するサービスプロバイダをインスタンス化し、 要求されたAPIを実行することで、リクエストを完了します。

注意: CWebServicePHP SOAP extension に依存します。 このセクションの例を実行する前に拡張が有効になっていることを確認して下さい。

1. サービスプロバイダの定義

上で述べたように、サービスプロバイダとはリモートから呼び出し可能なメソッドを定義するクラスのことです。

Yiiはdoc commentclass reflection に基づいて、 どのメソッドがリモートから呼び出し可能であり、どのような引数をとり、そしてどのような返り値を返すのかを決定します。

まず単純な株価情報サービスからはじめましょう。 このサービスではクライアントが株価情報を要求できます。 サービスプロバイダを以下のほうに定義します。 プロバイダクラスのStockControllerを、 CControllerのサブクラスとして定義していることに注意してください。 これは必須ではありませんが、後ほどなぜこうするのか理由を説明します。

class StockController extends CController
{
    /**
     * @param string the symbol of the stock
     * @return float the stock price
     * @soap
     */
    public function getPrice($symbol)
    {
        $prices=array('IBM'=>100, 'GOOGLE'=>350);
        return isset($prices[$symbol])?$prices[$symbol]:0;
        //... $symbol の株価を返す
    }
}

上記の例では、getPriceというメソッドを宣言し、コメントに@soapタグをつけることで、 ウェブサービスAPIにしています。 コメントによって引数のデータタイプと返り値も決まります。 追加のAPIも同じ方法で宣言できます。

2. ウェブサービスアクションを定義する

サービスプロバイダを定義したので、クライアントから呼び出し可能にする必要があります。 今回の例では、コントローラのアクションをサービスとして公開したいと思います。 これはコントローラで、CWebServiceActionアクションを宣言することで容易に実現可能です。 サンプルコードではStockControllerに追加します。

class StockController extends CController
{
    public function actions()
    {
        return array(
            'quote'=>array(
                'class'=>'CWebServiceAction',
            ),
        );
    }
 
    /**
     * @param string the symbol of the stock
     * @return float the stock price
     * @soap
     */
    public function getPrice($symbol)
    {
        //...$symbol の株価を返す
    }
}

これがウェブサービスを作るのに必要なことすべてです! URL http://hostname/path/to/index.php?r=stock/quote にアクセスすれば、 今定義したウェブサービスのWSDLを表すXMLが表示されます。

ヒント: デフォルトでは、 CWebServiceAction はそのメソッドを含むコントローラを サービスプロバイダとみなします。これがgetPriceメソッドをStockControllerクラスに定義した理由です。

3. ウェブサービスを利用する

この例を完成させるために、できたばかりのウェブサービスを利用するクライアントを作ってみましょう。 例のクライアントはPHPで書かれていますが、Java, C#, Flexなどのその他の言語で書くこともできます。

$client=new SoapClient('http://hostname/path/to/index.php?r=stock/quote');
echo $client->getPrice('GOOGLE');

このスクリプトをブラウザか、コンソールで実行します。 結果として、GOOGLEの株価350が表示されます。

4. データ型

リモートから呼び出し可能なクラスメソッドとプロパティを定義する際に、 入出力パラメータのデータ型を決める必要があります。 以下のような基本データ型が利用可能です。

  • str/string: xsd:stringに対応します;
  • int/integer: xsd:intに対応します;
  • float/double: xsd:floatに対応します;
  • bool/boolean: xsd:booleanに対応します;
  • date: xsd:dateに対応します;
  • time: xsd:timeに対応します;
  • datetime: xsd:dateTimeに対応します;
  • array: xsd:stringに対応します;
  • object: xsd:structに対応します;
  • mixed: xsd:anyTypeに対応します.

上記の基本型に当てはまらない場合は、複数の属性からなる複合型とみなされます。 複合型はクラスで表されます。各属性はクラスのパブリックプロパティのうち、 コメントで@soapマークがついたものになります。

また、基本型や複合型の末尾に [] をつけることで配列を使うこともできます。 これは特定の型の配列を示します。

以下はPostオブジェクトの配列を返すgetPostsウェブAPIの例です。

class PostController extends CController
{
    /**
     * @return Post[] a list of posts
     * @soap
     */
    public function getPosts()
    {
        return Post::model()->findAll();
    }
}
 
class Post extends CActiveRecord
{
    /**
     * @var integer post ID
     * @soap
     */
    public $id;
    /**
     * @var string post title
     * @soap
     */
    public $title;
}

5. クラスの対応付け

複合型のデータをクライアントから受け取るためには、 WSDL型からPHPクラスへの対応を宣言する必要があります。 これはCWebServiceActionclassMapプロパティをを設定することで 実現されます。

class PostController extends CController
{
    public function actions()
    {
        return array(
            'service'=>array(
                'class'=>'CWebServiceAction',
                'classMap'=>array(
                    'Post'=>'Post',  // or simply 'Post'
                ),
            ),
        );
    }
    ......
}

6. リモート呼び出しを横取りする (Intercepting Remote Method Invocation)

サービスプロバイダで IWebServiceProvider インターフェイスを実装することで、 リモートからのメソッド呼び出しを、実行前に横取りすることができます。 IWebServiceProvider::beforeWebMethod内でプロバイダは CWebService のインスタンスをうけとり、 CWebService::methodNameによって、リクエストされたメソッド名を得ることができます。 何らかの理由でリモートからのメソッド呼び出しを許可したくない場合は、false を返すことで実行を中断できます。 (例:認証が必要なアクセス)