Dart製のSinatra風Webフレームワーク「Start」を使ってみた

この記事は「Dart Advent Calendar 2014」の15日目の記事です。

最近、Angular.dartやPolymer.dartで徐々に?賑わい始めた感のあるDartですが、そもそもDartはJavaScriptの代替になりうるという役割に留まらず、その用途は色々な可能性を秘めています。

というわけで、今回はサーバサイドDartの話です。

Dart界隈をウォッチし始めて数ヶ月、StartというWebフレームワークを見つけました。

Sinatra inspired web development framework for Dart」と書かれているので、まさにDart版のSinatraです。早速触ってみましょう。

pubspec.yamlを用意

まずpubspec.yamlにStartへの依存を追加します。JSでいうとこのpackage.jsonです。Startの現時点での最新版は0.2.7です。

name: start-example
version: 0.0.1
description: A sample command-line application
dependencies:
  start: '>=0.2.7'

dev_dependencies:
#  unittest: any

pubspec.yamlを用意して、pub get すると依存しているライブラリがダウンロードされます。

サーバを起動するプログラムを用意

READMEにあるように、以下のような簡単なプログラムでサーバとして動作します。

import 'package:start/start.dart';

void main() {
  start(port: 3000).then((Server app) {

    app.static('web');

    app.get('/hello/:name.:lastname?').listen((request) {
      request.response
      .header('Content-Type', 'text/html; charset=UTF-8')
      .send('Hello, ${request.param('name')} ${request.param('lastname')}');
    });

    app.ws('/socket').listen((socket) {
      socket.on('ping').listen((data) => socket.send('pong'));
      socket.on('pong').listen((data) => socket.close(1000, 'requested'));
    });

  });
}

このプログラムを実行すると、http://localhost:3000/hello/hoge 等のリクエストをさばけるようになります。

軽くベンチマーク取ってみた

Node(express)で書いたコードとStartのベンチマークを比較してみた。簡単なJSONを返すだけのプログラムです。

Dart(start)
import 'package:start/start.dart';

void main() {
  start(port: 3000).then((Server app) {

    app.get('/api/test').listen((request) {

      Map<String, dynamic> data = {'name': 'neko', 'age': 10, 'description': 'Dart Advent Calendar 2014 14日目!!'};

      request.response
      .header('Content-Type', 'application/json; charset=UTF-8')
      .json(data);
    });

  });
}
Node(express)
var express = require('express');
var server = express();

server.get('/api/test', function(request, response) {
  setTimeout(function(){
    response.json({name: 'neko', age: 10, description : "Dart Advent Calendar 2014 14日目!!"});
  }, 100);
});

server.listen(9000);

これに対して、Apache Benchで3000リクエスト(同時100)でベンチを取ります。

Dart(start)
Concurrency Level:      100
Time taken for tests:   0.987 seconds
Complete requests:      3000
Failed requests:        0
Total transferred:      714000 bytes
HTML transferred:       231000 bytes
Requests per second:    3038.51 [#/sec] (mean)
Time per request:       32.911 [ms] (mean)
Time per request:       0.329 [ms] (mean, across all concurrent requests)
Transfer rate:          706.22 [Kbytes/sec] received

Node(express)
Concurrency Level:      100
Time taken for tests:   3.492 seconds
Complete requests:      3000
Failed requests:        0
Total transferred:      834000 bytes
HTML transferred:       270000 bytes
Requests per second:    859.19 [#/sec] (mean)
Time per request:       116.388 [ms] (mean)
Time per request:       1.164 [ms] (mean, across all concurrent requests)
Transfer rate:          233.26 [Kbytes/sec] received

この結果だけ見ると、Startなかなか優秀に思えるのだが・・・。比較対象を薄めな意味でexpressにしたけど、あまりフェアじゃなかったかもしれません(でもここまで開くものかなーという印象が強い)。

ちなみにStartはDart標準のHttpServerを利用しています。この辺の仕組みをもっと掘り下げたいところです。

まとめ

サーバサイドDartも今後選択肢としてはありうるかなという印象です。また、DartはDart editorやWebStromもあって、IDE面でのサポートは言うことないです。ただ、Nodeに比べると周辺の開発支援系ツールがまだまだ弱い。トータルでの生産性という意味ではまだまだ劣ると考えてます(逆に言えば、改善していく余地はかなりあるということでもある)。

あと、Start自体は8月くらいからコミットがありません(´・ω・`)

明日16日目は、sh4869さんになります。