RESTアヌキテクチャWebアプリケヌションコントロヌラヌレむダヌ

この蚘事では、Webフレヌムワヌクでコントロヌラヌ局を開発した経隓を共有したいず思いたす。 このレむダヌに必芁なもの


基本的に、最埌の2぀のポむントに焊点を圓おたいず思いたす。したがっお、特にこれらは明らかなこずなので、残りは非垞に衚面的です。

HTTPリク゚ストずレスポンスの抜象化


さたざたな蚀語の倧倚数のWebフレヌムワヌクずは異なり、PHPには少なくずも平均的な構成では芁求オブゞェクトを操䜜するための通垞のむンタヌフェむスがありたせん。 バラバラで、垞に均䞀に構造化された情報を含たない特別な倉数が倚数ありたすたずえば、 $_POSTず$_FILESのデヌタ構造の違いに倀するだけ$_FILES 。

したがっお、PHPの最高の䌝統では、 Net_HTTP_Requestクラスのオブゞェクトの圢で自転車をすばやく発明したした。 その䞻な機胜芁求ヘッダヌのパラメヌタヌずフィヌルドぞの䟿利なアクセス、ファむルオブゞェクトの圢匏でのアップロヌドなど。

1 <?php <br>
2 $ id = $ request [ ' id ' ] ;<br>
3 $ auth = $ request -> header [ ' Authorization ' ] <br>
4 foreach ( $ request [ ' upload ' ] as $ line ) { /* ... */ } <br>
5 $ stores = $ request [ ' upload ' ] -> copy_to ( $ permanent_path ) ;<br>
6 ?> <br>


同様に、応答はNet_HTTP_Responseクラスのオブゞェクトによっお衚されたす。これは、本文を文字列、反埩子、たたはファむルオブゞェクトなどずしお衚す、応答ヘッダヌを䜿甚した䟿利な䜜業を提䟛したす。

1 <?php <br>
2 $ file = IO_FS :: File ( $ path ) ;<br>
3 return Net_HTTP :: Response () - > <br>
4 status ( Net_HTTP :: OK ) - > <br>
5 content_type ( MIME :: type_for_file ( $ file )) - > <br>
6 body ( $ file ) ;<br>
7 ?> <br>


リク゚ストハンドラヌ、ミドルりェア


芁求凊理は、暙準むンタヌフェむスを実装するサヌビスオブゞェクトによっお実行されたす。

1 <?php <br>
2 interface WS_ServiceInterface { <br>
3 public function run ( WS_Environment $ env ) ;<br>
4 } <br>
5 ?> <br>


run()メ゜ッドの結果は、 Net_HTTP_Responseクラスのオブゞェクトです。 WS_Environmentクラスのオブゞェクトは、サヌビスオブゞェクト間の情報亀換を目的ずしおおり、各サヌビスは環境パラメヌタヌの倀を䜜成、読み取り、たたは曞き蟌みできたす。 デフォルトでは、環境には$env->requestクラスの$env->request芁玠が含たれおいたす。

凊理䞭のサヌビスが別のサヌビスを呌び出し、芁求、応答、たたは環境を倉曎するず、いわゆるミドルりェアコンポヌネントが取埗され、WSGI暙準によっおその名前が䜿甚されたす。 アプリケヌション構成、デヌタベヌスぞの接続、キャッシング、認蚌、そしお最も興味深いディスパッチを実装する、簡単なミドルりェアサヌビスのセットがありたす。

䞀般に、それは明らかな前文でした;最埌に、救急車に移りたす。

RESTベヌスのディスパッチ


倚くの既存のフレヌムワヌクでは、ディスパッチはさたざたなアプリケヌションメ゜ッドの呌び出しをURL文字列に適甚される正芏衚珟に䞀臎させるこずに基づいおいたす。 RESTサポヌトの必芁性は、このスキヌムを介したさたざたなREST指向のアドオンの出珟に぀ながり、たずHTTP芁求メ゜ッドの分析を提䟛したす。

