Dartのサーバーサイドフレームワーク Jaguarについて

この記事はDart Advent Calednar 22日目の記事です_（遅刻してしまいすいません……）_。この記事ではJaguarというDartのサーバーサイドフレームワークの説明をしていきます。

Jaguar は Dart のサーバーサイドフレームワークです。

- [GitHub](https://github.com/Jaguar-dart/jaguar)
- [公式サイト](https://jaguar-dart.com/)

ORM や Serialization、Auth 等の基本的な機能を揃えたサーバーサイドフレームワークとなっています。[サンプルプロジェクト](https://github.com/jaguar-examples)も豊富にあるので、導入も簡単にできそうですね。まだドキュメントが整備段階のようなので、試してみたい方に簡単な特徴の説明等をしていきます。

# セットアップ

Jaguar をとりあえず試してみるのは簡単です。

```yaml:pubspec.yaml
name: jaguar_example
version: 0.0.1
dependencies:
  jaguar: ^2.2.6
```

```dart:bin/main.dart
import 'package:jaguar/jaguar.dart';

main() => Jaguar(port: 8080)
  ..get('/about', (ctx) => 'Jaguar')
  ..postJson('/echo', (ctx) => ctx.bodyAsJson())
  ..serve();
```

```sh
$ pub get # 依存関係の解決
$ dart bin/main.dart
```

これだけで localhost:8080 にアクセスすればサーバーサイドのプログラムが実行されています。この辺の導入がシンプルなのはいいですね。

# 特徴

## Routing

Jaguar のルーティングは簡単に記述・構成が可能です。

```dart

// その他の例はこちらに
/// https://github.com/Jaguar-dart/jaguar/wiki/Powerful-path-matching
/// https://github.com/Jaguar-dart/jaguar/wiki/Path-parameters
/// 詳しい記事 https://medium.com/@tejainece/route-paths-and-path-variables-in-jaguar-dart-344525b94542

main(){
    final server = Jaguar();
    // シンプルなレスポンス
    server.get('/',(Context ctx) => 'Hello World!');
    server.post('/',(Context ctx) => 'Hello World!');
    // パラメータ指定
    final UserName = <String>[
        'Bob',
        'Alice',
        'Anyone'
    ];
    server.get('/api/user/:id',(Context ctx){
        final int index = ctx.queryParams.getInt('id', 1);
        return quotes[index - 1];
    })
    // glob
    server.get('/api/v1/*',(_) => new Response('Depreacted',statusCode: 500));
}
```

もちろん直で Routing をするのが必須なわけではありません。Controller classを利用することで継承が可能になっています[^1]。


[^1]: [jaguar_reflect](https://pub.dartlang.org/packages/jaguar_reflect)をdependenciesに追加する必要があります

```dart
import 'dart:async';
import 'package:jaguar/jaguar.dart';
import 'package:jaguar_reflect/jaguar_reflect.dart';


/// Collection of routes students can also access
@GenController(path: '/books')
class BookRoutes extends Controller {
  @GetJson()
  List<String> getAllBooks(Context ctx) => <String>['the dummy book title'];
}

@GenController(path: '/api')
class LibraryApi extends Controller {
  @IncludeController()
  final book = BookRoutes();
}

main() async {
  final server = Jaguar(port: 10000);
  server.add(reflect(LibraryApi()));
  server.log.onRecord.listen(print);
  await server.serve(logRequests: true);
}
```

## JSON Serialization

JSONへのSerializationはシンプルに行うことが出来ます。

```dart
  server.post('/api/book', (Context ctx) async {
    final Map<String, dynamic> json = await ctx.req.bodyAsJsonMap();
    Book book = new Book.fromMap(json);
  });
```

[json_serializable](https://github.com/dart-lang/json_serializable)等のライブラリと組み合わせて使えば簡単にシリアライズ・デシリアライズが可能です。

## ユーザー認証

`UserFetcher`というクラスを継承することで、ユーザー認証を行うことが出来ます。`UserFetcher`自体はAbstract Classなので、継承を行い実装していくパターンですね。公式では[Facebook認証用のライブラリ](https://github.com/Jaguar-dart/jaguar/tree/master/oauth_facebook)もあります。[Postgresqlでの実装のサンプル](https://github.com/jaguar-examples/boilerplate_postgresql)も参考になると思います。

## Session


リクエストハンドラでSessionを簡単に扱うことができます。

```dart
server.get('/example', (ctx) async {
    final Session session = await ctx.session;
    session['item'] = 'test';
    return session['item'];
});
```


[ドキュメント](https://github.com/Jaguar-dart/jaguar/wiki/Session-managers)にもある通り、Session管理としては、CookieやMongodb、JWTを選ぶことが可能です。

### データベース

[ORM](https://github.com/Jaguar-dart/jaguar_orm)が存在しており、Modelの定義に対してModelBeanを作成することでORMとして機能するようになっています。

```dart
class Book {
  @PrimaryKey(auto: true)
  int id;
  String title;
  String author;
}

@GenBean()
class BookBean extends Bean<BookBean> with _BookBean {
  BookBean(Adapter adapter) : super(adapter);

  @override
  String get tableName => 'bookBean';
}
```

これに対してbuild_runnerを走らせると、自動的にデータベース用のソースコードが出力されます。

# まとめ

簡単でしたがJaguarの特徴をまとめました。JaguarはDart2.0に対応していることもあって非常に扱いやすいフレームワークになっていると思います。source_genやAngular Dartとの連携も考えてあるのも嬉しいポイントかなと。まだドキュメント周りが多少整っていないので、少しでも使うためのハードルを下げられたら幸いです。