ミステリーデートのシステム構成
ミステリーデートというアプリをリリースすることになったのですが、
開発の観点から、システム構成を書いておきます。
サーバーシステム
DBはFirebaseのFirestoreにおきました。Firebaseは前から使っていたけど、Firestoreを使うのは今回が初めて。
APIを作ろうと思ってFirebaseに紐づけてGAEの設定もしたのですが、Queryかけてデータを返すだけだったらクライアントからやったほうが楽!
Firestoreすごい。
とうわけで用意していたGAEは管理画面のみで利用することにして、アプリからアクセスする分はすべてFirestoreとCloud Functionsでやることになりました。
iOSのクライアントアプリ
Podfileの中身はこんな感じです。
platform :ios, '11.0'
use_frameworks!
def install_pods
pod 'SVProgressHUD'
pod 'JSONModel'
pod 'SDWebImage'
pod 'FirebaseUI/Auth'
pod 'FirebaseUI/Storage'
pod 'Firebase/Firestore'
pod 'Firebase/Core'
pod 'Firebase/Messaging'
pod 'Firebase/Storage'
pod 'Firebase/Analytics'
pod 'Fabric'
pod 'Crashlytics'
pod 'GoogleMaps'
pod 'R.swift'
pod 'Stripe'
pod 'RxSwift'
pod 'RxCocoa'
pod 'RxFirebase/Firestore'
pod 'RxFirebase/Auth'
pod 'RxFirebase/Functions'
pod 'JTAppleCalendar', '8.0.0'
pod 'RealmSwift'
pod 'EAIntroView'
pod 'Zoomy'
pod 'libPhoneNumber-iOS', '~> 0.8'
script_phase :name=> 'Fabric',
:script=> '"${PODS_ROOT}/Fabric/run"',
:input_files=> ['$SRCROOT/$PRODUCT_NAME/$(INFOPLIST_PATH)']
end
target "mysterydate" do
install_pods
end
target "mysterydate staging" do
install_pods
end
stagingとproductionで構成を切り替えるのと、Fabricのやり方がちょっと面倒でした。
Rx系はいちおう使ってるけど、そんなに必要なかったかな。
あと、JSONModelはCodableでも良かったなと後で思いました。
言語はSwiftです。
管理画面の構成
管理画面はとりあえずは自分しか使わないのですが、勉強のためにGAE上でNuxt.jsで作りました。ここはハマりが多かった!
FirebaseはGAEと融合しているようなので、GAEのDatastoreの関数でそのまま紐づいているFirestoreが操作されるそう。でもこれがどうやってもDatastoreの関数ではうまく初期化すらできませんでした。
なのであきらめて普通のFirestoreの関数でアクセスすることにしました。
ローカルでデバッグする時もそのほうが楽だし、最初からそうしておけばよかった・・
const { Datastore } = require('@google-cloud/datastore')
fallback.js:75 Uncaught (in promise) Error: {}You need to pass auth instance to use gRPC-fallback client in browser. Use OAuth2Client from google-auth-library.
at new GrpcClient (fallback.js:75)
at Object.<anonymous> (index.js:38)
at Object../node_modules/@google-cloud/datastore/build/src/index.js (index.js:856)
at __webpack_require__ (bootstrap:790)
at fn (bootstrap:150)
at _callee2$ (index.js:1)
at tryCatch (runtime.js:45)
at Generator.invoke [as _invoke] (runtime.js:271)
at Generator.prototype.<computed> [as next] (runtime.js:97)
at asyncGeneratorStep (asyncToGenerator.js:3)
ただし、その際もちょっとだけ問題が。
Nuxtはサーバーモードとクライアントモードとあるのですが、普通にFirebaseのインポートすると
These dependencies were not found:
* @firebase/app in ./node_modules/@firebase/database/dist/index.cjs.js
* dns in ./node_modules/@grpc/grpc-js/build/src/resolver-dns.js
* http2 in ./node_modules/@grpc/grpc-js/build/src/server.js
To install them, you can run: npm install --save @firebase/app dns http2
みたくなってうまくいきません。
if (process.server) {
var admin = require('firebase-admin')
if (!admin.apps.length) {
admin.initializeApp({
credential: admin.credential.applicationDefault(),
databaseURL: process.env.firebaseConfig.databaseURL
})
}
}
のように、サーバーモードの時だけ処理を分けることで対処しました。
StagingとProductionでGoogleのCredentialを分ける
ミステリーデートで予約が入ると、店舗ごとのGoogleカレンダーに追加されるようにしたのですが、Cloud FunctionsからGoogle Calendar APIを呼ぶ時に利用するCredentialをStagingとProductionで切り替えるのを工夫した結果、環境変数を使う方法に落ち着きました。
やり方としては、
firebase functions:config:set --project mystery-date credentials.client_id="xxxxxx.apps.googleusercontent.com"
firebase functions:config:set --project mystery-date credentials.client_secret="xxxxxxxxxxxxx"
firebase functions:config:set --project mystery-date credentials.refresh_token="xxxxxxxxxxxxx"
firebase functions:config:set --project mystery-date-staging credentials.client_id="xxxxxx.apps.googleusercontent.com"
firebase functions:config:set --project mystery-date-staging credentials.client_secret="xxxxxxxxxxxxx"
firebase functions:config:set --project mystery-date-staging credentials.refresh_token="xxxxxxxxxxxxx"
のように、一個づつ環境変数に入れました。これで、ソースからは
let authClient = new google.auth.OAuth2(
functions.config().credentials.client_id,
functions.config().credentials.client_secret,
"https://developers.google.com/oauthplayground"
);
authClient.setCredentials({
refresh_token: functions.config().credentials.refresh_token
});
のように初期化して利用できます。
refresh_tokenの作り方はこちらを参考にしました。
その他ハック
いつも一人で開発している時は、ハマって解決してもログに残らないので、今回からSlackにハマりを書いておく専用チャンネルを作りました。
ハマった時に書いて、解決したらそのスレッドに返信するようにしておくと、今回みたいな記事もすぐ書けて便利です。
この記事が気に入ったらサポートをしてみませんか?