Yiinitializr AdvancedでAPIを機能させる方法





Yiinitializrのような興味深いツールに関する前回の投稿の続きで Advancedテンプレートが提供するAPI機能に関する質問に答えることにしました。 解説の一部または前の記事への追加段落として、資料を収容できなかったため、このトピックに興味のあるすべての人を猫に招待します。 その中で、正しいAPIアーキテクチャの設計の原則については触れませんが、 2amigosの人たちの仕事をどのように活用するかを理解します。



YiinitializrでAPIの操作を実装する方法



API-外部ソフトウェア製品で使用するために使用されるアプリケーションプログラミングインターフェイス。 他の開発者が自分のプロジェクトでアプリケーションの機能を利用できるようにしたい場合は、適切に設計されたAPIなしではできません。 残念ながら、最初のバージョンのYiiはこの問題を解決できません。 Yiinitializrはおそらくあなたに合うでしょう。これはいくつかの問題を解決しますが、私たちが知っているように、ドキュメントの欠如は深刻な障害です。



すばらしいアプリケーションの作業が完了し、APIの作業が確立され、システムを利用したい最初の開発者がすでに登場していることを想像してください。 その使用はどの原則に基づいていますか?



システムは、公開キー(外部アプリケーションの識別子)、秘密キー、およびこれらのキーが予約されているユーザーを生成し、データベースに保存します。 登録は終了しました。 APIユーザーとシステムとの対話は、RESTの原則に基づいています。 ユーザーアプリケーションは、特定のHTTPメソッドを使用してシステムにリクエストを送信します。このメソッドには、公開キー付きのHTTPヘッダーと、署名とその有効期限、およびさまざまな追加パラメーターを含むJSON形式のメッセージが含まれます。 要求を処理し、それが正しいことを確認すると、システムは応答を返します。



高度なテンプレートの違い



以前に中間テンプレートについて話していた場合、高度なテンプレートに追加されたものを見てみましょう。 既に理解しているように、それが提供する追加機能はすべてAPIに関連しています。 ダウンロードして解凍し、。 ./api



ディレクトリ./api



移動して、現在の内容を確認します。 そして、私たちは:



./api/extensions/filters/EApiAccessControlFilter.php



アクセスルールをチェックするためのフィルタークラス。

./api/extensions/components/EApiAccessRule.php



アクセスルールを表すクラス。

./api/extensions/components/EApiActiveRecord.php



を使用してARモデルを操作する補助メソッドのクラス。

./api/extensions/components/EApiController.php



リクエストを処理するためのコントローラークラス。

./api/extensions/components/EApiError.php



ログを読みやすくするために存在するAPIエラークラス。

./api/extensions/components/EApiErrorHandler.php



エラーを処理するためのクラス。 データベースにエラーを記録することにした場合、この特定のクラスを使用します。

./api/models/ApiUser.php



は、APIの外部ユーザーを管理するモデルの例です。

./common/lib/YiiRestTools/



APIの機能のためのヘルパークラス。



この一般的な情報は、APIを介してサードパーティアプリケーションとシステムとの対話を直接実装するのに十分です。



構成とバグ修正



Yiinitializrの開発者は明らかにパレートの原則を順守しており、作業の80%を完了した後、ドキュメントとバグの修正に80%の時間を費やさないことを決定し、これを洗練された開発者(つまり私たち)の肩にかけました。



