WebMatrix 2:RESTful?な Web アプリケーション
執筆日時:
たとえば、
- ~/Posts/ …… ページリストの表示
- ~/Posts/:id …… 個別ページの表示
というのをやってみたいとき。
- ~/Posts/Default.cshtml
を作成して、
- UrlData.Count() == 0 ……ページリストの表示
- UrlData.Count() == 1 ……個別ページの表示
という処理を書けばいいよね(WebMatrix のルーティング - だるろぐ)。
これはウソだ。申し訳ない。まぁ、別に正しいことを書いているブログではないので、いいと言えばいいんだけど。正しくは、
- ~/Posts.cshtml
を作成するだね。ほかにもウソがあるのだけど、それはまた別のエントリーでフォローするから!
――なにはともあれ。
この ~/Posts.cshtml をガリガリ書いていけば、いわゆる RESTful な Web アプリケーションが書けるのではないかと思いついた。RESTful の厳密な定義は知らないけど、だいたい
- Lists:GET /Posts
- Show:GET /Posts/:id
- New: POST /Posts
- Edit:PUT /Posts/:id
- Remove:DELETE /Posts/:id
みたいな感じだよね。だったら、下のような感じで書けばいいんじゃないか(本質に関係ない部分は削ってる)。
@try{ switch (Request.HttpMethod.ToUpper()) { case "GET": switch (UrlData.Count) { case 0: // GET Posts/ @List() break; case 1: switch (UrlData[0].ToUpper()) { case "NEW": // GET Posts/New @New() break; default: // GET Posts/1, Posts/Title @Show(UrlData[0]) break; } break; case 2: switch (UrlData[0].ToUpper()) { case "EDIT": // GET Posts/Edit/1 @Edit(UrlData[1]) break; case "REMOVE": // GET Posts/Delete/1 @Remove(UrlData[1]) break; } break; } break; case "POST": Create(); break; case "PUT": Update(UrlData[0].AsInt()); break; case "DELETE": Delete(UrlData[0].AsInt()); break; } } catch (Exception e) { <p><span class="badge error">Error</span> @e.Message</p> }
@List() や @New() の部分は、@functions で定義してる。
@functions { HelperResult List() { var query = "SELECT * FROM Post ORDER BY CreatedAt DESC";using (var db = Database.Open("db")) { var posts = db.Query(query); return RenderPage("~/Views/Posts/_ListPosts.cshtml", posts); } } }
HelperResult を返す関数にして @ をつけて呼べば、ちゃんと部分ビューがレンダリングされる。POST/PUT/DELETE のところで使う関数は、どうせ Response.Redirect() するから void でいいし、@Delete() なんて書く必要もない。
で。
Create() は動くのだけど、なぜか Update() と Delete() だけが動かない。ちゃんとビューで method も指定したのになぁ……
#Delete() → RenderPage() ~/Views/Posts/_RemovePost.cshtml" @{ var model = PageData.First().Value; } <form method="delete" action="~/Posts/@model.Id"> <div> <label>Title</label> <input type="text" name="Title" value="@model.Title" disabled /> </div> <div> <label>Body</label> <textarea name="Body" disabled>@model.Body</textarea> </div> <div> <input type="submit" /> </div> </form>
なぜかこれを Submit すると GET での呼び出しになってしまう。よく知らんけど、ブラウザーは GET と POST しかサポートしていないらしい*1。あと、サーバー側にも設定がいるのかな。
とりあえず、GET と POST しか使えない。道理で、IsPost() なんていうのがお役に立つ訳だわ。なんで IsGet()、IsPut()、IsDelete() しかないのかなって思ってた。こういうのって、たぶん Web 開発者にとっては基本的な知識なんだろうな。やっぱりなにごとも経験しないとだめだねぇ。
というわけで、GET と POST だけ使っていろいろ書き直したのだけど、それはまた今度。一足先に感想を言えば、こういうのは「ASP.NET MVC」使った方が賢い(ぉ
*1:そういえば、Rails でも _method="delete" みたいな感じにして、ここら辺の問題を回避していた気がする