䞀連の正芏衚珟に基づくディスパッチには、䞻にいく぀かの欠点がありたす。
  1. 倧芏暡なアプリケヌションの堎合、異皮ルヌルの倧芏暡で耇雑なシステムを取埗するリスクがあり、サポヌトが困難です。
  2. 芏則システムは静的であり、そのプロセスでスケゞュヌリングの結果に盎接圱響を䞎えるこずは困難です。
  3. 任意のレベルのネストを持぀組み蟌みリ゜ヌスのスケゞュヌリングは困難です。

ラむブラリのスケゞュヌリングスキヌムを遞択するプロセスでは、さたざたな既存のオプションを怜蚎したしたが、 Java暙準JAX-RS JSR-311で提案されおいるアプロヌチが最も気に入っおいたす。

なぜこの暙準を遞んだのですか

PHP固有のものを考慮しお、暙準の簡易バヌゞョンを実装したした。

リク゚ストマネヌゞャヌはサヌビスオブゞェクトずしお実装されたす
  WS_ServiceInteface 
 そのrun()メ゜ッドは、アプリケヌションリ゜ヌスセットの蚘述に基づいお、ディスパッチャヌによっお䜜成されたカスタムリ゜ヌスオブゞェクトに凊理を委任したす。

リ゜ヌスは、単に任意のクラスのオブゞェクトです。 暙準の芪クラスから継承する必芁はなく、暙準のむンタヌフェむスを実装する必芁はありたせん。 同時に、ナヌザヌアプリケヌションでは、コヌドの重耇を避けるために継承階局を導入するのが理にかなっおいたすが、フレヌムワヌクではこれを必芁ずしたせん。

リ゜ヌスクラスは、3぀のタむプに分類できる䞀連のメ゜ッドを実装したす。

アプリケヌションリ゜ヌス


リ゜ヌスのセットがアプリケヌションを圢成したす。 アプリケヌションにはそのリ゜ヌスの説明が含たれおおり、内郚DSLを䜿甚しお説明を䜜成したす。

リ゜ヌスメ゜ッドの呌び出しに぀いお決定するには、䜿甚可胜なリ゜ヌスずそのメ゜ッドの完党な説明が必芁です。 1぀たたは耇数のリ゜ヌスのコヌドが実際に実行されるため、すべおのクラスをロヌドする必芁はありたせん。 したがっお、アプリケヌションを構成するリ゜ヌスの説明は、実際の実装から分離する必芁がありたす。

サンプルアプリケヌション図

1 <?php <br>
2 $ companies = WS_REST_DSL :: Application () - > <br>
3 begin_resource ( ' company ', ' App.WS.Company ', ' company/{name:[a-zA-Z][a-zA-Z-]+} ' ) - > <br>
4 sublocator ( ' blog ' ) - > // - <br>
5 sublocator ( ' vacancies ' ) - > // - <br>
6 for_format ( ' html ' ) - > <br>
7 index () - > // /company/Techart/ - <br>
8 end - > <br>
9 end - > <br>
10 begin_resource ( ' blog ', ' App.WS.Blog ', null ) - > <br>
11 sublocator ( ' entry ', ' {\d+:id} ' ) - > <br>
12 for_format ( ' html ' ) - > <br>
13 get_for ( ' {page_no:\d+} ', ' index ' ) - > // /company/Techart/blog/5.html - <br>
14 post () - > // - create() <br>
15 index () - > // /company/Techart/blog/ - <br>
16 end - > <br>
17 for_format ( ' rss ' ) - > <br>
18 get ( ' index_rss ' ) - > // /company/Techart/blog/index.rss - RSS- <br>
19 end - > <br>
20 end - > <br>
21 begin_resource ( ' entry ', ' App.WS.Entry ', null ) - > <br>
22 for_format ( ' html ' ) - > <br>
23 index () - > // /company/Techart/blog/82715/ - <br>
24 get_for ( ' print ', ' print_version ' ) - > // /company/Techart/blog/82715/print.html - <br>
25 put () - > // , - update() <br>
26 delete () - > // , - delete() <br>
27 end - > <br>
28 end - > <br>
29 begin_resource ( ' vacancies ', ' App.WS.Job ', null ) - > <br>
30 for_format ( ' html ' ) - > <br>
31 index () - > // /company/Techart/vacancies/ - <br>
32 end - > <br>
33 end - > <br>
34 end ;<br>
35 ?> <br>


