初心者向けの理論と実践のWebサービス

Webサービスとは何ですか?





まず、Webサービス(またはWebサービス)はテクノロジーです。 また、他の技術と同様に、かなり明確に定義されたアプリケーション環境を備えています。



ネットワークプロトコルのスタックのコンテキストでWebサービスを見ると、これは、古典的な場合、HTTPプロトコルを介した別のアドオンにすぎないことがわかります。



一方、仮にインターネットをいくつかの層に分割する場合、少なくとも2つの概念的なタイプのアプリケーション(非自明な機能を実装するコンピューティングノードとWebアプリケーションリソース)を区別できます。 さらに、後者は前者のサービスにしばしば関心を持っています。



しかし、インターネット自体は異種です。つまり、さまざまなネットワークノード上のさまざまなアプリケーションがさまざまなハードウェアおよびソフトウェアプラットフォームで動作し、さまざまなテクノロジと言語を使用しています。



これらすべてを接続し、1つのアプリケーションが他のアプリケーションとデータを交換する機会を提供するために、Webサービスが考案されました。



本質的に、Webサービスは、異なる言語で書かれているだけでなく、異なるネットワークノードに分散されている異なるアプリケーション間でデータを交換するための絶対に明確なインターフェースの実装です。



SOAのアイデアが進化したのはWebサービスの出現で、サービス指向アーキテクチャーでした。



Webサービスプロトコル





これまで、Webサービスを実装するための以下のプロトコルが最も広く使用されています。







実際、SOAPはXML-RPCから進化したものであり、開発の次のステップです。 RESTは、WWWの概念のコンテキストでのCRUD(作成、読み取り、更新、削除)オブジェクト操作理論に基づく新しい技術ではなく、アーキテクチャスタイルに基づく概念です。



もちろん、他のプロトコルも存在しますが、広く使用されていないため、SOAPとRESTの2つの主要なプロトコルに関するこの簡単なレビューで停止します。 XML-RPCは、それがいくぶん「時代遅れ」であるという事実を考慮して、詳細に検討しません。



私たちは主に、既存のWebサービスへのクライアントの実装ではなく、新しいWebサービスの作成の問題に関心を持っています(原則として、WebサービスプロバイダーはパッケージにAPI関数とドキュメントを提供するため、既存のWebサービス用のクライアントを構築するという問題は、著者の観点からはあまり興味がありません)。



SOAP vs REST





この対立の問題については、ポータルwww.citforum.ruにあるLeonid Chernyakの記事に 詳しく説明されています。



著者によると、次のことを簡単に強調できます。



SOAPは、オブジェクトとの相互作用がCRUD理論の範囲を超えている複雑なアーキテクチャでより適用可能ですが、この理論のフレームワークを離れないアプリケーションでは、RESTはその単純さと透明性のために非常に適用可能になることがあります。 実際、サービスのオブジェクトが、「作成」、「読み取り」、「変更」、「削除」を除いて、より複雑な関係を必要としない場合(原則として、これは99%のケースで十分です)、RESTが正しい選択になる可能性があります。 さらに、RESTは、サーバーで複雑なXMLコマンドを解析するコストを必要としないため、SOAPと比較して生産性が向上する場合があります(通常のHTTP要求-PUT、GET、POST、DELETEが実行されます)。 一方、SOAPはより信頼性が高く安全です。



いずれにせよ、どちらがアプリケーションに適しているかを決定します。 サービスのユーザーに選択を任せるために両方のプロトコルを実装したいと思うこともありますが、それはあなたの権利です。



Webサービスの実用化





これは実用的なアプリケーションであるため、Webサービスを構築するためのプラットフォームを選択し、タスクを設定する必要があります。 著者はPHP 5に最も近いため、サービスを構築するためのテクノロジーとして選択し、タスクとして次の要件を受け入れます。



アプリケーションによって収集され、データベースに蓄積される為替レートに関する情報へのアクセスを提供するサービスを作成する必要があるとします。 さらに、Webサービスを介して、この情報はサードパーティのアプリケーションに送信され、サードパーティのアプリケーションに便利な形式で表示されます。



