man ympbyc
manualhubというウェブサービスを作ったので記事を書きましょう。
ゴールデンウィークの前半3日、なにか作ろうと思ってやっちゃったのがこれです。暦通りの職場だし、後半3日は山中湖に旅行に行くので(いいでしょ!)、まとまった時間はこれしかない!
いつも通りNode.jsです。最近ほんとにjsしか書いてないんですよね。ブラウザ然りNode然りTitanium然り。Javascript便利!
manualhubの話しましょう。
manualhub、ほんとはmanhubって名前にしたかったんですが、ぐぐったらゲイサイトがヒットしちゃったのでやむなくmanualhub。
manページを使ったプロフィールサービスです。
ついったーで某やの字の名前をmanしてみたところから着想を得ました。
man ympbyc
これできたらうれしいんじゃないかな!?
ご存知かとは思いますが、manページというのは、UNIXのコマンドに付いてくるドキュメントで、なかなか特徴的な見た目なんです。
そしてこれがmanualhub。ここで作ったmanページはダウンロードできます。
なかなか見やすくて、ギーク臭ただよっていい感じしますね。
こんなにかっこいいmanページを簡単に作れて、しかも公開プロフィールとしてホスティングしてくれるサービスがあったら間違いなく流行る!流行ろう!流行れ!
実装の事書きましょう。
Node.js, MongoDB とクライアントサイドのjsでできています。
ログインはgithubのOAuth2に寄生しました。認証フローがtwitterに比べてめちゃくちゃシンプルでびっくり!リダイレクトして回るだけ!HMACだNONCEだSHA1だなんて気にしないでおっけー!すごい!
注意点としては、ローカルで開発中はリダイレクト先をlocalhostにしたいんですが、どうやらこれができないみたいで、どっかにプロキシを建ててやる必要があります。今回はjsapp.usにシンプルなサーバを置いて中継させました。できるらしいです
RESTなAPIチックに書きたかったので、ejsなどのテンプレートエンジンを使ってレンダリングといった事は特に行わずに、urlに応じてhtmlを返してあげて、その中のjsからajaxにAPIを叩く形にしました。RESTを意識したので、割とCOOLなURIになってると思うんです。
GET /auth/github
GET /auth/github/callback
GET /user/:name
PUT /user
GET /me
GET /:username
それから
POST /user
っていうのもあったんですが、後述する理由でなくしました。
server.js
app.put('/user', function (req, res) { UserModel.update({id : req.session....}, {$set : req.body...}) }) app.get('/:username', function (req, res) { res.render('user.html'); })
user.html::javascript
$('textarea').on('blur', function () { $.put('/user', {description : 'hogehogefugafuga'}); });
NodeでMongoDBを使うためのドライバにはMongooseを使いました。でもschemaはあんまり有効活用してないです。
プロフィールサービスの特性上、updateがしたいわけです。上書きsaveでも問題ないけど、アップデートしたいんだからupdateでしょ。
ところがところが、Mongooseのupdateって、MongoDBのupdateにクエリをそのまま丸投げするだけらしいんですよ。Schemaでせっかく面白いエラーメッセージいっぱい用意してバリデータを作ったのに、バリデータは通してくれないし、おまけにSomeModel.pre('update', function (){})みたいなホックもないんですよ。
というわけで自分でバリデータを書きましょう。
app.put('/user', function (req, res) { function validate (v) { return v.length > 0 && v.length < MAX_LENGTH && !v.match(/someregex/); } var change = {}; _(req.body.changeSet).each(function (item, key) { if (key === 'name' || key === 'internai_id') return; //上書きされちゃ困るフィールドはスルーするー if (!validate(item)) return; //バリデーションに通らなかったらスルーするー change[key] = item; }); SomeModel.update({id : req.session...}, change); });
今回はすべてのフィールドが2000文字以下のStringっていう簡単な設計にしたので楽々でしたが、Embedded Documentとかを使ってると、再帰的にチェックしなきゃいけなかったり、型ごとのバリデータを作らなきゃいけなくなったりでめんどっちいです。耐えましょう。
ドキュメントは初回ログインのときにsaveしちゃっとくと、CRUDのCをRESTに出さずにUだけで済むので楽ちんになります。
こんなかんじです。
実行環境の話をしましょう。
もともとno.deとかnodesterとかnodejitsuとかでホストしてもらおうと思ってたんですが、どこもいっぱいでアカウントがもらえず。
dotcloudは無料スロット2つのうちtofuchaproxyで1スロット使っちゃってるのでサーバが動かせてもDBが動かせないっていう状況だし、
fluxflexはfcgiだかなんだかの上でNodeを動かすことになるから書き換えなきゃいけないし、
Herokuよくわかんないし、Dynoってなんだよ!
途方に暮れてたんですが、そういえばgehirnのRS2っていうのがあったなあと、今朝思い出しました。
SSHで接続できて、Nodeがコンパイルできるんですよ!すごいね!
#ローカル ssh yourname@s*.rs2.gehirn.jp #リモート git clone http://github.com/ry/node mkdir opt export PREFIX=/home/yourname/opt cd git ./configure --debug make make install
たしかこんなかんじ。
MongoDBはコンパイル面倒くさそうなので仮想rootっていう環境を作ってapt-getでインストールします。仮想rootってなんやねん?なんやねん?
isidaiさんのブログをみてください。
fakeroot環境ができたら
cd /root apt-get install mongodb mkdir db mongod --dbpath /root/db --port 27017
こんなかんじでMongoDBが動きますょ。
そんなわけで http://s7.rs2.gehirn.jp:8080/ で公開してるんですが、アカウントの有効期限が5/11とのことなので(多分この日でβ版が終わるんじゃないかな?かな?)、とりあえず一時的な公開ということになりそうです。http://manualhub.herokuapp.com/で公開してます
昨日公開されたK社のMake::Boothに展示したかったので急いで作って急いで公開した形になります。
過度な期待はせずに個人情報ください。
ソースは https://github.com/ympbyc/manualhub にありますけどコメントとかまだ付いてません。
おしまい。