Yiinitializrをセットアップすることを決めたので、もちろん設定ファイルに興味があります。 それを開いて、APIルーティングのルール( ./api/config/api.php



)を見てみましょう:



 'rules' => array( // REST patterns array('<controller>/index', 'pattern' => 'api/<controller:\w+>', 'verb' => 'POST'), array('<controller>/view', 'pattern' => 'api/<controller:\w+>/view', 'verb' => 'POST'), array('<controller>/update', 'pattern' => 'api/<controller:\w+>/update', 'verb' => 'PUT'), array('<controller>/delete', 'pattern' => 'api/<controller:\w+>/delete', 'verb' => 'DELETE'), array('<controller>/create', 'pattern' => 'api/<controller:\w+>/create', 'verb' => 'POST'), ),
      
      





理解できないものが見えます。 このコメントは、これがRESTテンプレートであることを示していますが、実際にはそうではありません。 RESTは、すべてのリクエストが単一のURLに送信され、アクションがHTTPメソッドとリクエストパラメータに基づいて選択されることを前提としています。つまり、次のようになります。

住所 HTTPメソッド トリガーアクション
api.yiinitializr.dev/test/ ゲット TestController \ actionIndex()
api.yiinitializr.dev/test/1/ ゲット TestController \ actionView(1)
api.yiinitializr.dev/test/ 投稿 TestController \ actionCreate()
api.yiinitializr.dev/test/1/ 置く TestController \ actionUpdate(1)
api.yiinitializr.dev/test/1/ 削除 TestController \ actionDelete(1)


ルールを目的の形式にします。



 'rules' => array( // REST patterns array('<controller>/index', 'pattern' => '<controller:\w+>', 'verb' => 'GET'), array('<controller>/view', 'pattern' => '<controller:\w+>/<id:\d+>', 'verb' => 'GET'), array('<controller>/update', 'pattern' => '<controller:\w+>/<id:\d+>', 'verb' => 'PUT'), array('<controller>/delete', 'pattern' => '<controller:\w+>/<id:\d+>', 'verb' => 'DELETE'), array('<controller>/create', 'pattern' => '<controller:\w+>', 'verb' => 'POST'), ),
      
      





構成ファイルには、現在のステージにとって本当に重要なものはないので、他の問題に進みます。 最初の解決策は絶対に簡単です-ポータブル



 use YiiRestTools\Helpers\RequestData; use Yiinitializr\Helpers\ArrayX;
      
      





これらのクラスは2番目のファイルで使用されるEApiAccessRule.php



EApiAccessRule.php



からEApiAccessControlFilter.php



へ。



次の問題はすでに興味深いものです。 おそらく私は何かを理解していなかったので、一緒に推論することを提案します。 以下のコード( ./api/extensions/components/EApiAccessRule.php



)をよく見てください:



 public function isRequestAllowed($user, $controller, $action, $ip, $verb) { if ($this->isActionMatched($action) && $this->isUserMatched(Yii::app()->user) && $this->isRoleMatched(Yii::app()->user) && $this->isSignatureMatched($user) && $this->isIpMatched($ip) && $this->isVerbMatched($verb) && $this->isControllerMatched($controller) ) { return $this->allow ? 1 : -1; } else { return 0; } }
      
      





isRequestAllowed



メソッドは、リクエストがルールに一致するかどうisRequestAllowed



チェックします。 ifブロックのチェックチェーンがtrueの場合、このルールが適用され、このルールの機能に応じて1または-1が返されます-許可または拒否されます。 それ以外の場合、このルールは特定のリクエストに適用されず、メソッドは0を返します。より明確にするために、フィルターのルールがどのように見えるかを思い出します。



 public function filters() { return array( array( 'EApiAccessControlFilter -error', 'rules' => array( array('allow', 'users' => array('@')), ) ) ); }
      
      





$this->isSignatureMatched($user)



は、このチェーンの署名検証$this->isSignatureMatched($user)



です。 間違った署名を受け取ると、システムはこのルールが適用できないと判断し、それに応じてユーザー(またはハッカー)を内部に渡します。 ほとんどの場合、署名の検証は正しい要求で行われるべきであり、その結果によって、システムに入れられるか入れられないかが決まります。 したがって、このメソッドをわずかに変更する必要があります。



 public function isRequestAllowed($user, $controller, $action, $ip, $verb) { if ($this->isActionMatched($action) && $this->isUserMatched(Yii::app()->user) && $this->isRoleMatched(Yii::app()->user) && $this->isIpMatched($ip) && $this->isVerbMatched($verb) && $this->isControllerMatched($controller) ) { return ($this->allow && $this->isSignatureMatched($user)) ? 1 : -1; } else { return 0; } }
      
      





欠陥は終わったようです。 ドキュメントの欠如が影響します。 ステップバイステップデバッガーの助けを借りて、APIクラス間の相互作用のメカニズムを研究し、あなたと観察を共有することを急いでいます。



開始するには、 グレートガイドの説明に従って基本設定を行います。 次に、公開キーを送信する構成( ./api/config/api.php



)でHTTPヘッダーの名前を定義します。



 'params' => array( 'api.key.name' => 'APIKEY', )
      
      





正しいタイムゾーンを設定することを忘れないでください(システムとクライアントアプリケーションで同じである必要があります)( common/config/main.php



):



 'params' => array( ... 'php.timezone' => 'Europe/Moscow', ),
      
      





Composerからインストールを開始します。 すでに可能です。

次に、APIをテストするために、外部ユーザーを登録する必要があります。 新しい移行を作成します。



 > yiic migrate create create_api_user_table
      
      





そして、メソッドをup()



down()



次の形式にします:



 public function up() { $this->createTable('{{api_user}}', array( 'id' => 'pk', 'username' => 'varchar(32) NOT NULL', 'api_key' => 'varchar(32) NOT NULL', 'api_secret' => 'varchar(32) NOT NULL', )); $this->insert('{{api_user}}', array( 'username' => 'test_user', 'api_key' => 'e4afe26b5b57083f74b2d01c7066379c', // md5('public_key') 'api_secret' => '156a17333e77a3c504018cae5ada8c3b', // md5('private_key') )); } public function down() { $this->dropTable('{{api_user}}'); }
      
      





また、 ApiUser



モデルでAPIのユーザーを含むテーブルの名前を編集します。



 class ApiUser extends EApiActiveRecord { ... public function tableName() { return '{{api_user}}'; } ... }
      
      





移行を適用します。 結果は、APIの唯一の仮想ユーザーを持つデータベース内のテーブルになります。 続けましょう。



シンプルなクライアントアプリケーションの作成



最後のステップは、Yiinitializr APIを操作するための簡単なクライアントアプリケーションを作成することです。 動作するには、さまざまなHTTPメソッドを使用してリクエストを送信できる必要があります。cURLライブラリはこれを支援します。 さらに苦労せずに、すべてのコードはネタバレのためにレイアウトされています。 開いて、見て、コピーしてください。



SimpleClientクライアントクラス
署名をgenerateSignature()



メソッドは、 RequestData



ライブラリのprepareData($secretKey)



クラスのprepareData($secretKey)



メソッドにRequestData



ます。



 /** * Class SimpleClient * * Simple REST-client for Yiinitializr Advanced API. */ class SimpleClient { private $baseUrl; private $apiPublic; private $apiSecret; private $expiration; public function __construct($url, $publicKey, $secretKey, $expiration = '+1 hour') { $this->baseUrl = $url; $this->apiPublic = $publicKey; $this->apiSecret = $secretKey; $this->expiration = $expiration; } public function makeRequest($verb, $controller, $params = array()) { $ch = curl_init(); $signature = $this->generateSignature(); $url = $this->makeUrl($controller); if (!empty($params) && isset($params['id'])) { $url .= $params['id']; } curl_setopt_array($ch, array( CURLOPT_URL => $url, CURLOPT_CUSTOMREQUEST => $verb, CURLOPT_HTTPHEADER => array('APIKEY: ' . $this->apiPublic), CURLOPT_POSTFIELDS => json_encode(array( 'signature' => $signature, 'expiration' => $this->relativeTimeToAbsolute($this->expiration), )), )); $result = curl_exec($ch); curl_close($ch); return $result; } private function generateSignature() { $ttdInt = strtotime($this->expiration); $raw = json_encode(array('expiration' => gmdate('Ymd\TH:i:s\Z', $ttdInt))); $jsonPolicy64 = base64_encode($raw); $signature = base64_encode(hash_hmac( 'sha1', $jsonPolicy64, $this->apiSecret, true )); return $signature; } private function makeUrl($controller) { return 'http://' . rtrim($this->baseUrl, '/') . '/' . $controller . '/'; } private function relativeTimeToAbsolute ($relativeTime) { return date('M d Y, H:i:s', strtotime($relativeTime)); } }
      
      







SimpleClientクラスの使用
 $api = new SimpleClient('api.yiinitializr.dev', 'e4afe26b5b57083f74b2d01c7066379c', '156a17333e77a3c504018cae5ada8c3b'); $api->makeRequest('GET', 'test'); $api->makeRequest('GET', 'test', array('id' => 1)); $api->makeRequest('POST', 'test'); $api->makeRequest('PUT', 'test', array('id' => 1)); $api->makeRequest('DELETE', 'test', array('id' => 1));
      
      







テストコントローラーの修正バージョン
 class TestController extends EApiController { public function actionIndex() { // just drop API request :) $this->renderJson(array('response' => 'index')); } public function actionView($id) { $this->renderJson(array('response' => 'view#' . $id)); } public function actionCreate() { $this->renderJson(array('response' => 'created')); } public function actionUpdate($id) { $this->renderJson(array('response' => 'updated#' . $id)); } public function actionDelete($id) { $this->renderJson(array('response' => 'deleted#' . $id)); } }
      
      







Apacheを構成する
ApacheがPUTおよびDELETEリクエストのブロックを停止するには、。 ./api/www/.htaccess



ファイルに次の行を追加する必要があります。



 <Limit GET POST PUT DELETE> order deny,allow allow from all </Limit>
      
      





ここで決定が下されます



まとめると



このような単純な方法で、私たちは車を始動させました。 何が何であるかを理解するために、私は1日以上(2ではなく)過ごす必要がありました。 いずれにせよ、そのようなソリューションは、この問題に関する深い知識がなくても高品質のAPIを作成することがはるかに簡単であることに基づいて、開始位置として非常に適切です。 追加のリンクのうち、 Yiinitializrすばらしいガイド (まだやっていない?)YiiのREST APIの作成方法 (英語) をご覧になることをお勧めします。



コメントでは、YiiでのAPIの実装に関するあなたの考えを共有し、この方法を批判し、改善を提案することを提案します。 ご清聴ありがとうございました。



All Articles