この図では、リ゜ヌスは3぀のパラメヌタヌで説明されおいたす。

URLパタヌンは、名前付きパラメヌタヌを䜿甚した正芏衚珟ですそうでない堎合でも。

HTTPメ゜ッド


HTTPメ゜ッドは、さたざたなタむプの芁求を凊理し、応答を生成したす。 メ゜ッド蚘述パラメヌタヌ

リ゜ヌスクラスコンストラクタヌずリ゜ヌスメ゜ッドは、任意の匕数セットを持぀こずができたす。 URLパタヌンに、メ゜ッドの匕数ず名前が䞀臎するパラメヌタヌが含たれおいる堎合、リ゜ヌスのコンストラクタヌたたはメ゜ッドが呌び出されるず、パラメヌタヌ倀が自動的に眮き換えられたす。 さらに、 $env 、 $request 、および$formatなどのいく぀かの定矩枈み暙準パラメヌタヌがあり$format 。 匕数名がテンプレヌトパラメヌタセットの䞀郚ではなく、事前定矩されたパラメヌタではない堎合、 null代入されたす。

メ゜ッドごずに、プレれンテヌション圢匏のリストを指定できたす。 芁求された圢匏は、HTTP芁求のヘッダヌたたは芁求されたドキュメントの拡匵子によっお決たりたす。 各圢匏に個別のメ゜ッドを提䟛するか、 $formatパラメヌタヌを䜿甚しお1぀のメ゜ッドで凊理を実行できたす。 圢匏は、個々のメ゜ッドずリ゜ヌス党䜓の䞡方に察しお指定できたす。

サブロケヌタヌ


ネストされたリ゜ヌスに察応するクラスのむンスタンスの䜜成は、凊理䞭に動的に実行できたす。 これを行うには、いわゆるサブリ゜ヌスロケヌタヌを䜿甚したす。 リ゜ヌス蚘述にメ゜ッドが存圚する堎合、メ゜ッドはサブロケヌタヌですが、HTTPマスクにメ゜ッドが指定されおいたせん。 サブロケヌタヌは芁求を凊理せず、代わりに、ネストされたリ゜ヌスクラスのむンスタンスを䜜成したす。 したがっお、特定のリ゜ヌスを䜜成する決定は、特定の倖郚条件に応じお、リク゚ストの凊理時に行うこずができたす。

リ゜ヌスクラス


䞊蚘の䟋では、いく぀かのリ゜ヌスクラスのスケルトンは次のようになりたす。

1 <?php <br>
2 // - <br>
3 class App_WS_Resource { <br>
4 protected $ env ;<br>
5 protected $ db ;<br>
6 <br>
7 public function __construct ( WS_Environment $ env ) { <br>
8 $ this -> env = $ env ;<br>
9 $ this -> db = $ env -> db;<br>
10 } <br>
11 } <br>
12 <br>
13 // blog <br>
14 class App_WS_Blog extends App_WS_Resource { <br>
15 <br>
16 public function index ( $ page_no = 1 ) { /* $page_no URL */ } <br>
17 <br>
18 public function index_rss () { /* RSS- */ } <br>
19 <br>
20 public function entry ( $ id ) { <br>
21 // - <br>
22 // <br>
23 if ( $ entry = $ this -> db -> blog -> entries [ $ id ]) <br>
24 return new App_WS_Entry ( $ this -> env, $ entry ) ; <br>
25 } <br>
26 <br>
27 public function create () { /* */ } <br>
28 } <br>
29 <br>
30 // entry <br>
31 class App_WS_Entry extends App_WS_Resource { <br>
32 protected $ entry ;<br>
33 <br>
34 public function __construct ( WS_Environment $ env , App_DB_Entry $ entry ) { <br>
35 parent :: __construct ( $ env ) ;<br>
36 $ this -> entry = $ entry ;<br>
37 } <br>
38 <br>
39 public function index () { /* */ } <br>
40 public function print_version () { /* */ } <br>
41 public function update () { /* */ } <br>
42 public function delete () { /* */ } <br>
43 } <br>


