Perfect 基礎編
Apr 10, 2016 · oldswift2
サーバーサイドSwiftフレームワークのPerfectの使い方のメモその2
基礎編ではルーティングやリクエストの処理方法のあたりまで
URLルーティング
サンプルを見ると、ルーティングは大きくわけて
mustacheテンプレートエンジンのページをPageHandlerに登録RoutingにRequestHandlerを登録
の2種類がある様子
設定はいずれもPerfectServerModuleInit()の中で行う
PageHandlerでのルーティング
Webアプリなどでの固定ページの表示向け
公式の参考になるサンプルはAuthenticator
例えば、http://0.0.0.0:8181/admin/というページを表示させたい時の流れとしては、
表示するページをmustacheのテンプレートで作成
例だとadmin.mustacheというファイル名にし、先頭のところでhandler:AdminHandlerと指定する
ポイントは、
- 先頭の
handler:の部分で対応するPageHandlerの名前を指定 - ファイル名がアクセスする際のディレクトリと対応
テンプレートをプロジェクトへ追加
後述の小ネタにある「ドキュメントの配置」の方法で、admin.mustacheがドキュメントルートへ配置されるように設定する
PageHandlerを作成
ページにアクセスがあった時の処理を行う為のPageHandlerを継承したクラスを作る
(クラス名は任意だが、わかりやすいようにAdminHandlerとしておく)
作ったクラスをPageHandlerRegistry.addPageHandlerで登録する
PageHandlerRegistry.addPageHandler("AdminHandler") {
// (r: WebResponse) -> PageHandler in
return AdminHandler()
}
ポイントは、
addPageHandlerの一つ目の引数の文字列は、テンプレートの中で指定したhandlerと同じにする- リクエストの詳細な情報で分岐させたい時は、コメントアウトを外し
WebResponseの情報を使う
PageHandlerの中では、テンプレートに流し込む変数のDictionaryを生成する
RequestHandlerでのルーティング
APIとかブログのような動的なページ向け
公式の参考になるサンプルはURL Routing
例えば、REST APIでhttp://0.0.0.0:8181/user/mikeのGETでmikeというユーザの情報を取得したい時の流れとしては、
ルーティングを設定
Routingでルーティングのルール(HTTPのメソッドやURLなど)をRouteMapを使って設定する
例だと、
Routing.Routes["GET", "/user/{id}"] = { _ in return UserHandler() }
となる。ポイントは、
- HTTPのメソッドが指定できる
(指定する場合は一つ目にする) - URL部分は配列で複数指定できる
- ルール部分では
{}で囲うとRequestHandlerへ値を渡せる *が使える- クロージャで対応する
RequestHandlerを指定する
RequestHandlerを作成
クライアントへ返すレスポンスを生成する為のRequestHandlerを継承したクラスを作る
(クラス名は任意だが、わかりやすいようにUserHandlerとしておく)
URLで指定されたユーザ名をそのままJSONで返す場合は以下の感じ
これで、http://0.0.0.0:8181/user/mikeにアクセスすると{ user: "mike" }と返ってくる
ルーティング設定の確認
Routing.Routes.descriptionで設定をダンプできる。これ、かなり便利!
リクエストの処理
URLパラメータやPOSTのボディの中身は、WebRequestの中に格納されている
http://0.0.0.0:8181/hoge?key1=value1&key2=value2とした場合、
func handleRequest(request: WebRequest, response: WebResponse) {
request.queryString() // key1=value1&key2=value2
request.queryParams // [("key1", "value1"), ("key2", "value2")]
request.params() // [("key1", "value1"), ("key2", "value2")]
request.param("key1") // value1
request.param("key3", defaultValue: "value3") // value3
POSTで{ "count"=100 }を送った場合、
func handleRequest(request: WebRequest, response: WebResponse) {
let body = request.postBodyString
let json = try! JSONDecoder().decode(body) as! JSONDictionaryType
json["count"] // 100
といった感じで取得できる
小ネタ
ドキュメントの配置
Xcode経由で起動している時に、サーバからドキュメントへアクセスできるようにする方法。なお、ドキュメントルートはデフォルトで./webroot/が設定されている
DocumentRootのパスを変更する
状況によってはソースから改変するのもアリだが、起動時に立ち上がるGUIから変更するのが手軽。Choose...でフォルダ位置を選択できる。
ただし、注意すべきなのはDocument Rootのテキストフィールド内でキー操作(return)しないと変更と認識されずに保存されない点
(これにはまってソースまで見てようやく気付いた・・・)。変更後はサーバの再起動が必要(というか勝手にされるはず)
この方法だとサーバを起動したままでもドキュメントを変更できるが、一方でパスの設定が必要となる
ビルドでファイルを配置する
前回の導入編で使った方法で、デフォルトの./webroot/を使いたい場合用
- 作成したプロジェクトを選択
TARGETSでプロジェクト名と同じもの、Build Phasesタブを選択- 左上の
+をクリックして、New Copy Files Phasesを選択 DestinationでProducts Directoryを選択
Subpathにwebrootと入力Nameの下の方にある+をクリックし、追加ファイルを選択してAdd
(プロジェクトに未追加のファイルの場合はAdd Other...からで)
同一LAN内からのアクセス
例えば同じルータに繋がっているiPhoneから、Mac上で動いているPerfectのサーバに接続する方法
起動時に立ち上がるGUIのServer AddressをMacに割り当てられているIPアドレスに変更すればOK。
(変更後にreturnで確定を忘れずに・・・)
ポートも変更できるが、80とかはroot権限が必要と怒られて変更できないので注意
(今回は既にDocker+nginxを構築してあったので、nginxのリバースプロキシの設定でさくっと対応)
感想
普段、クライアント(iOSアプリ)側で使っている開発環境と全く同じ環境でサーバの開発が出来るというのは、 想像以上に便利というかストレスフリーな感じ
もちろん、PerfectではCocoaが使えないというのはあるし、物足りない感じはしなくも無いが。。。
ただ、そのあたりのカバーを目指してのPerfectという命名なんだろうと勝手に想像
