$30 off During Our Annual Pro Sale. View Details »

DartによるBFF構築・運用 〜 Dart Frog × Melos 〜

Ryotaro Onoue
November 10, 2023

DartによるBFF構築・運用 〜 Dart Frog × Melos 〜

FlutterKaigi 2023 登壇資料

Ryotaro Onoue

November 10, 2023
Tweet

More Decks by Ryotaro Onoue

Other Decks in Programming

Transcript

  1. スピーカー名
    DartによるBFF構築・運用 〜
    Dart Frog × Melos 〜
    もぐもぐ / K9i

    View Slide

  2. 自己紹介

    View Slide

  3. もぐもぐ
    ↓こんなの

    View Slide

  4. もぐもぐ
    - Ryotaro Onoue
    - なんでもぐもぐにしたのか覚えてません
    - 食べるのは好きです
    - ゆめみのFlutterエンジニア
    - 2023年4月に新卒として入社
    - Flutter/Dart歴 3年

    View Slide

  5. もぐもぐ
    - 地震関連のアプリ開発してます
    - 今年中にアプリストアでリ
    リース予定

    View Slide

  6. K9i

    View Slide

  7. K9i
    - Kota Hayashi
    - K9iはK8s(Kubernetes)とかL10n(Localization)と同じ感じ
    - Kota->Tako->🐙
    - K9iはケーナインアイだがいいづらいので、林呼び推奨
    - ゆめみのFlutterリードエンジニア
    - 1社目:Androidなど(この時期に趣味でFlutterをはじめた)
    - 2社目:Flutter
    - 3社目:今年の5月からゆめみ
    - Flutterは4年目くらい

    View Slide

  8. K9i
    - RiverpodのChangelogに稀に生息

    View Slide

  9. 会社の紹介

    View Slide

  10. 株式会社ゆめみ
    - 公式アカウントの大喜利で有名😅

    View Slide

  11. ゆめみFlutterギルド
    - イベントやっとります

    View Slide

  12. アジェンダ

    View Slide

  13. アジェンダ(1/3)
    1. Dartバックエンドの世界
    a. Dartのおさらい
    b. Dartバックエンドフレームワークの紹介
    c. BFFとは
    2. プロジェクトの背景
    a. ゆめみ参入の経緯
    b. バックエンドの構成変更
    c. Flutter向けBFFの方針
    前半

    View Slide

  14. アジェンダ(2/3)
    3. 技術スタックの紹介
    a. Flutterチーム担当領域のプロジェクト構成
    b. Dart Frog解説
    c. Melos解説
    4. 実践した感想
    a. Dockerのつらみ
    b. [TODO]
    後半

    View Slide

  15. アジェンダ(3/3)
    5. Liveデモ
    a. [TODO]
    6. まとめ
    後半

    View Slide

  16. 1. Dartバックエンドの世界

    View Slide

  17. Dartのおさらい

    View Slide

  18. Dartとは
    - Googleが開発
    - 2011年10月10日に登場

    View Slide

  19. Dartのこれまで(超ダイジェスト)
    - JavaScriptの代替となることを目的に作られた
    - 2011年末までにVMがChromeに統合される予定だった
    - 普及は進まず2015年にはChrome統合を断念
    - Skyフレームワーク(Flutterの前身)がJavaScriptの変わりとなる言語と
    探していたところDartと出会う
    - 2015年にSkyがDartをはじめて導入
    - 以降Flutterとともに成長し今に至る

    View Slide

  20. Dartバックエンドという選択肢
    - Flutterの普及に伴いバックエンドもDartで開発したい欲求
    - 言語を統一することで様々なメリット
    - 同じメンバーがフロントエンドもバックエンドも開発
    - コードの共有・再利用
    - ツール・ライブラリの共通化
    - etc…

    View Slide

  21. Dartバックエンド
    フレームワークの紹介

    View Slide

  22. Aquaduct
    - 概要
    - 懐かしかったので紹介(知ってたら古参?)
    - Stable Kernelが2018年に開発
    - 2021年に開発中止されリポジトリはPublic archive
    - Conduct
    - AquaductのFork
    - 活発に開発されてはなさそう?(最終更新半年前)

    View Slide

  23. Serverpod
    - Serverpod社が開発するFlutter向けのアプリサーバー
    - トップページに「The missing server for Flutter」とありFlutterを
    強く意識している
    - 2021年に発表され、2023年1月31日に1.0になった
    - CLIでプロジェクトを作成するとFlutterアプリとバックエンドが両方作成さ
    れる
    - 後述するDart Frogなどに比べ多機能な印象

    View Slide

  24. Shelf
    - Dartチームによって開発されているサーバーフレームワーク
    - 0.1.0は2014年に公開
    - Shelf本体は軽量
    - 複数のShelf用パッケージを組み合わせて使うモジュール方式
    - shelfのリポジトリだけでも複数のパッケージが存在

    View Slide

  25. View Slide

  26. Dart Frog
    - VGV(Very Good Ventures)が開発しているサーバーフレームワーク
    - 開発元がFlutter界隈で有名なので注目されている
    - 2022年に発表され、2023年8月2日に1.0.0になった
    - Shelfをベースに構築されている、Shelf同様軽量
    - こちらも複数パッケージを組み合わせるモジュール方式
    - Shelfをより便利に使えるような機能がある
    - 技術スタック紹介の章で説明

    View Slide

  27. BFFとは

    View Slide

  28. BFFとは
    - BFF(Backend For Frontend)
    - 初めて名前を聞くと言う人もいるかも?
    - フロントエンド(アプリ含む)とバックエンドの中間に置かれるサーバー
    - ???

    View Slide

  29. BFFの例1:バックエンドが複数

    View Slide

  30. BFFの例2:フロントエンドが複数

    View Slide

  31. BFFとは
    - メリット
    - APIの集約
    - 複数のバックエンドを一つのAPIでフロントエンドに提供
    - 特定のフロントエンドに特化
    - WebにはGraphQL、アプリにはREST
    - 開発言語も対応するフロントエンドと揃えたりできる
    - デメリット
    - 開発コスト
    - 複雑・冗長

    View Slide

  32. 2. プロジェクトの背景

    View Slide

  33. ゆめみの参入の経緯

    View Slide

  34. 参入プロジェクト
    - 介護・看護分野の企業と労働者のマッチングサービス
    - PMF(プロダクトマーケットフィット)の段階
    - フロントエンドは3種類存在
    - 企業用Webフロントエンド
    - 労働者用Webフロントエンド
    - 労働者用モバイルアプリ(これを担当)

    View Slide

  35. 参入前のプロジェクトのメンバー
    - バックエンド、PMなど:顧客企業の方がフルタイム稼働
    - ゆめみはクライアントワーク
    - Webフロント:ゆめみのフロントメンバー(別チーム)が日中稼働
    - モバイルアプリ:副業メンバーが夜間など不規則な稼働

    View Slide

  36. 参入前の課題
    - モバイルアプリの開発メンバーが不規則な稼働
    - クライアント企業の方とコミュニケーションがとりづらい
    - 思うようにモバイルアプリ開発が進んでいなかった
    - Flutter・Dart得意なメンバー不在
    - 全体的に負債の塊
    - ゆめみのFlutterギルド参入で課題を解決したい
    - 今年8月〜

    View Slide

  37. バックエンドの構成変更

    View Slide

  38. バックエンドの構成変更
    - プロジェクト参入次点でバックエンドの構成変更が進行中
    - PMF期に生じた負債の解消

    View Slide

  39. 元々の構成

    View Slide

  40. 元々の構成
    旧バックエンドは元々モバイルアプリ
    用に作られたが、Webからも使われ
    るようになってしまう
    特定のフロントエンドのための分岐と
    うで複雑に

    View Slide

  41. 目的とする構成

    View Slide

  42. 目的とする構成
    フロントエンドごとに BFFを作り、特定
    のフロントエンドのためのロジックを
    移譲
    旧バックエンドは廃止

    View Slide

  43. Flutter向けBFFの方針

    View Slide

  44. Flutterチームの担当

    View Slide

  45. Flutter向けBFFの方針
    - 実は作り途中のBFFがあったが…
    - 色々と課題…
    - 廃止されるまでは旧バックエンドも部分的に使う
    - Dartで統一
    - Jsonをやり取りするクラスをクライアントと共通化
    - せっかく新規に作るので気になる技術を試す
    - Dart Frog、Melos
    - 賛否有りそうだけど大事

    View Slide

  46. Flutter向けBFFの方針

    View Slide

  47. Flutter向けBFFの方針 旧バックエンドを当分は直接利用
    いずれは消える

    View Slide

  48. Flutter向けBFFの方針 初期リリースでは一部のエンドポイン
    トラップ(とりあえず動かすため)

    View Slide

  49. 3. 技術スタックの紹介

    View Slide

  50. Flutterチーム担当領域の
    プロジェクト構成

    View Slide

  51. リポジトリ・パッケージ構成

    View Slide

  52. 主な利用技術
    - Melos
    - マルチパッケージ構成の管理に利用
    - Dart Frog
    - BFFの実装に利用
    - Freezed、JsonSerializable
    - クライアントとBFFで共有する通信用の型で利用
    - 一般的だと思うので解説しません🙏

    View Slide

  53. Melos解説

    View Slide

  54. マルチパッケージとは
    - 複数のDartパッケージでプロジェクトを構成する手法
    - 機能やレイヤーごとのディレクトリを作るのではなく、パッケージに切
    り出す
    - パッケージごとにリポジトリを作ると管理が大変なため、1つのリポジトリで
    複数パッケージを管理するのが一般的
    - モノレポともいう

    View Slide

  55. マルチパッケージ利点
    - 大規模なアプリで機能・レイヤーごとにパッケージを分ける
    - 関心の分離
    - 意図しない依存を防ぎやすい
    - 共有コードをパッケージに切り出せる
    - 今回やりたかったこと

    View Slide

  56. Melosとは
    - Dartでのマルチパッケージを支援するコマンドラインツール
    - Invertaseが開発しており、有名パッケージの開発にも使われている
    - Riverpod、FlutterFireなどが利用
    - Melosの開発にもMelosが使われている
    - 注意:マルチパッケージならMelos必須というわけではない
    - 使ってないリポジトリも
    - Flutter News Toolkit、I/O Flip

    View Slide

  57. Melosのはじめかた
    - グローバルにインストール
    - dart pub global activate melos
    - プロジェクトのルートにmelos.yamlを作る
    - melosのコマンドが使えるようになる

    View Slide

  58. Melosの機能
    - Commands
    - Filter
    - Scripts

    View Slide

  59. Commands
    - モノレポをやりやすくするいくつかのコマンドがある
    - bootstrap / clean
    - exec
    - list
    - publish
    - run
    - version

    View Slide

  60. Commands
    - モノレポをやりやすくするいくつかのコマンドがある
    - bootstrap / clean
    - exec
    - list
    - publish
    - run
    - version
    これらを紹介

    View Slide

  61. bootstrap / clean
    - 複数パッケージに対してpub get
    - pubspec_overrides.yamlの用意
    - リポジトリ内の依存を相対パスでoverrideして開発中バージョンを使
    うようにする
    - 問題に気づきやすくなるなど利点がある
    - cleanはbootstrapの逆

    View Slide

  62. exec
    - モノレポ内の複数のパッケージに対して同じコマンドを実行
    - これがないと一々ディレクトリ移動してbuild_runner実行みたいにな

    - 後述するfilter機能と組み合わせる

    View Slide

  63. list
    - モノレポ内のパッケージをリスト表示
    - 依存関係などを簡単に確認

    View Slide

  64. publsh
    - モノレポ内のパッケージをpub.devに公開しやすくするコマンド
    - アプリ作る分には使わない

    View Slide

  65. run
    - 後述するScripts機能を実行するコマンド

    View Slide

  66. version
    - Conventional Commitsの作法に従っている場合に自動でバージョニン
    グができる
    - 「feat: hoge」みたいなcommit
    - !をつけると破壊的変更としてメジャーバージョンがあがるなどのルー
    ルがある(feat!: hoge)
    - tagで前回からの差分を判断
    - 手動バージョニングにも使える

    View Slide

  67. Filter
    - Commandsの対象パッケージを絞り込む機能
    - melos bootstrap --no-privateなら--no-private部分
    - いくつかのフィルターがある
    - scope:特定の文字列を含むパッケージのみ
    - depends-on:特定のパッケージに依存してるパッケージのみ
    - 他にも色々

    View Slide

  68. Scripts
    - melos.yamlにスクリプトを定義しておきrunコマンドで実行できる
    - よく使うものを登録しておき、CIからも使うと良い感じ

    View Slide

  69. Dart Frog解説

    View Slide

  70. Dart Frog(再掲)
    - VGV(Very Good Ventures)が開発しているサーバーフレームワーク
    - 開発元がFlutter界隈で有名なので注目されている
    - 2022年に発表され、2023年8月2日に1.0.0になった
    - Shelf上に構築されており、Shelf同様軽量
    - こちらも複数パッケージを組み合わせるモジュール方式
    - Shelfをより便利に使えるような機能がある
    - 技術スタック紹介の章で説明

    View Slide

  71. Dart Frogのはじめかた
    - グローバルにインストール
    - dart pub global activate dart_frog_cli
    - DartのコマンドラインツールなのでMelosと同じ
    - dart_frog create my_project
    - 最低限のDart Drogのコード
    - dart_frog devですぐ動く

    View Slide

  72. Dart Frogの基本機能・特徴
    - ホットリロード対応
    - ファイルベースルーティング
    - 便利なクラス
    - Middleware
    - DI
    - テストの容易性

    View Slide

  73. ファイルベースルーティング
    - ディレクトリ構成がそのままルーティングに対応する
    - ”/”と”/hello”のエンドポイントに対応させる場合
    - 画像のどちらか
    - 競合したらビルド失敗等で分かる

    View Slide

  74. エンドポイントの追加方法
    - もちろん手動でファイルを追加すればできるが
    - コマンドで追加も可能
    - dart_frog new route "/hello"

    View Slide

  75. 追加直後のエンドポイント
    - RequestContextを受け取ってResponseを返す関数

    View Slide

  76. エンドポイントの追加方法
    - もちろん手動でファイルを追加すればできるが
    - コマンドで追加も可能
    - dart_frog new route "/hello"
    - dart_frog_cliのコマンドはMasonで実現されている
    - Masonはテンプレートからコードを生成するDartツール
    - ファイルベースルーティングなのはテンプレートからの生成との
    相性が良いからかも?

    View Slide

  77. View Slide

  78. 便利なクラス
    - Dart FrogはShelfのクラスをラップして便利にしている
    - 先程のRequestContext

    View Slide

  79. RequestContext

    View Slide

  80. RequestContext
    - 内部的にshelfのRequest

    View Slide

  81. body、jsonなどよく使うであろうメソッ
    ドが事前に用意されている

    View Slide

  82. Middleware
    - ディレクトリごとに配置でき、サブディレクトリ含めて前処理を行える

    View Slide

  83. Middleware
    - handlerのuseにMiddleware(requestLogger)を渡す
    - 用途
    - ロガー
    - 共通のエラー処理
    - DI

    View Slide

  84. Middlewareのチェイン
    - useはMiddlewareを受
    け取りHandlerを返すの
    でチェインできる

    View Slide

  85. 補足:Shelfのリソースを活用

    View Slide

  86. DI
    - providerというMiddlewareでDIできる

    View Slide

  87. DI
    - middlewareでこうして

    View Slide

  88. DI
    - 利用側はRequestContextから取得

    View Slide

  89. テストの容易性
    - プロジェクト初期化次点でmock_tailが追加されている

    View Slide

  90. テストの容易性

    View Slide

  91. テストの容易性
    RequestContextはmocktailでモッ

    View Slide

  92. テストの容易性
    onRequest関数をテストすれば良い

    View Slide

  93. テストの容易性
    expectで確認!で完了

    View Slide

  94. もぐもぐタイム

    View Slide

  95. 4. 実践した感想

    View Slide

  96. サンプルコード
    - 実際のソースコードを見せることはできないので、簡素化したサンプルプ
    ロジェクトを作成しました
    - GitHub Repository Search APIの検索結果をBFFでキャッシュします
    - https://github.com/YumNumm/dart-frog-github-repository-se
    arch
    - 後でライブデモをするので そこで詳しくお話します

    View Slide

  97. サンプルコード

    View Slide

  98. 1. バックエンド と BFF のクライアントを同じように実
    装できた
    - アプリがBFFを叩く部分 と BFFがバックエンドAPIを叩く部分で同じパッ
    ケージを使った
    - 実装が似ているのでキャッチアップしやすい
    - retrofitを利用してクライアントを実装しました

    View Slide

  99. 2. API型定義の取り方
    - 実際の案件では、 Flutter App と BFF のリポジトリが別
    - Flutter Appは BFFのリポジトリにある 型定義へ依存している
    - どうするねん!

    View Slide

  100. 2. API型定義の取り方

    View Slide

  101. 2. API型定義の取り方
    - bff_api_typesをpub.devで公開すれば良いんじゃ!?
    → インシデント確定演出
    - git submoduleで置いて、path packageとして扱う
    → 微妙
    - pubspec.yamlのgit packageとして扱う
    → git経由の依存関係 よござんす👍

    View Slide

  102. API型定義の取り方
    - bff_api_typesをpub.devで公開すれば良いんじゃ!?
    → インシデント確定演出
    - git submoduleで置いて、path packageとして扱う
    → チョット汚い
    - pubspec.yamlのgit packageとして扱う
    → よござんす👍
    CI環境どうする!?
    - actions/checkoutでAppのコードをクローンしている
    - BFFのレポジトリはクローンできない

    View Slide

  103. 2. API型定義の取り方 - GitHub Deploy Keyのすゝめ
    - Deploy Keyとは?
    - 単一リポジトリへのアクセス(R, R/W)を許可するSSHキー
    - サーバ上でプロジェクトを起動するためのもの
    - publicな部分をリポジトリに privateな部分をサーバに配置
    - ユーザに紐づかないため、管理が楽
    cf. https://docs.github.com/ja/authentication/connecting-to-github-with-ssh/managing-deploy-keys

    View Slide

  104. 2. API型定義の取り方 - GitHub Deploy Keyのすゝめ
    - GitHub Actions内で SSHのprivate keyを展開
    - SSHできる用意をしてあげる
    - flutter pub get ヨシ👍

    View Slide

  105. 3. Docker を使う
    - Docker とは?
    - 仮想マシン(VM)とは違い、コンテナという単位でアプリケーションを実
    行できる
    - Dockerfileを書くことでコンテナビルド方法をコードで記述できる
    (IaC: Infrastracture as Code)
    - クラウドでもローカルでも実行できる
    - 実行環境依存のものを減らすことができる
    https://aws.amazon.com/jp/docker/
    より

    View Slide

  106. 3. Docker を使う
    - プロジェクトでAWS Fargate上でデプロイする必要があった
    - 環境に依存せずにローカルでデバッグできるようにしたかった

    View Slide

  107. OrbStackのススメ (余談)
    - Docker DesktopとWSLの代替品
    - macOSでDocker ContainerとLinux マシンを動かすことができるApp
    - Docker Desktopを使うよりも高速・軽量・シンプル
    https://orbstack.dev/
    - 個人利用であれば無料、
    商用利用は$8/month per user
    - macOS専用

    View Slide

  108. 3. Dart FrogのDockerfile 生成
    - dart_frog build で build/Dockerfileが生成される
    - buildコマンドを実行するためには dart_frog が実行できることが前
    提 (ホスト環境に依存してはいけない)
    - build/* をリポジトリに含めると、差分がすごいことになるので含めた
    くない
    → 自分でDockerfile書きますわ

    View Slide

  109. バイナリをビルドするための Dartコンテナ
    バイナリを実行するためのコンテナ
    builder
    scratch

    View Slide

  110. バイナリをビルドするための Dartコンテナ
    バイナリを実行するためのコンテナ
    builder
    scratch
    ローカルで依存しているライブラリの pubspec.yamlと
    pubspec_overrides.yaml
    をコピー
    ローカルで依存しているライブラリの全体をコピー

    View Slide

  111. バイナリを実行するためのコンテナ
    バイナリをビルドするための Dartコンテナ
    builder
    scratch
    builderで生成されたバイナリをコピーして
    実行する

    View Slide

  112. 5. LIVEデモ

    View Slide

  113. LIVEデモ
    - 実際のソースコードを見せることはできないので、簡素化したサンプルプ
    ロジェクトを作成しました
    - GitHub Repository Search APIの検索結果をBFFでキャッシュします
    - GitHub Personal Access Tokenセット済み -> レートリミット緩和
    - 仕様
    - GET /api/v1/repository/search : リポジトリ検索
    - param: query={検索文字列}
    - https://github.api.yumnumm.dev にデプロイ済み

    View Slide

  114. LIVEデモ

    View Slide

  115. LIVEデモ
    GitHub Repository Search API BFF, App

    View Slide

  116. LIVEデモ - dart_frog create
    - dart_frog create hoge でプロジェクトを作成できる
    - dart_frog dev で実行
    - localhost:8080でアクセスできます
    - localhost:8181でDevToolへアクセスできます
    demo/1 Branch

    View Slide

  117. LIVEデモ - melos bootstrap
    - melos bootstrap で pubspec_overrides.yamlが生成される
    - melos clean でpubspec_overrides.yamlが消える
    - melos.yamlで記述したbuild_runnerスクリプトを実行できる
    demo/2 Branch
    - melos bootstrap で pubspec_overrides.yamlが生成される
    - melos clean でpubspec_overrides.yamlが消える
    - melos.yamlで記述したbuild_runnerスクリプトを実行できる

    View Slide

  118. LIVEデモ - Dart Frog BFF
    - dart_frog new route hoge でエンドポイントを作成できる
    - dart_frog dev で開発サーバを起動
    - http://localhost:8080/ でアクセスできる
    - http://localhost:8181/ でDevToolへアクセスできる
    - api/v1/repository/search の中身を実装していく
    demo/2 Branch

    View Slide

  119. LIVEデモ - Dart Frog × Docker
    - docker compose up -d /-build でコンテナを起動
    - [OrbStackを利用している場合] http://orb.local でコン
    テナ一覧を見ることができる
    -
    main Branch

    View Slide

  120. LIVEデモ - Application
    - 実際にFlutterアプリからアクセスしてみましょう
    - App: https://gh-repo-search.yumnumm.dev/
    - BFF: https://github.api.yumnumm.dev/
    (どちらも 2023/11/11 には閉鎖します )
    main Branch

    View Slide

  121. 6. まとめ

    View Slide

  122. 1章まとめ:Dartバックエンドの世界
    - Dart 12年の歴史
    - Chrome統合が失敗しオワコン化?
    - Sky(現Flutter)に採用され復活
    - Flutterの盛り上がりによりDartバックエンドの機運が高まる
    - ServerPod、Dart Frogなどが盛り上がる

    View Slide

  123. 2章まとめ:プロジェクトの背景
    - Flutterチームが夜間稼働でコミュニケーションなどに課題
    - ゆめみ参戦
    - PMF期に複雑化したバックエンドの構成変更
    - 3つのフロントエンドそれぞれのBFF越しに共通バックエンドを叩く構
    成にする
    - Dart Frog x MelosのBFFつくるぞい

    View Slide

  124. 3章まとめ:技術スタックの紹介
    - マルチパッケージ管理ツールMelosを使ってアプリとBFFでパッケージ共

    - Melos解説
    - 複数パッケージに対してコマンド実行などが便利
    - Dart Frog解説
    - ファイルベースルーティングとMasonによるコード生成
    - Shelfのクラスをラップした便利クラス
    - テストもやりやすい

    View Slide

  125. 4章まとめ:実践した感想
    - バックエンドとBFFのClient実装がほぼ同じ
    - BFF API 型定義をApp側と共有することで 保守性向上
    - モノレポでローカル依存が多いならではの Dockerfileのつらみ

    View Slide

  126. 5章まとめ:ライブデモ
    - 実際のプロダクトにBFFを取り込む過程を紹介
    - melos, dart_frog を利用することで、高速に開発を進めることができて
    いる
    - Dockerを利用してローカルで開発を行うこともできます

    View Slide

  127. 告知
    - この後同じルームでゆめみスポンサーセッション🥳
    通称:モリモリ山トリオ

    View Slide

  128. Links
    - https://ja.wikipedia.org/wiki/Dart
    - https://zenn.dev/mjhd/articles/680a19ae893c1e
    - https://github.com/stablekernel/aqueduct
    - https://serverpod.dev/
    - https://pub.dev/packages/shelf
    - https://dartfrog.vgv.dev/
    - https://github.com/felangel/mason
    - https://blog.codemagic.io/writing-your-backend-in-dart
    /
    -

    View Slide

  129. Links
    - https://zenn.dev/overflow_offers/articles/20220418-wha
    t-is-bff-architecture
    - https://melos.invertase.dev/
    - https://www.conventionalcommits.org/ja/v1.0.0/
    - スライド内のサンプルプログラム
    - GitHub API BFF+App:
    https://github.com/YumNumm/dart-frog-github-reposi
    tory-search

    View Slide

  130. View Slide