FlutterNinjas 2024: Exploring Full-Stack Dart for Firebase Server-Side Development
saigusa758cloudy
146 views
53 slides
Aug 06, 2024
Slide 1 of 53
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
About This Presentation
Exploring Full-Stack Dart for Firebase Server-Side Development
Flutter has revolutionized the way we build client-side applications, allowing us to create cross-platform apps swiftly with just Dart. Moreover, leveraging Firebase enables us to effortlessly utilize features like databases, authentica...
Exploring Full-Stack Dart for Firebase Server-Side Development
Flutter has revolutionized the way we build client-side applications, allowing us to create cross-platform apps swiftly with just Dart. Moreover, leveraging Firebase enables us to effortlessly utilize features like databases, authentication, and push notifications without delving into server-side development. However, when it comes to Firebase server-side processing, particularly Cloud Functions, Dart is often left out of the picture.
In this session, we will explore how to bridge this gap by utilizing various Google Cloud Platform services and tools, such as Cloud Run, Eventarc, Secret Manager, Workload Identity, and the gcloud CLI, along with the functions_framework and dart_firebase_admin packages. By doing so, we will demonstrate how Firebase server-side processing can be elegantly written in Dart, paving the way for a cohesive full-stack Dart development experience.
Join us as we delve into this exciting journey of expanding the Dart ecosystem beyond the client side, enabling Flutter developers to seamlessly integrate server-side functionalities and truly embrace the full potential of Dart in their applications.
Size: 2.28 MB
Language: en
Added: Aug 06, 2024
Slides: 53 pages
Slide Content
FlutterNinjas 2024
Exploring Full-Stack Dart for Firebase
Server-Side Development
Kosuke (@kosukesaigusa)
Hello, Flutter Ninjas!
FlutterNinjas 2024
kosukesaigusa1
About me
Kosuke Saigusa (@kosukesaigusa)
Application Engineer located in Japan
Flutter, Dart Lover
OSS & Community Contributor
pub.dev
geoflutterfire_plus
flutterfire_gen
...
Hold & Speak at Tech Conferences in Japan
FlutterNinjas 2024
kosukesaigusa 2
Goal
Exploring Full-Stack Dart for Firebase Server-Side
Development
Develop server-side processes for Firebase using Dart
Integration of various GCP services
Implement solutions with pub.dev packages:
functions_framework
dart_firebase_admin
FlutterNinjas 2024
kosukesaigusa 4
First Demo
Let's see sample app!
FlutterNinjas 2024
kosukesaigusa 5
Overview
FlutterNinjas 2024
kosukesaigusa 6
Cloud Run
FlutterNinjas 2024
kosukesaigusa 7
Cloud Run
FlutterNinjas 2024
Cloud Run is a managed compute
platform that lets you run
containers directly on top of
Google's scalable infrastructure.
You can deploy code written in any
programming language on Cloud
Run if you can build a container
image from it.
“
“
kosukesaigusa 8
functions_framework package
Developed by GoogleCloudPlatform organization
Provides a framework to write Dart functions and deploy it on Cloud
Run, GAE, ...etc
FlutterNinjas 2024
kosukesaigusa 11
Write HTTP Function in Dart
Write function with @CloudFunction in bin/functions.dart:
import 'package:functions_framework/functions_framework.dart';
import 'package:shelf/shelf.dart';
@CloudFunction()
Response hello(Request request) => Response.ok('Hello, Flutter Ninjas!');
Generate code:
dart pub run build_runner build -d
FlutterNinjas 2024
kosukesaigusa 12
Launch server:
$ dart run bin/server.dart
Listening on :8080
Request to server:
$ curl http://localhost:8080
Hello, Flutter Ninjas!
FlutterNinjas 2024
kosukesaigusa 14
Run in Container
Dockerfile
FROM dart:stable AS build
WORKDIR /app
COPY . .
RUN dart pub get
RUN dart pub run build_runner build -d
RUN dart compile exe bin/server.dart -o bin/server
FROM scratch
COPY --from=build /runtime/ /
COPY --from=build /app/bin/server /app/bin/
EXPOSE 8080
ENTRYPOINT ["/app/bin/server", "--target=hello", "--signature-type=http"]
FlutterNinjas 2024
kosukesaigusa 15
Build container:
docker build -t hello .
Run it:
$ docker run -it -p 8080:8080 --name app hello
Listening on :8080
Request to server:
$ curl http://localhost:8080
Hello, Flutter Ninjas!
FlutterNinjas 2024
kosukesaigusa 16
Demo
Try to run hello function on local machine!
FlutterNinjas 2024
kosukesaigusa 17
Deploy HTTP Function on Cloud Run
Deploy on Cloud Run with Dockerfile using gcloud CLI:
gcloud run deploy hello \ # Function (service) name
--source=. \ # Path to Dockerfile
--platform=managed \ # For Cloud Run
--allow-unauthenticated # For public access
Request to Cloud Run:
$ curl https://hello-<generated-url>-an.a.run.app
Hello, Flutter Ninjas!
Be careful of unauthenticated functions.
FlutterNinjas 2024
kosukesaigusa 18
FlutterNinjas 2024
kosukesaigusa 19
Demo
Deploy hello function to Cloud Run!
FlutterNinjas 2024
kosukesaigusa 20
Transfer Cloud Firestore event to Cloud Run
FlutterNinjas 2024
kosukesaigusa 28
Eventarc
FlutterNinjas 2024
Eventarc lets you build event-
driven architectures without
having to implement, customize, or
maintain the underlying
infrastructure. Eventarc offers a
standardized solution to manage
the flow of state changes, called
events, between decoupled
microservices.
“
“
kosukesaigusa 29
CloudEvents
FlutterNinjas 2024
CloudEvents is a specification for
describing event data in a common
way.
CloudEvents seeks to dramatically
simplify event declaration and
delivery across services, platforms,
and beyond!
“
“
kosukesaigusa 30
Write CloudEvents triggered Function in Dart
FlutterNinjas 2024
kosukesaigusa 31
Write CloudEvents triggered Function in Dart
Define function with @CloudFunction(), and give two parameters:
CloudEvent event
RequestContext context
@CloudFunction()
void oncreateevent(CloudEvent event, RequestContext context)
=> Response.ok('Hello, Flutter Ninjas!');
Only lowercase letters, numbers and '-' are allowed for function
name.
FlutterNinjas 2024
kosukesaigusa 32
Deploy CloudEvents triggered Function on Cloud Run
Set --signature-type=cloudevent to ENTRYPOINT option:
FROM dart:stable AS build
WORKDIR /app
COPY . .
RUN dart pub get
RUN dart pub run build_runner build -d
RUN dart compile exe bin/server.dart -o bin/server
FROM scratch
COPY --from=build /runtime/ /
COPY --from=build /app/bin/server /app/bin/
EXPOSE 8080
ENTRYPOINT ["/app/bin/server", "--target=oncreateevent" , "--signature-type=cloudevent" ]
FlutterNinjas 2024
kosukesaigusa 33
Deploy Eventarc trigger
Deploy Eventarc trigger using gcloud CLI
Transfer:
from Cloud Firestore: type=google.cloud.firestore.document.v1.created
to Cloud Run: oncreateevent
gcloud eventarc triggers create oncreateevent \ # Trigger name
--destination-run-service=oncreateevent \ # Destination function name
--event-filters="type=google.cloud.firestore.document.v1.created" \ # Event type
--event-filters="database=(default)" \
--event-filters="namespace=(default)" \
--event-filters-path-pattern="document=events/{eventId}" \ # Target path
--event-data-content-type="application/protobuf" \
--service-account="[email protected]"
FlutterNinjas 2024
kosukesaigusa 34
How to handle Raw CloudEvents data?
Request body is in application/protobuf byte data format:
[10, 195, 3, 10, 84, 112, 114, 111, 106, 101, 99, 116, 115, 47, 102, 117 ...]
FlutterNinjas 2024
kosukesaigusa 38
How to handle Raw CloudEvents data?
CloudEvents metadata found in header such as:
Triggered document
Triggered event type
{
"ce-dataschema": "https://github.com/googleapis/.../events/cloud/firestore/v1/data.proto",
"authorization": "Bearer ...",
"ce-subject": "documents/todos/6iGrCr5nJar6NNB8gPog",
"ce-source": "//firestore.googleapis.com/.../databases/(default)",
"ce-type": "google.cloud.firestore.document.v1.created", // Triggered event type
"content-type": "application/protobuf",
"ce-document": "todos/6iGrCr5nJar6NNB8gPog", // Triggered document
"ce-project": "...",
...
}
FlutterNinjas 2024
kosukesaigusa 39
firebase-functions (Node.js)
Node.js SDK provides:
Document path parameters from context.params.documentId
Triggered DocumentSnapshot snapshot
import * as functions from 'firebase-functions'
const onCreateTodo = functions
.region(`asia-northeast1`)
.firestore.document(`todos/{todoId}`)
.onCreate(async (snapshot, context) => {
const todoId = context.params.todoId
const data = snapshot.data()
const title = data.title
// ...
})
FlutterNinjas 2024
kosukesaigusa 40
Possible to write in Dart?
FlutterNinjas 2024
kosukesaigusa 41
dart_firebase_functions package
Still in early stages
Provides Node.js-like Firebase functions capability in Dart!
FlutterNinjas 2024
kosukesaigusa 42
onCreate
@OnDocumentCreated('todos/{todoId}')
Future<void> oncreatetodo(
({String todoId}) params,
QueryDocumentSnapshot snapshot,
RequestContext context,
) async {
final todoId = params.todoId;
final data = snapshot.data();
final title = data?['title'];
// ...
}
const onCreateTodo = functions
.region(`asia-northeast1`)
.firestore.document(`todos/{todoId}`)
.onCreate(async (snapshot, context) => {
const todoId = context.params.todoId
const data = snapshot.data()
const title = data.title
// ...
})
FlutterNinjas 2024
kosukesaigusa 43
onUpdate
@OnDocumentUpdated('todos/{todoId}')
Future<void> onupdatetodo(
({String todoId}) params,
({
QueryDocumentSnapshot before,
QueryDocumentSnapshot after,
}) snapshot,
RequestContext context,
) async {
final todoId = params.todoId;
final before = snapshot.before.data();
final after = snapshot.after.data();
final newTitle = after.title;
// ...
}
const onUpdateTodo = functions
.region(`asia-northeast1`)
.firestore.document(`todos/{todoId}`)
.onUpdate(async (snapshot, context) => {
const todoId = context.params.todoId
const before = snapshot.before.data()
const after = snapshot.after.data()
const newTitle = after.title
// ...
})
FlutterNinjas 2024
kosukesaigusa 44
onDelete
@OnDocumentDeleted('todos/{todoId}')
Future<void> ondeletetodo(
({String todoId}) params,
QueryDocumentSnapshot snapshot,
RequestContext context,
) async {
final todoId = params.todoId;
final data = snapshot.data();
final title = data?.title;
// ...
}
const onDeleteTodo = functions
.region(`asia-northeast1`)
.firestore.document(`todos/{todoId}`)
.onUpdate(async (snapshot, context) => {
const todoId = context.params.todoId
const data = snapshot.data()
const title = data.title
// ...
})
FlutterNinjas 2024
kosukesaigusa 45
onWrite
@OnDocumentUpdated('todos/{todoId}')
Future<void> onwritetodo(
({String todoId}) params,
({
QueryDocumentSnapshot before,
QueryDocumentSnapshot after,
}) snapshot,
RequestContext context,
) async {
final todoId = params.todoId;
final before = snapshot.before.data();
final after = snapshot.after.data();
final newTitle = after.title;
// ...
}
const onWriteTodo = functions
.region(`asia-northeast1`)
.firestore.document(`todos/{todoId}`)
.onWrite(async (snapshot, context) => {
const todoId = context.params.todoId
const before = snapshot.before.data()
const after = snapshot.after.data()
const newTitle = after?.title
// ...
})
FlutterNinjas 2024
kosukesaigusa 46
Nested Collection
@OnDocumentCreated('foos/{fooId}/bars/{barId}')
Future<void> oncreatebar(
({String fooId, String barId}) params,
QueryDocumentSnapshot snapshot,
RequestContext context,
) async {
final fooId = params.fooId;
final barId = params.barId;
final data = snapshot.data();
// ...
}
FlutterNinjas 2024
kosukesaigusa 47
Write Firestore triggered function in Dart:
@OnDocumentCreated('todos/{todoId}')
Future<void> oncreatetodo(
({String todoId}) params,
QueryDocumentSnapshot snapshot,
RequestContext context,
) async {
// Use Dart Firebase Admin SDK here.
}
Generate code:
dart pub run build_runner build -d
FlutterNinjas 2024
kosukesaigusa 48
Deploy it on Cloud Run
Set --signature-type=cloudevent to ENTRYPOINT option:
FROM dart:stable AS build
WORKDIR /app
COPY . .
RUN dart pub get
RUN dart pub run build_runner build -d
RUN dart compile exe bin/server.dart -o bin/server
FROM scratch
COPY --from=build /runtime/ /
COPY --from=build /app/bin/server /app/bin/
EXPOSE 8080
ENTRYPOINT ["/app/bin/server", "--target=oncreateevent" , "--signature-type=cloudevent" ]
FlutterNinjas 2024
kosukesaigusa 49
Final Demo
Let's see sample app's server-side code!
FlutterNinjas 2024
kosukesaigusa 50
Summary
In container, Dart executable can be run (Cloud Run)
HTTP and CloudEvents triggered functions are available in Dart,
thanks to functions_framework package
Firebase Admin SDK is available, thanks to dart_firebase_admin
package
Eventarc transfers CloudEvents from Cloud Firestore to Cloud Run
dart_firebase_function package provides Node.js-like Firebase
functions capability in Dart
FlutterNinjas 2024
kosukesaigusa 51