ご覧のとおり、タスクは非常に単純であり、サービス自体の観点からは、情報の読み取りのみに制限されていますが、実用的な目的のためにはこれで十分です。



ステージ1-為替レートに関する情報を収集するためのアプリケーションの実装。





NBU(ウクライナ国立銀行)のWebサイトのページから為替レートに関する情報を毎日収集し、MySQL DBMSの管理下にあるデータベースに格納します。



データ構造を作成します。



通貨表(通貨):



  + ------------- + ------------------ +
 | フィールド| タイプ|
 + ------------- + ------------------ +
 | コード|  int(10)符号なし|
 | 文字コード|  char(3)|
 | 説明|  varchar(100)|
 | 値|  int(10)符号なし|
 | ベース|  tinyint(1)|
 + ------------- + ------------------ + 




両替表:



  + ------------ + ------------------ +
 | フィールド| タイプ|
 + ------------ + ------------------ +
 |  id |  bigint(20)ai |
 |  rate_date | タイムスタンプ|
 |  rate_value | フロート|
 | コード|  int(10)符号なし|
 + ------------ + ------------------ + 




データベースを操作するために、 PHP Doctrineパッケージに基づいたORMレイヤーを使用します。 グラバーを実現します。



Grubberクラス(models / Grabber.php):



  <?php
 / *
  * @package Currency_Service
  * /
クラスGrabber {

     / **
      *外部Webリソースからデータを抽出して返します
      *
      * @param void
      * @return配列
      * /
     public static function getData(){
         / **
          *外部Webリソースからのデータの抽出
          * /
         $ content = file_get_contents( 'http://www.bank.gov.ua/Fin_ryn/OF_KURS/Currency/FindByDate.aspx');
         if(preg_match_all( '/(\ d +)<\ / td>([AZ] +)<\ / td>(\ d +)<\ / td>(。+?)<\ / td>(\ d + \。 \ d +)<\ / td> / i '、$ content、$ m)== false){
            新しい例外をスロー(「データを解析できません!」);
         }

         / **
          *返されるデータの事前フォーマット。
          * /
         $ data = array();
         foreach($ m [1] as $ k => $ code){
             $データ[] =配列(
                 'code' => $ code、
                 'charcode' => $ m [2] [$ k]、
                 '値' => $ m [3] [$ k]、
                 '説明' => $ m [4] [$ k]、
                 'rate_value' => $ m [5] [$ k]
             );
         }
         $データを返します。
     }

     public static function run(){
         $ data = self :: getData();

         / **
          *存在しない場合はデフォルトの通貨を設定します
          * /
         if(!Doctrine :: getTable( 'Currency')-> find(980)){
             $通貨=新しい通貨();
             $通貨-> setCode(980)
                      -> setCharcode( 'UAH')
                      -> setDescription( 'ウクライナグリブナ')
                      -> setValue(1)
                      -> setBase(1)
                      ->保存();
         }

         foreach($ currencyDataとしての$データ){
             / **
              *見つかった値で通貨表を更新する
              * /
             if(!Doctrine :: getTable( 'Currency')-> find($ currencyData ['code'])){
                 $通貨=新しい通貨();
                 $ currency-> setCode($ currencyData ['code'])
                          -> setCharcode($ currencyData ['charcode'])
                          -> setDescription($ currencyData ['description'])
                          -> setValue($ currencyData ['value'])
                          -> setBase(0)
                          ->保存();
             }

             / **
              *為替レートの更新
              * /
             $ date = date( 'Ymd 00:00:00');
             $ exchange = new Exchange();
             $ exchange-> setRateDate($ date)
                      -> setRateValue($ currencyData ['rate_value'])
                      -> setCode($ currencyData ['code'])
                      ->保存();
         }

     }
 }
 ?> 




グラバー自体(grabber.php):



  <?php
 require_once( 'config.php');
 Doctrine :: loadModels( 'models');
