【Flutter】dart_frog でデータ操作からデプロイまで
初めに
今回は Dart Frog の使い方についてまとめてみたいと思います。
基本的な使い方から、Cloud Firestore でのデータ操作、Cloud Run へのデプロイまで各章に分けてみていきます。
記事の対象者
- Flutter 学習者
- Dart でバックエンド実装を行いたい方
- dart_frog でデータ操作、デプロイまで行いたい方
目的
今回の目的は、Dart Frog を用いたデータ操作の方法やデプロイについてざっくり理解することです。
Cloud Firestore でのデータ操作では簡単なCRUD処理を行う方法を理解することを目的とします。
また、デプロイに関しては今回は Cloud Run へのデプロイを行います。
扱わないこと
この記事では以下の項目については詳しく扱わないので、ご注意ください。
- Dart Frog のテスト
- dart_frog_auth を用いた認証
- Cloud Run 以外のサービスへのデプロイ
- Flutter 側の詳細なUI実装
Dart Frog とは
Dart Frog は Dart のバックエンドフレームワークです。
公式ページ で以下のように説明されています。
A fast, minimalistic backend framework for Dart
Dart 用の高速で最小限のバックエンドフレームワーク
加えて以下のような特徴が紹介されていました。
- スピードを重視した設計
- わずか数行で新しいエンドポイントを作成し、ホットリロードで非常に高速に反復処理を実行
- 軽量
- シンプルなコアと小さな API サーフェスにより、立ち上げ時間を最小限に抑える
- Dart
- Shelf、DevTools、テストなどを備えた強力な Dart エコシステムを活用
導入
以下のパッケージの最新バージョンを pubspec.yaml
に記述
dependencies:
flutter:
sdk: flutter
dart_frog: ^1.2.0
firedart: ^0.9.8
http: ^1.3.0
または
以下をターミナルで実行
flutter pub add dart_frog firedart http
記事の後半では、Cloud Firestore を用いたデータ操作や Cloud Run へのデプロイを行います。したがって、Firebase のプロジェクトを作成したり、 Cloud Run を有効化する必要があります。
これらの手順については公式ドキュメント等を参照していただければと思います。
実装手順
今回は以下の手順で実装を進めていきます。
1 ~ 6 で Dart Frog の簡単な扱い方を公式ドキュメント をもとに見ていきます。
7, 8 で Cloud Firestore のデータ操作や Cloud Run へのデプロイを扱います。
- プロジェクトの作成
- 実行方法
- 新しいルートの作成
- bodyへのアクセス
- クエリパラメータへのアクセス
- メソッドの種類の判定
- Cloud Firestore のデータ操作
- Cloud Run へのデプロイ
1. プロジェクトの作成
dart_frog のプロジェクトは以下の2ステップで作成できます。
Dart Frog CLI のインストール
以下のコマンドで Dart Frog CLI をインストールしてアクティベートできます。
これで dart_frog が使用できるようになります。
dart pub global activate dart_frog_cli
プロジェクト作成
dart_frog create
コマンドで新たにプロジェクトを作成することができます。
dart_frog create my_project
全く新しいディレクトリとして Dart Frog のプロジェクトを作成した場合は以下のようなディレクトリが作成されるかと思います。
my_project/
├── .dart_frog/
├── .dart_tool/
├── .vscode/
├── routes/
│ ├── index.dart
├── test/
├── .gitignore
├── README.md
├── analysis_options.yaml
├── pubspec.lock
└── pubspec.yaml
Flutter アプリに backend として組み込む場合は以下のようなディレクトリ構造になるかと思います。
dart_frog_sample/
├── .dart_tool/
├── .idea/
├── .vscode/
├── android/
├── backend/ // backend プロジェクトを Dart Frog で作成
│ ├── .dart_frog/
│ ├── .dart_tool/
│ ├── .vscode/
│ ├── routes/
│ ├── test/
│ ├── analysis_options.yaml
│ ├── pubspec.lock
│ ├── pubspec.yaml
│ └── README.md
├── ios/
├── lib/
├── linux/
├── macos/
├── test/
├── web/
├── windows/
├── .gitignore
├── .metadata
├── analysis_options.yaml
├── dart_frog_sample.iml
├── pubspec.lock
├── pubspec.yaml
└── README.md
筆者の手元では後者の既存 Flutter アプリに組み込んだ場合を想定して実装していきます。
2. 実行方法
次に、作成したプロジェクトを開いて実行してみます。
デフォルトで routes/index.dart
に以下のようなコードが記載されます。
import 'package:dart_frog/dart_frog.dart';
Response onRequest(RequestContext context) {
return Response(body: 'Welcome to Dart Frog!');
}
この関数をローカルで実行するには、Dart Frog のルートディレクトリで以下のコマンドを実行します。
dart_frog dev
すると以下のような出力が見つかります。
✓ Running on http://localhost:8080 (78ms)
http://localhost:8080
にブラウザでアクセスするか、ターミナルで以下のコマンドを実行することで、出力結果を確認することができます。
curl --request GET --url http://localhost:8080
ブラウザで確認すると以下のような結果になります。
routes/index.dart
のコードの Response に書かれていたテキストが表示されています。
なお、デフォルトのポート番号は 8080
に設定されていますが、/.dart_frog/server.dart
の以下の部分を変更するか、実行時に PORT={任意のポート番号} dart_frog dev
のように明示的に指定することで変更することができます。
void main() async {
final address = InternetAddress.tryParse('') ?? InternetAddress.anyIPv6;
final port = int.tryParse(Platform.environment['PORT'] ?? '8080') ?? 8080;
hotReload(() => createServer(address, port));
}
これで実装したコードを実行できるようになりました。
3. 新しいルートの作成
次に新しいルートを作成してみます。
Dart Frog では、File-based routing が採用されています。
Dart Frog で実装されているプロジェクトのディレクトリ構造がそのままルーティングに使用されます。
例えば、routes/hello.dart
のようなルートにファイルを作成すると、そのファイルは /hello
エンドポイントに対応するようになります。
したがって、routes/posts/[id].dart
のように定義すると、 /posts/1
, /posts/2
などのパスに対応して動的なルーティングが実装できます。
ただ、今回は動的なルーティングについては扱いません。
以上の点を踏まえて、新しいルートの作成を行います。
新しいルートは以下のコマンドで作成できます。
dart_frog new route {作成するファイルのルート}
Dart Frog のルートディレクトリで以下のコマンドを実行してみると、routes/new_route.dart
ファイルが作成されます。
dart_frog new route new_route
作成された routes/new_route.dart
ファイルは以下のようになっています。
import 'package:dart_frog/dart_frog.dart';
Response onRequest(RequestContext context) {
// TODO: implement route handler
return Response(body: 'This is a new route!');
}
新しいルートを作成して、 dart_frog dev
が実行されている状態で、ブラウザで http://localhost:8080/new_route
にアクセスしてみると以下のようになっています。
routes/new_route.dart
に記載されている内容が反映されていることがわかります。
4. bodyへのアクセス
次に、リクエストの body にアクセスしてみます。
以下のコマンドで新たにルートを作成します。
dart_frog new route body_access
内容を以下のように修正します。
リクエストの body には context.request
の body()
でアクセスできます。
import 'package:dart_frog/dart_frog.dart';
Future<Response> onRequest(RequestContext context) async {
final request = context.request;
final body = await request.body();
return Response(body: 'The body is "$body".');
}
以下のコマンドを実行して、新たに作成された http://localhost:8080/body_access
にアクセスすると「The body is "".」というテキストが表示されているかと思います。
リクエストの body に特にデータを指定していない場合はこのようになります。
curl --request GET --url http://localhost:8080/body_access
エントリーポイントの末尾に --data="Hello World !"
を追加して以下のようなコマンドを実行すると、「The body is "Hello World !".」というテキストが表示されるかと思います。
curl --request GET --url http://localhost:8080/body_access --data 'Hello World !'
このように、 context.request
の body()
でリクエストの body にアクセスできるようになります。
5. クエリパラメータへのアクセス
次に、リクエストのクエリパラメータにアクセスしてみます。
以下のコマンドで新たにルートを作成します。
dart_frog new route query_params
内容を以下のように修正します。
リクエストのクエリパラメータには context.request
の uri.queryParameters
でアクセスできます。
import 'package:dart_frog/dart_frog.dart';
Response onRequest(RequestContext context) {
final request = context.request;
final params = request.uri.queryParameters;
final name = params['name'] ?? 'there';
return Response(body: 'Hi $name');
}
ファイルの変更が完了したら、 http://localhost:8080/query_params?name=John
のように、name
パラメータを指定してブラウザを開きます。
すると、「Hi John」というテキストが表示されているかと思います。
このようにしてクエリパラメータにアクセスすることができるようになります。
もちろん、以下のようなコードにすることで、複数のクエリパラメータを渡すこともできます。
import 'package:dart_frog/dart_frog.dart';
Response onRequest(RequestContext context) {
final request = context.request;
final params = request.uri.queryParameters;
final name = params['name'] ?? 'there';
+ final age = params['age'] ?? 'unknown';
return Response(body: 'Hi $name, you are $age years old');
}
// http://localhost:8080/query_params?name=John&age=20
// Hi John, you are 20 years old
6. メソッドの種類の判定
次にメソッドの種類を判定してみます。
以下のコマンドで新たにルートを作成します。
dart_frog new route method_access
内容を以下のように修正します。
リクエストのメソッドには context.request
の method.value
でアクセスできます。
import 'package:dart_frog/dart_frog.dart';
Response onRequest(RequestContext context) {
final request = context.request;
final method = request.method.value;
switch (method) {
case 'GET':
return Response(body: 'This is a GET request.');
case 'POST':
return Response(body: 'This is a POST request.');
case _:
return Response(body: 'This method is not allowed.');
}
}
ファイルの変更が完了したら、以下のコマンドを実行してみます。
curl --request GET --url http://localhost:8080/method_access
すると、以下のように GET メソッドであると判定されます。
This is a GET request.
このようにメソッドを判定することで、メソッドに応じた処理を指定することができます。
7. Cloud Firestore のデータ操作
次に Cloud Firestore におけるデータ操作を実装してみたいと思います。
Dart Frog を通して Cloud Firestore のデータ操作を行う場合は firedart パッケージを使用します。
実装
次に新たなルートを作成します。
以下のようなコマンドで、 routes
ディレクトリ内で新たに index.dart
, _middleware.dart
ファイルを生成します。
dart_frog new route /db/firestore
dart_frog new route /db/firestore/_middleware
これで routes/db/firestore
ディレクトリ内に、 index.dart
, _middleware.dart
の二つのファイルが作成されます。
index.dart
では、 Cloud Firestore を用いた処理を実装していきます。
_middleware.dart
では、 Middleware を作成し、 Cloud Firestore のデータ操作に必要な設定を行います。
_middleware.dart の実装
まずは _middleware.dart
の編集を行います。
Middleware では、リクエストが処理される前後に実行する処理を定義することができます。
_middleware.dart
という名前で定義されたファイルは同じ階層のリクエストの Middleware として扱われるようになります。
今回は Cloud Firestore にリクエストを送る前に、 Firebase のプロジェクトIDを渡して初期化する処理が必要になります。したがって、その処理を Middleware で行います。
コードは以下の通りです。
import 'dart:io';
import 'package:dart_frog/dart_frog.dart';
import 'package:firedart/firedart.dart';
Handler middleware(Handler handler) {
final projectId = Platform.environment['FIRESTORE_PROJECT_ID'];
if (projectId == null) {
throw Exception('FIRESTORE_PROJECT_ID is not set');
}
return (context) async {
if (!Firestore.initialized) {
Firestore.initialize(projectId);
}
final response = await handler(context);
return response;
};
}
詳しくみていきます。
以下では、 Firebase のプロジェクトIDを読み取っています。
Platform.environment
では環境変数を読み取ることができます。
プロジェクトIDやシークレットキーなどは dart_frog dev
でサーバーを起動する段階で事前に環境変数として定義しておくことができます。
もし環境変数として Firebase のプロジェクトIDが定義されていない場合は Exception を投げるようにしています。
Handler middleware(Handler handler) {
final projectId = Platform.environment['FIRESTORE_PROJECT_ID'];
if (projectId == null) {
throw Exception('FIRESTORE_PROJECT_ID is not set');
}
今回の場合は以下のようなコマンドを実行することで、コード内に Firebase のプロジェクトIDを含まずにアプリを実行することができるようになります。
FIRESTORE_PROJECT_ID={FirebaseのプロジェクトID} dart_frog dev
Firebase のプロジェクトID
Firebase のプロジェクトIDは Firebase Console > プロジェクトの設定 > プロジェクトID で確認することができます。
先程のコードの以下の部分では、 Firestore が初期化されていない場合に限って、環境変数から読み込んだ projectId
を渡すことで Firestore の初期化を行なっています。
その後に await handler(context)
を記述することで、リクエストを受け取る前の段階で Firestore の初期化を済ませることができます。
return (context) async {
if (!Firestore.initialized) {
Firestore.initialize(projectId);
}
final response = await handler(context);
return response;
};
これで _middleware.dart
の実装は完了です。
_middleware.dart の内容
import 'dart:io';
import 'package:dart_frog/dart_frog.dart';
import 'package:firedart/firedart.dart';
Handler middleware(Handler handler) {
print('middleware is activated');
final projectId = Platform.environment['FIRESTORE_PROJECT_ID'];
if (projectId == null) {
throw Exception('FIRESTORE_PROJECT_ID is not set');
}
return (context) async {
if (!Firestore.initialized) {
Firestore.initialize(projectId);
}
final response = await handler(context);
return response;
};
}
index.dart の実装
次に、 Cloud Firestore のデータ操作を含む index.dart
の実装を行います。
index.dart
の処理は以下の7つに分けてみていきます。
- モデルの定義
- メソッドの判定
- POST処理
- GET処理
- PUT処理
- DELETE処理
- その他の処理
まずはモデルの定義を行います。
Dart Frog で使用するモデルは、freezed を用いて作成することができます。しかし、 build_runner
ではなく、別の方法で生成する必要があったので、今回は単純なクラスの定義にしています。
コードは以下の通りです。
今回は ID, 名前、メールアドレスを持つ DartFrogUser
という簡単なクラスを例にして実装していきます。ID だけは Cloud Firestore 側で生成するため Nullable に設定しています。
class DartFrogUser {
DartFrogUser({
required this.name,
required this.email,
this.id,
});
factory DartFrogUser.fromJson(Map<String, dynamic> json) => DartFrogUser(
id: json['id'] as String?,
name: json['name'] as String,
email: json['email'] as String,
);
factory DartFrogUser.fromDocument(Document doc) => DartFrogUser(
id: doc.id,
name: doc.map['name'] as String,
email: doc.map['email'] as String,
);
final String? id;
final String name;
final String email;
Map<String, dynamic> toJson() => {
'name': name,
'email': email,
};
}
次にメソッドの判定部分についてみていきます。
コードは以下の通りです。
前の章でも扱った通り、メソッドの種類は context.request.method
で取得することができます。 method
の switch文でそれぞれのメソッドに応じた処理を実装していきます。
また、userCollection
として、 Firestore のコレクションを指定しています。このコレクションに対して Firestore のデータ操作を行います。
Future<Response> onRequest(RequestContext context) async {
final request = context.request;
final method = request.method;
final usersCollection = Firestore.instance.collection('users');
try {
switch (method) {
case HttpMethod.post:
...
case HttpMethod.get:
...
次にPOST処理についてみていきます。
コードは以下の通りです。
POST処理では、ユーザーの新規作成を行うようにしています。
request.json() as Map<String, dynamic>
でリクエストを Map<String, dynamic>
型に変換します。
そしてそれを DartFrogUser.fromJson
で DartFrogUser
に変換します。
変換したデータを usersCollection.add
で指定したコレクションに追加しています。
これで Firestore へのデータの追加が完了します。
データの追加が完了したら、返り値としてドキュメントIDを含む新規ユーザーのデータを返しています。また、この時 201
ステータスコードを返すようにしています。
case HttpMethod.post:
final data = await request.json() as Map<String, dynamic>;
final user = DartFrogUser.fromJson(data);
final doc = await usersCollection.add(user.toJson());
final document = await usersCollection.document(doc.id).get();
final createdUser = DartFrogUser.fromDocument(document);
return Response.json(
body: {
'id': createdUser.id,
...user.toJson(),
},
statusCode: 201,
);
次にGET処理についてみていきます。
コードは以下の通りです。
GET処理はユーザーの全件取得と特定のユーザーの取得の2種類を実装しています。
リクエストのクエリパラメーターに userId
が含まれる場合はそのIDに一致するユーザーを取得し、含まれない場合はユーザーの全件取得を行っています。
特定のユーザーを取得する場合は usersCollection.document(userId).get()
で取得します。
全件取得する場合は usersCollection.get()
で取得します。
case HttpMethod.get:
final queryParams = request.uri.queryParameters;
final userId = queryParams['id'];
if (userId != null) {
try {
final document = await usersCollection.document(userId).get();
final user = DartFrogUser.fromDocument(document);
return Response.json(
body: {
'id': user.id,
...user.toJson(),
},
);
} catch (e) {
return Response.json(
statusCode: 404,
body: {'error': 'User not found'},
);
}
}
final documents = await usersCollection.get();
final users = documents.map((doc) {
final user = DartFrogUser.fromDocument(doc);
return {
'id': user.id,
...user.toJson(),
};
}).toList();
return Response.json(body: users);
次にPUT処理についてみていきます。
コードは以下の通りです。
PUT処理では、リクエストのクエリパラメータの含まれる userId
と一致するユーザーの更新を行なっています。 userId
が存在しない場合や、 userId
に一致するユーザーのデータが存在しない場合はステータスコード 400
, 404
を返すようにしています。
データの更新処理は docRef.update
メソッドで行います。
リクエストの body に含まれるデータを DartFrogUser
に変換して渡しています。
case HttpMethod.put:
final userId = request.uri.queryParameters['id'];
if (userId == null) {
return Response.json(
statusCode: 400,
body: {'error': 'User ID is required'},
);
}
try {
final docRef = usersCollection.document(userId);
final doc = await docRef.get();
if (doc.map.isEmpty) {
return Response.json(
statusCode: 404,
body: {'error': 'User not found with id: $userId'},
);
}
final data = await request.json() as Map<String, dynamic>;
final user = DartFrogUser.fromJson(data);
await docRef.update(user.toJson());
final updatedDoc = await docRef.get();
final updatedUser = DartFrogUser.fromDocument(updatedDoc);
return Response.json(
body: {
'id': updatedUser.id,
...updatedUser.toJson(),
},
);
} catch (e) {
return Response.json(
statusCode: 400,
body: {'error': 'Invalid request data'},
);
}
次にDELETE処理についてみていきます。
コードは以下の通りです。
リクエストのクエリパラメータに含まれる userId
を取得し、それに合致するユーザーのデータを取得して削除しています。
データの削除は docRef.delete
メソッドで実行できます。
case HttpMethod.delete:
final userId = request.uri.queryParameters['id'];
if (userId == null) {
return Response.json(
statusCode: 400,
body: {'error': 'User ID is required'},
);
}
try {
final docRef = usersCollection.document(userId);
final doc = await docRef.get();
if (doc.map.isEmpty) {
return Response.json(
statusCode: 404,
body: {'error': 'User not found with id: $userId'},
);
}
await docRef.delete();
return Response.json(
statusCode: 200,
body: {'message': 'User deleted successfully'},
);
} catch (e) {
return Response.json(
statusCode: 500,
body: {'error': 'Failed to delete user'},
);
}
最後にその他の処理についてみていきます。
コードは以下の通りです。
これまでのメソッドに当てはまらない場合はステータスコード405を返すようにしておきます。
case _:
return Response.json(
statusCode: 405,
body: {'error': 'Method not allowed'},
);
index.dart の内容
import 'package:dart_frog/dart_frog.dart';
import 'package:firedart/firedart.dart';
class DartFrogUser {
DartFrogUser({
required this.name,
required this.email,
this.id,
});
factory DartFrogUser.fromJson(Map<String, dynamic> json) => DartFrogUser(
id: json['id'] as String?,
name: json['name'] as String,
email: json['email'] as String,
);
factory DartFrogUser.fromDocument(Document doc) => DartFrogUser(
id: doc.id,
name: doc.map['name'] as String,
email: doc.map['email'] as String,
);
final String? id;
final String name;
final String email;
Map<String, dynamic> toJson() => {
'name': name,
'email': email,
};
}
Future<Response> onRequest(RequestContext context) async {
final request = context.request;
final method = request.method;
final usersCollection = Firestore.instance.collection('users');
try {
switch (method) {
case HttpMethod.post:
final data = await request.json() as Map<String, dynamic>;
final user = DartFrogUser.fromJson(data);
final doc = await usersCollection.add(user.toJson());
final document = await usersCollection.document(doc.id).get();
final createdUser = DartFrogUser.fromDocument(document);
return Response.json(
body: {
'id': createdUser.id,
...user.toJson(),
},
statusCode: 201,
);
case HttpMethod.get:
final queryParams = request.uri.queryParameters;
final userId = queryParams['id'];
if (userId != null) {
try {
final document = await usersCollection.document(userId).get();
final user = DartFrogUser.fromDocument(document);
return Response.json(
body: {
'id': user.id,
...user.toJson(),
},
);
} catch (e) {
return Response.json(
statusCode: 404,
body: {'error': 'User not found'},
);
}
}
final documents = await usersCollection.get();
final users = documents.map((doc) {
final user = DartFrogUser.fromDocument(doc);
return {
'id': user.id,
...user.toJson(),
};
}).toList();
return Response.json(body: users);
case HttpMethod.put:
final userId = request.uri.queryParameters['id'];
if (userId == null) {
return Response.json(
statusCode: 400,
body: {'error': 'User ID is required'},
);
}
try {
final docRef = usersCollection.document(userId);
final doc = await docRef.get();
if (doc.map.isEmpty) {
return Response.json(
statusCode: 404,
body: {'error': 'User not found with id: $userId'},
);
}
final data = await request.json() as Map<String, dynamic>;
final user = DartFrogUser.fromJson(data);
await docRef.update(user.toJson());
final updatedDoc = await docRef.get();
final updatedUser = DartFrogUser.fromDocument(updatedDoc);
return Response.json(
body: {
'id': updatedUser.id,
...updatedUser.toJson(),
},
);
} catch (e) {
return Response.json(
statusCode: 400,
body: {'error': 'Invalid request data'},
);
}
case HttpMethod.delete:
final userId = request.uri.queryParameters['id'];
if (userId == null) {
return Response.json(
statusCode: 400,
body: {'error': 'User ID is required'},
);
}
try {
final docRef = usersCollection.document(userId);
final doc = await docRef.get();
if (doc.map.isEmpty) {
return Response.json(
statusCode: 404,
body: {'error': 'User not found with id: $userId'},
);
}
await docRef.delete();
return Response.json(
statusCode: 200,
body: {'message': 'User deleted successfully'},
);
} catch (e) {
return Response.json(
statusCode: 500,
body: {'error': 'Failed to delete user'},
);
}
case _:
return Response.json(
statusCode: 405,
body: {'error': 'Method not allowed'},
);
}
} catch (e) {
return Response.json(
statusCode: 500,
body: {'error': e.toString()},
);
}
}
これで Cloud Firestore のデータ操作の実装は完了です。
8. Cloud Run へのデプロイ
最後に Cloud Run へのデプロイまで行いたいと思います。
Cloud Run へのデプロイは Dart Frog の Deploy > Google Cloud Run のドキュメントをもとに行います。
デプロイは以下の手順で行います。
なお、すでに gcloud コマンドが使用できる場合はステップ2から進められます。
- gcloud コマンドのインストール、ログイン
- ビルド
- デプロイ
1. gcloud コマンドのインストール、ログイン
gcloud コマンドがインストールされていない場合は gcloud CLI をインストールする のドキュメントを見ながらインストールしていきます。
基本的にはドキュメントに沿って進めていくと gcloud コマンドが使用できるようになります。
なお、自分の手元では command not found になったため、こちらの記事を参考にさせていただいて解消できました。
gcloud コマンドがインストールできたらログインを実行します。
ターミナルで以下のコマンドを実行して、 gcloud login を行います。
gcloud auth login
コマンドを実行すると以下のようにログインを求められるので、ログインしておきます。
2. ビルド
次に Dart Frog を用いた実装を行なったディレクトリで以下のコマンドを実行します。
dart_frog build
これでルートディレクトリに build
ディレクトリが作成されます。
この build
ディレクトリ配下のファイルをもとにしてデプロイを行います。
3. デプロイ
build
ディレクトリが作成されたら最後にデプロイを行います。
以下のコマンドでデプロイができます。
gcloud run deploy [SERVICE_NAME] \
--source build \
--project=[PROJECT_ID] \
--region=[REGION] \
--allow-unauthenticated
SERVICE_NAME
はデプロイしたい関数の名前を指定しておきます。
source
では build
ディレクトリを指定しておくことで、build
ディレクトリの内容をもとにデプロイを行うことができます。
PROJECT_ID
は Cloud Firestore のデータ操作を行なった際に指定したIDと同じで、Firebase Console > プロジェクトの設定 > プロジェクトIDで確認することができます。
REGION
はデプロイを行うリージョンを指定します。東京の場合は asia-northeast1
となります。それぞれのリージョンはこちらで参照可能です。
allow-unauthenticated
の指定をしておくことで、認証していないユーザーからのアクセスも受け入れるように設定することができます。
例えば以下のコマンドでは、 user-management123
というプロジェクトIDのプロジェクトにおいて、東京リージョンで users
という名前のサービスをデプロイすることができます。
gcloud run deploy users \
--source build \
--project=user-management123 \
--region=asia-northeast1 \
--allow-unauthenticated
デプロイが完了してから少し時間をおいて、 Cloud Run を確認してみるとデプロイされたサービスを確認できるかと思います。
あとは作成された Cloud Run のエンドポイントを指定して叩けば Dart Frog で書かれた処理が実行されるかと思います。
以上です。
まとめ
最後まで読んでいただいてありがとうございました。
今回は Dart Frog を用いた基本的な実装や Cloud Firestore のデータ操作、デプロイを行う方法についてまとめました。
やはりフロントエンドとバックエンドで言語を統一して実装できるので、実装やしやすいように感じました。
誤っている点やもっと良い書き方があればご指摘いただければ幸いです。
参考
Discussion