0) 今回は、web連携最初の関門、POST
先人のおかげで、あまり苦労せず。Expressに比べ、モジュール選定の自由が高い分、あちこち調べながらとはなったが。あと、Curlのお勉強も必要となった。
1) MithrilのPOST関係コードを見る
Mithril黒ムツ本(というらしい)のサンプルのうち、2章のToDo3を参考にする。
MVVMモデルのMithrilということで、追加ボタンを押した後、
[View]
- m("input", {onchange: m.withAttr("value", vm.description), value: vm.description()})
- m("button", {onclick: vm.add}, "追加")
[ViewModel]
- vm.add = function (){ ... Todo.save(vm.list())...}
[Model]
- Todo.save = function...
の順に、メソッドが呼ばれサーバへのPOSTが行われる。Mithtil APIのm.requestを用い、dataコレクションを送付:
// サーバに現在のタスクを送信
Todo.save = function (todoList) {
var data = todoList.filter(function (todo) { return !todo.done(); });
m.request({method: "POST", url: "/tasks", data: data});
};
受け側のexpressコードは以下:
app.post("/tasks", function (req, res) {
console.log("post tasks");
fs.writeFileSync("todo.json", JSON.stringify(req.body));
res.status(200).end();
});
req.bodyはJSONの配列で、これを、fsモジュールより、ローカルファイルのtodo.jsonに書き出している。
m.requestによる呼び出しに対応するcurlは以下:
curl localhost:8000/tasks -H 'Content-Type: application/json' --data-binary '[{"description":"入力内容","done":false}]'
cf. Curlどう書くんだっけ?という時は、こちらを参考: WebAPIリクエスト仕様書としてcurlコマンドのご提案
doneは、ToDoのチェックがされたかどうか(true/false)。
2) KoaでMithrilからのPOSTを受ける。
ということで、上記のcurlリクエストを受けるKoaコードを書いてみる。
まずは、今回の作業に必要となりそうな、Koaのモジュールを改めて導入。
npm init
npm install koa koa-router koa-bodyparser koa-json koa-static co-views jade fs --save
このうち、koa-bodyparser がPOSTされたbodyをパースしてくれる。本質コードは、これだけ:
router.post '/', (next)->
fs.writeFileSync "todo.json",JSON.stringify(@request.body)
yield next
curlの--data-binary以下から送付された内容(ここではJSON配列)が、@request.bodyに格納されるので、その内容をファイルに書き出す。
今回から、よく出来たラウター・モジュールとして、koa-routerを導入。
結果、app本体部分は以下のコードに:
koa = require 'koa'
api = do require 'koa-router'
serve = require 'koa-static'
api.use '/tasks', require './api/tasks'
#/tasksへのリクエストは./api/task.coffeeにて処理
app = koa()
app
.use do require 'koa-bodyparser'
.use do require 'koa-json'
.use api.routes()
.use api.allowedMethods()
.use serve __dirname + '/static' #静的HTMLは、/static以下に置く。
.listen 3000
ToDoタスクの登録・一覧部分のコード:
router = do require 'koa-router'
fs = require "fs"
# `POST /tasks` = タスク登録(todo.jsonに書き出し)
router.post '/', (next)->
console.log "post tasks"
fs.writeFileSync "todo.json",JSON.stringify(@request.body)
yield next
# `GET /tasks` = タスク一覧(todo.jsonから読み出し)
router.get '/', (next)->
console.log "get tasks"
docs = JSON.parse fs.readFileSync("todo.json", "utf8")
@body = docs
yield next
module.exports = router.routes()
koa-routerのおかげで、コードも適切にモジュール化され、めでたしめでたし。
・・・で終わりにしたかったのだが、router.post~yield nextだけでは、タスク一覧の更新をよろしくやってくれないらしい(ブラウザ画面をリフレッシュすると、更新されたタスク一覧が表示される)。このあたり、Mithril側の責務だと思うが、次回への宿題とする。
3) 次回以降
Mithrilとkoa-routerの組み合わせをマスターすると共に、mongodbあたりへの永続化を行う。
ここまでできたら、全体をgithubに上げることとしたい。
koa-routerとKoaでのmongoの扱いについては、先人:koaでjsonwebtokenを使っていい感じに認証するが、自前認証モジュール含め、かなりいい感じ。Thanks!