グラバー::実行();
 ?> 




次に、グラバー開始コマンドをcronテーブルに追加して、グラバーを1日1回午前10:00に動作させるようにします。



  0 10 * * * / usr / bin / php /path/to/grabber.php 




それだけです-かなり便利なサービスがあります。



現在、他のアプリケーションがデータベースからデータを取得できるようにするWebサービスを実装しています。



SOAPサービスの実装





SOAPプロトコルに基づいてWebサービスを実装するには、SOAPを操作するためにPHPの組み込みパッケージを使用します。



Webサービスは公開されるため、Webサービスの構造を説明するWSDLファイルを作成することをお勧めします。



WSDL(Webサービス定義言語)-特定の形式のXMLファイルです。 ここで構文の詳細な説明を見つけることができます



実際には、 Zend Studio for Eclipse IDEが提供する自動ファイル生成機能を使用すると便利です。 この関数を使用すると、PHPクラスからWSDLファイルを生成できます。 したがって、まず、サービスの機能を実装するクラスを作成する必要があります。



CurrencyExchangeクラス(models / CurrencyExchange.php):



  <?php
 / **
  *必要なすべてのメソッドを備えたWebサービスを提供するクラス
  *為替レートに関する情報を提供するため
  *
  * @package Currency_Service
  * /
クラスCurrencyExchange {

     / **
      *特定の通貨の交換価値を取得します
      *
      * @param integer $ code-通貨コード
      * @param string $ data-為替レートの日付
      * @return float-レート値
      * /
    パブリック関数getExchange($コード、$日付){
         $通貨= Doctrine :: getTable( '通貨')->検索($コード);
         $ exchange = $ currency-> getExchange($ date);
         $交換を返しますか?  (フロート)$ exchange-> getRateValue():null;
     }

     / **
      *利用可能なすべての通貨を取得します
      *
      * @return array-利用可能なすべての通貨のリスト
      * /
    パブリック関数getCurrencyList(){
         return Doctrine :: getTable( 'Currency')-> findAll()-> toArray();
     }

 }
 ?> 




WSDLの自動生成では、受け入れられた引数と戻り値のタイプに関する情報を規定しているので、javadocスタイルでコメントを記述する必要があることに注意してください。 また、メソッドの操作を簡単に説明すると便利です。WSDLは、Webサービスを使用するサードパーティ開発者向けのAPIの説明として機能します。



docブロックにparam voidを書いたり、voidを返さないでください。これはWSDLにとって重要ではありませんが、同じクラスにRESTアクセスを実装すると、問題が発生します。




Zend Studioで、[ファイル]-> [エクスポート]メニューに移動し、PHP-> WSDLを選択し、クラスを追加し、サービスのURIを登録して、WSDLファイルを作成します。 結果は次のようになります。http//mikhailstadnik.com/ctws/currency.wsdl



Webサービスに新しい機能を追加する場合、WSDLファイルを再作成する必要があります。 しかし、ここでは事態はそれほどスムーズではありません。 既にWSDLファイルを要求しているSOAPクライアントは、その側でそれをキャッシュすることに注意してください。 したがって、WSDLファイル内の古いコンテンツを新しいコンテンツで置き換えると、一部のクライアントはそれを読み取れません。 そのため、新しい機能を追加するときは、ファイルの名前にバージョンを追加してください。 また、特に顧客でない場合は、古い顧客に下位互換性を提供することを忘れないでください。



一方、WSDLはWebサービスの構造をかなり厳密に定義します。つまり、サーバーに比べてクライアントの機能を制限する必要がある場合、クラスの特定のメソッドをWSDLに含めることはできません。 したがって、存在していても呼び出すことはできません。



サーバー自体の実装は現在、複雑さを示していません。



index.phpファイル:



  <?php
 require_once( 'config.php');

 Doctrine :: loadModels( 'models');

 $ server = new SoapServer( 'http://mikhailstadnik.com/ctws/currency.wsdl');
 $ server-> setClass( 'CurrencyExchange');
 $ server->ハンドル();
 ?> 




