All Dartの選択肢DartのWebフレームワーク「Shelf」をさわる

# はじめに

「Shelf」はGoogleが開発しているDartのWebフレームワークです。
Dart公式が提供しているパッケージで、定期的にアップデートされていて、Dart SDKと親和性が高いのでDartのエコシステム全体を一貫して使用することができます。
現在、Dart3系に対応した安定版(stable)がリリースされており、安心して使用することができると考えています。

サーバサイドを「Shelf」、フロントエンドを「Flutter」で作ることにより、All Dartで開発を行うことができます。(Flutter, ShelfともにGoogle製なので、メンテナンスや信頼性も問題なさそう！)

すべてDartでシステム開発をすることで以下の利点が考えられます。

- フロントエンドとバックエンドの垣根が低くなり、柔軟な人材配置が可能になる
- バックもフロントも同じ言語なので理解しやすい
- AI駆動開発などでAIが書いたコードをレビューするときにDartエンジニアだけでできる

今回はShelfでプロジェクトを作成して、サーバー起動まで書きたいと思います。

https://pub.dev/packages/shelf

サンプルコード

https://github.com/w2406/study_web_server_shelf/tree/main/todo_api

# プロジェクト作成

Dartバージョン

```bash
study_web_server_shelf % dart --version

Dart SDK version: 3.6.0 (stable) (Thu Dec 5 07:46:24 2024 -0800) on "macos_arm64"
```

プロジェクト作成します。

以下のコマンドを実行してプロジェクトを作成します。

```bash
study_web_server_shelf % dart create todo_api 

Creating todo_api using template console...

  .gitignore
  analysis_options.yaml
  CHANGELOG.md
  pubspec.yaml
  README.md
  bin/todo_api.dart
  lib/todo_api.dart
  test/todo_api_test.dart

Running pub get...                     3.9s
  Resolving dependencies...
  Downloading packages...
  Changed 50 dependencies!

Created project todo_api in todo_api! In order to get started, run the following commands:

  cd todo_api
  dart run
```

サンプルプログラムを試しに実行します。

```bash
study_web_server_shelf % cd todo_api 
todo_api % dart run

Building package executable... 
Built todo_api:todo_api.
Hello world: 42!

```

# Shelfパッケージを追加

shelfはWebフレームワークとして、非常に軽量でシンプルな設計をしています。
DBクライアントやルーティング機能など必要な機能はパッケージを追加する必要があります。
※ この記事では使用するところまで書いていません

```bash
## shelfパッケージ追加
dart pub add shelf

## routerパッケージ追加
dart pub add shelf_router
## DBパッケージ追加
dart pub add postgres
## ORMパッケージ(Postgres対応)
dart pub add drift 

dart pub get
```

# サーバー起動

`bin` ディレクトリにあるファイル(todo_api.dart)に以下のようにサーバーを起動させる処理を書きます。

```dart
import 'package:shelf/shelf.dart';
import 'package:shelf/shelf_io.dart' as shelf_io;

void main(List<String> arguments) async {
  // リクエストを処理するハンドラー追加
  // ミドルウェア追加
  final handler = const Pipeline().addMiddleware(logRequests()).addHandler(_echoRequest);

  // サーバ起動
  var server = await shelf_io.serve(handler, 'localhost', 8080);

  // コンテンツ圧縮機能ON(レスポンス速度が上がる)
  server.autoCompress = true;

  // サーバ起動メッセージ
  print('Serving at http://${server.address.host}:${server.port}');
}

// リクエストを処理するハンドラー
Response _echoRequest(Request request) => Response.ok('Request for "${request.url}"');
```

`dart run`コマンドを実行してサーバを立ち上げて、ブラウザからアクセスしてみます。

以下結果になります。

```dart
todo_api % dart run
Building package executable... 
Built todo_api:todo_api.
Serving at http://localhost:8080
2024-12-31T17:36:34.376824  0:00:00.003498 GET     [200] /HelloShelf!
2024-12-31T17:36:34.416905  0:00:00.000083 GET     [200] /favicon.ico
```

![スクリーンショット 2024-12-31 17.36.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3868196/a52d6476-4935-5568-2d29-579c4d409680.png)


# おわりに

今回はDartのWebサーバーフレームワークであるshelfについてためしに触ってみました。小規模のREST APIサーバーやマイクロサービスとして使用できると思いました。
ただフレームワークとしての機能は少ないので、パッケージ導入や自前で実装する必要があります。
大規模で使用されるシステムの場合は、Spring BootとかLaravelのほうが良いかなと思いました。
もしくは 最近開発が進んでいる「Serverpod」、「Dart Frog」などもより安定すればAll Dartのバックエンドの選択肢になると思います！
すでにバックエンドでDartを採用されている企業もあるので、どんなふうにしているのか気になりました。