経緯
以前作成した Lua + Luarocks + MoonScript + Lapis (OpenResty) の環境 の上で、
- フォームに入力させる
- 入力した値を POST で飛ばして
- その値によって出力を変化させる
という簡単なサンプルプログラムを作成したいと思います。
成果物
app.moon
lapis = require "lapis"
import respond_to from require "lapis.application"
class App extends lapis.Application
@enable "etlua"
[index: "/"]: =>
-- デフォルトの文字コードが Shift-JIS で日本語を含むコンテンツだと文字化けしてしまうので、レスポンスヘッダを調整
@res.headers["Content-Type"] = "text/html; charset=UTF-8"
"ok"
render: true
[mna: "/mna"]: => status: 405
[twardowski: "/twardowski"]: respond_to {
before: =>
-- デフォルトの文字コードが Shift-JIS で日本語を含むコンテンツだと文字化けしてしまうので、レスポンスヘッダを調整
@res.headers["Content-Type"] = "text/html; charset=UTF-8"
GET: =>
@write redirect_to: "/mna"
POST: =>
"ok"
@ip = @params.ip
render: true
}
etlua
: テンプレートエンジンとしてetlua
を使用。使用するためにクラスの最初で@enable "etlua"
の宣言をしています。- ルーティング:
- 今回のルーティングは大きく3つ。
- トップページ(
/
):- 他のルーティングも共通ですが、レスポンスヘッダに
Content-Type
指定がないと Windows クライアント環境下ではデフォルトで文字コード Shift-JIS として表示されてしまうらしく、開発環境が UTF-8 で作成している都合上文字化けしてしまいます。- そのため、
@res.headers["Content-Type"] = "text/html; charset=UTF-8"
で UTF-8 出力を明示しています。
- そのため、
- 他のルーティングも共通ですが、レスポンスヘッダに
- 405 Method not Allowed(
/mna
):- 後述のフォームの表示結果ページは
POST
メソッド でフォーム入力値が飛んで来ることを想定しています。そのため、GET
メソッド でアクセスされた場合はこのページへリダイレクトさせます。 - また、その際 HTTPステータスコード を 405 にセットしたかったため
status: 405
でセットしています。- ただしこれをセットすると
etlua
でファイルを用意してもページのレンダリングがされませんでした。- レンダリングさせる方法が分からなかったのですが今回はそこまで追究しませんでした。
- ただしこれをセットすると
- 後述のフォームの表示結果ページは
- 結果表示ページ(
/twardowski
):- トップページで入力された値 (サブネットマスク指定ありのIPv4アドレス) を使用して表示を変化させる。
respond_to
ライブラリをファイル先頭でインポートして、その機能を利用してメソッドごとに処理を場合分け。before
: 共通内容。- 今回はトップページと同様文字コードの指定を追加。
GET
:GET
メソッド でアクセスされた場合。- 今回は先述した通り
POST
メソッド のみ受け付けたいので@write redirect_to: "/mna"
でエラーページへリダイレクトさせます。
- 今回は先述した通り
POST
:POST
メソッド でアクセスされた場合。@params
にform
タグ 内のフォーム、name
属性 でパラメータが渡ってくる(今回はname="ip"
)ので、@params.ip
で受け取ります。etlua
に出力する場合は@
付き変数で参照可能にしておかなければいけないため、@ip
に再代入しています(@params.ip
のままでも大丈夫そうですが記述が増えるので)。- サーバ側バリデーションもしたかったのですが、どうも標準機能では正規表現がなさげなので諦めて素通りさせました。実用では危険すぎますが、今回はあくまでサンプルと言うことで目を瞑りました……。
- トップページで入力された値 (サブネットマスク指定ありのIPv4アドレス) を使用して表示を変化させる。
- トップページ(
- 今回のルーティングは大きく3つ。
views/index.etlua
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
<div class="container my-4">
<h2 class="display-2">Twardowski</h2>
<p class="lead">Pan Twardowski is is a sorcerer in Polish folklore and literature.</p>
<form action="./twardowski" method="post" class="row g-3">
<div class="col-auto">
<label for="ip" class="visually-hidden">IPアドレス</label>
<input
type="text"
class="form-control"
id="ip"
name="ip"
placeholder="192.0.2.1/24"
pattern="^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)/([\d]{1}|1[\d]{1}|2[\d]{1}|3[012])$"
/>
</div>
<div class="col-auto">
<button type="submit" class="btn btn-primary mb-3">このIPアドレス出力する</button>
</div>
</form>
</div>
トップページのテンプレート。
- デザインは Bootstrap の CDN 利用。
- Lua 系の話とは関係ないですが、 HTML で
input
タグ のpattern
属性 で正規表現による入力値チェックができる、ということで今回検証 (そのためにあえてIPv4アドレスを想定した)。- “input pattern” | Can I use… Support tables for HTML5, CSS3, etc
- 参考にした記事では Safari はまだ対応していない、とあったのですが Can I use… で確認したところ対応している模様。基本全部行けそうなのでこれはこれでありかもしれませんね。
^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)/([\d]{1}|1[\d]{1}|2[\d]{1}|3[012])$
がそれ。192.0.2.1/8
や192.0.2.1/32
は通りますが192.0.2.1/33
はNG。良さそうです。
- “input pattern” | Can I use… Support tables for HTML5, CSS3, etc
views/twardowski.etlua
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
<div class="container my-4">
<h2 class="display-2">Twardowski</h2>
<p class="lead">A value of your inputting is ... <%= ip %></p>
</div>
出力側。 app.moon
で再代入した変数 @ip
の値をそのまま表示するだけ。
サンプルと言うことで色々ごまかしている部分はありますが、 HTTPメソッド ごとの表示切り分け等の挙動は確認できたので一応記録として残しておきます。
余談
例によって名前ですが、 Lua なので月関連ということで、ポーランドの伝説で魔力と引き換えに魂を売り渡す契約を悪魔とかわし、最後は地獄へ行く途中で月へ落とされてしまった魔術師 Twardowski (トファルドフスキ) です。この伝説に拠って、ポーランドでは月の海はトファルドフスキの姿、と言われることもあるようですね (日本だと兎が餅を搗いているとか薬を作っているとか言われているアレと同じ類)。
参考
- Quick Reference – Lapis Reference Manual
- GET, POST 等のメソッドごとの書き分け
- Requests and Actions – Lapis Reference Manual
- HTTP ステータスコードの指定の仕方