職場でWebサービスを試すことができます: http : //mikhailstadnik.com/ctws/

テストクライアントも利用できます: http : //mikhailstadnik.com/ctws/client.php



最も簡単なクライアントコードは次のとおりです。



  <?php
 $ client = new SoapClient( 'http://mikhailstadnik.com/ctws/currency.wsdl');
 echo 'USD exchange:'。  $ client-> getExchange(840、date( 'Ym-d'));
 ?> 




RESTサービスの実装





RESTは標準でも仕様でもありませんが、HTTP、URI(Uniform Resource Identifier)、XMLおよびRDF(Resource Description Format)などの既存のW3Cコンソーシアム標準によって制御されている既存のよく知られた上に構築されたアーキテクチャスタイルです。 RESTサービスでは、リモートサービスの実行ではなく、リソースへのアクセスに重点が置かれています。 これは、SOAPサービスとの根本的な違いです。



それでも、リモートプロシージャコールはRESTにも適用できます。 オブジェクトの操作には、PUT、GET、POST、DELETE HTTPプロトコルのメソッドを使用します。 SOAPとの基本的な違いは、RESTはHTTPリクエストのままであるということです。



PHPにはまだREST実装がないため、 Rend ClientとREST Northの両方の実装を含むZend Framworkを使用します。



既製のCurrencyExchangeクラスを使用します。 サーバー自体を書きましょう:



rest.php:



  <?php
 require_once 'config.php';
 require_once 'Zend / Rest / Server.php';

 Doctrine :: loadModels( 'models');

 $ server = new Zend_Rest_Server();
 $ server-> setClass( 'CurrencyExchange');
 $ server->ハンドル();
 ?> 




ご覧のとおり、すべてが非常に似ており、シンプルです。



ただし、RESTサービスは、SOAPサービスよりも安全性が低いことに注意してください。CurrencyExchangeクラスに追加されたメソッドは、呼び出されたときに機能します(クラス自体がサービスの構造を決定します)。



サービスの動作を確認してください。 これを行うには、GETリクエストの期間にメソッド呼び出しのパラメーターを渡すだけで十分です。



  ?メソッド= getExchange&コード= 840&日付= 2008-11-29 




または



  ?method = getExchange&arg1 = 840&arg2 = 2008-11-29 




必要または必要に応じて、RESTサービスのXML応答の構造を自己定義できます。 この場合、XMLドキュメントのタイプ定義(DTD-ドキュメントタイプ定義)の作成にも注意する必要があります。 これは、サービスの最小限のAPI記述になります。



この場合、RESTサービスの最も簡単なテストクライアントは次のようになります。



  <?php
 $ client = new Zend_Rest_Client( 'http://mikhailstadnik.com/ctws/rest.php');
 $ result = $ client-> getExchange(840、date( 'Ym-d'))-> get();
 if($ result-> isSuccess()){
     echo 'USD exchange:'。  $ result-> response;
 }
 ?> 




原則として、今日のZend_RestはRESTの原則の最も正確な実装とは言えません。 誇張して言うと、この実装はリモートプロシージャコール(RPC)に帰着したと言えますが、RESTの考え方はもっと広範です。



PHP DoctrineおよびZend Framework(4.42 Mb)からソースコードの例ダウンロードできます



おわりに





最小限のタスクを完了し、Webサービスとは何か、なぜ必要なのか、それらを実装する方法を示しました。 当然のことながら、与えられた例は人生から幾分離婚しているかもしれませんが、ウェブサービスの主題と本質を説明するためのツールとしてのみ選ばれました。



さらに、最新のツールを使用する場合、Webサービスの実装は非常に簡単なタスクであり、低レベルのプロトコル実装を心配することなく、まずサービス自体の機能の開発に集中できることがわかりました。



著者は、この資料がWebサービスの開発の道にいる人たちにとって本当に役立つことを望んでいます。



開発に頑張ってください!



All Articles