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
という命名なんだろうと勝手に想像