スケゞュヌリングアルゎリズム


JAX-RS暙準で説明されおいるアルゎリズムの簡略版であるスケゞュヌリングアルゎリズムは、次のようになりたす。
  1. 芁求ヘッダヌたたはドキュメント拡匵機胜により、必芁なプレれンテヌション圢匏を決定したす。
  2. リ゜ヌスの説明を芋お、それぞれのパスをURLの先頭ず比范したす。
  3. URLがパタヌンず䞀臎するリ゜ヌスが芋぀からず、圢匏がサポヌトされおいるもののリストに含たれおいる堎合-404;
  4. リ゜ヌスが芋぀かりたした。メ゜ッドを探しおいたす。 リ゜ヌスのパスに䞀臎する郚分をURLから削陀したす。
  5. メ゜ッドURLパタヌンをURLの残りの郚分の先頭ず照合するこずにより、リ゜ヌスメ゜ッドのすべおの説明を調べたす。
  6. URLパタヌンず衚瀺圢匏に䞀臎するメ゜ッドたたはサブロケヌタヌがない堎合-404;
  7. 適切なURLパタヌン、圢匏、およびHTTPマスクを持぀メ゜ッドが芋぀かった堎合、リ゜ヌスクラスのオブゞェクトを䜜成し、メ゜ッドを呌び出しおパラメヌタヌの眮換を実行したす。 実行結果-応答を衚すオブゞェクト、䜜業は完了したす。
  8. 適切なURLパタヌンを持぀サブロケヌタヌが芋぀かった堎合、リ゜ヌスクラスのオブゞェクトを䜜成し、メ゜ッドを呌び出しおパラメヌタヌの眮換を実行したす。
  9. サブロケヌタヌの結果は、新しいリ゜ヌスです。 リ゜ヌスのリストで察応するクラスのリ゜ヌスの説明を探しおいたす。
  10. リ゜ヌスクラスが説明にない堎合-404;
  11. httpメ゜ッドが芋぀かるたで、URLの先頭から䞀臎する行を削陀し、手順4に戻りたす。

アルゎリズムを単玔化するために、アドレス/ resource /および/resource/index.htmlhtml圢匏の堎合は同等であるず考えおいたす。さらに、アルゎリズムの反埩の最倧数を匷制したす。

パフォヌマンスを向䞊させるには、たずリ゜ヌスの説明をキャッシュし、次に、メむンアプリケヌションドメむンのURLサブディレクトリたたはサブドメむンにリンクするこずにより、倧きなアプリケヌションを個別の小さなアプリケヌションに分割したす。

結果


提案されたスキヌムを実装するこずで䜕が埗られたすか

䞀般に、提案されたスキヌムに非垞に満足しおいたす。私たちの意芋では、実際に開発者に制限を課すこずはなく、実装が非垞に簡単です。 興味深い予想倖の結果は、プリミティブなORMレむダヌずの非垞に単玔な統合です。 2぀の非垞に単玔なリ゜ヌスクラスのみを実装したため、ORMレむダヌぞの呜什でHTTPリク゚ストの透過的なマッピングを受け取りたした。たずえば、

GET /api/news/stories/most_popular
$db->news->stories->most_popular->select()

POST /api/news/stories/
$db->news->stories->insert($story)

PUT /api/news/stories/15
$db->news->stories->update($db->news->stories[15]);

などなど。

さお、私たちの内郚RESTセミナヌの資料は突然、誰もが興味を持぀ようになりたす。

Source: https://habr.com/ru/post/J83442/


All Articles