Serverpodを使ってみた

Serverpod

Serverpodとは Dart でサーバを書くために用意されたフレームワークです。今回はそちらを使ってみての感想をまとめていきます。

Get started

Installing Serverpod

まずは Serverpod をインストールしましょう。公式によると2023/7現在では serverpod は mac と linux で動かすことを推奨されているようです。Windows でも動くようですがまだ実験段階とのことなので Windows ユーザーはもう少し待ったほうがいいかもしれません。Serverpod をインストールするコマンドは以下の通りです。

$ dart pub global activate serverpod_cli

インストールが完了したら

$ serverpod

と打って実行してましょう。インストールが無事成功していればコマンドの詳細が表示されます。当然 Dart を使うわけなので Dart SDK が端末にインストール済みであることが条件です。筆者は Flutter のバージョン管理をするために fvm を使っていたので dart と打っても command not found: dart と出てしまいました。そんなときは ~/.pub-cache/bin にある serverpod のファイル内の dart コマンドの箇所を fvm dart に変更しましょう。

Serverpod Insights

Serverpod Insights は Serverpod の開発者が提供しているツールで、サーバの状態を可視化することができます。こちらからダウンロードできます。

プロジェクトを作ってみよう

実際にプロジェクトを立ち上げてみましょう。Docker Desktop が立ち上がっていることを確認して以下のコマンドを打ってみましょう。

$ serverpod create study_serverpod

プロジェクトの生成が終わると、study_serverpod_client, study_serverpod_flutter, study_serverpod_server の3つのディレクトリがデフォルトで生成されています。それぞれの役割については以下の通りです。

  • study_serverpod_client
    • サーバとの通信をするためのコードが入っています。基本は自動生成されたファイルを置く場所なので触らない
  • study_serverpod_flutter
    • Flutter でクライアントサイドを書くためのフォルダ。クライアントの処理はこちらで
  • study_serverpod_server
    • サーバサイドを書くためのフォルダ。サーバの処理はこちらで

サーバーを立ち上げよう

Docker Desktop の方も見てましょう。新たなコンテナが生成されています。そのコンテナを以下のコマンドで立ち上げましょう

$ cd study_serverpod_server
$ docker-compose up --build --detach
$ dart bin/main.dart

成功すれば

Insights listening on port 8081
Server default listening on port 8080
Webserver listening on port 8082

とターミナルに表示されます。

API のエンドポイントを作ってみよう

エンドポイントを追加するためには study_serverpod_server/lib/src/endpoints にファイルを追加して Endpoint を継承したクラスを作成し Future メソッドを作るだけです。初期段階ではすでに example_endpoint.dart がありその中でエンドポイントを追加するコードが書かれています。

import 'package:serverpod/serverpod.dart';

class ExampleEndpoint extends Endpoint {
  Future<String> hello(Session session, String name) async {
    return 'Hello $name';
  }
}

もしプリミティブ型以外で独自の型を持つデータを返したい場合は study_serverpod_server/lib/src/protocol に yaml ファイルを追加しクラス名とフィールドを指定してあげます。

class: Article  # クラス名
fields:         # フィールド
  title: String
  content: String
  published: DateTime
  isPrime: bool

新たな型クラスを追加したら下記コマンドを実行してプロトコルを生成します。 (このコマンドは study_serverpod_serverpod のルート直下で実行してください)

$ serverpod generate

完了すると generated フォルダに先ほどの yaml ファイルに対応したクラスが生成されます。これで新たな型を返すことができるようになりました。freezed や retrofit を使っている方にとってはコマンド1つでクラスを自動生成してくれて便利という感じが伝わるかと思います。

もしデータベースに同じモデルのテーブルを作りたい場合は先ほどの yaml ファイルに table を追加してあげましょう。

class: Article  # クラス名
table: articles # テーブル名
fields:         # フィールド
  title: String
  content: String
  published: DateTime
  isPrime: bool

再度 generate コマンドを打てば再生成されますが yaml ファイルを変更する度に generate コマンドを打つのはめんどくさいです。そんなときは以下のようなコマンドにすれば変更を監視しくれます。

$ serverpod generate --watch

続いて実際に記事を返すエンドポイントを追加しましょう。 example_endpoint.dart に以下のようなコードを追加してください。

Future<Article> getArticle(Session session, int id) async {
    return Article(
      title: 'Flutter with Serverpod',
      content: 'This is a test article.',
      published: DateTime.now(),
      isPrime: true,
      author: 'test',
    );
  }

先ほど serverpod generated --watch を実行していたので保存するだけで自動でコードが生成されますがもし ctrl+c で止めてしまった場合は再度 generate コマンドを打ってください。

Client から API を叩いてみよう

新たに API を追加できたので実際にクライアントから叩いてみましょう。 study_serverpod_flutter/lib/main.dart を開いてください。47行目にあるあるメソッドが hello API を叩いている処理になっています。

void _callHello() async {
    try {
      final result = await client.example.hello(_textEditingController.text);
      setState(() {
        _resultMessage = result;
      });
    } catch (e) {
      setState(() {
        _errorMessage = '$e';
      });
    }
  }

では記事を取得する処理を追加しましょう。

final result = await client.example.hello(_textEditingController.text);
final resultArticle = await client.example.getArticle(1);
print(resultArticle);

ここまでできたらアプリを起動してみましょう。study_serverpod_flutter からアプリを起動させます。(⚠️ Docker のコンテナとサーバーが起動していることを前提としています。) 筆者は iOS のシミュレータで実行するために pod install を実行したら以下のようなエラーが出ました。

[!] An error occurred while processing the post-install hook of the Podfile.

/Users/***/fvm/versions/3.10.3/bin/cache/artifacts/engine/ios/Flutter.xcframework must exist. If you're running pod install manually, make sure "flutter precache --ios" is executed first

flutter precache --ios を実行してねと書いてあったので実行したらエラーが解消されました。

また、現時点では Android と iOS のシミュレーターで build すると動きませんでした。Android は build 中から全く進まなくなり、iOS は module 'connectivity_plus' not found というエラーメッセージが表示されました。調べた限りの対策を試してみましたがダメでした(悔しい)。一応 web だと動くので現時点では web で試してみてください。動作結果が以下の画像になります。ちゃんと API を叩いてその結果を表示できていますね。

以上が Serverpod を触ってみたになります。Dart でもサーバーサイドをかけるというのはいいですね。次回は CRUD 操作をしてみたいと思います。