GCP、Firebase、GraphQL、react、react-native、appetize.ioのよくばりexampleセットをつくったぞーーーー！！！

サクッとexampleコードを書くつもりが、nativeコードにハマりにハマって１ヶ月かかってしまいました。。。
js界隈の人間には、react-nativeのnative側のコードをいじるのが、とにかく辛かった。

# 今回作ったexample

## 概要
 * タイトルの通り、GCP、Firebase、GraphQL、react、react-native、appetize.ioを使い、web、iOS、Android向けにFirebaseのauthログイン + リスト表示ができるexampleを作成
（※使用技術については下記記載）


## github
 * https://github.com/wheatandcat/react-graphql-examples

## DEMO

 ![demo.gif](https://qiita-image-store.s3.amazonaws.com/0/170824/97910276-0a46-82ca-6288-8d6834f04c68.gif)



### web

* https://example-202505.appspot.com/signin

### iOS (appetize.io)

* https://appetize.io/app/6n99qu72hq58uabhqbdmue64qg

### Android (appetize.io)

* https://appetize.io/app/cadx8a22mw0tcxbj952m3tfv0g

## 構成 (使用技術)

### backend

#### 実装環境: [Cloud Functions for Firebase](https://firebase.google.com/docs/functions/?hl=ja)
 * Googleが提供するFunction実行サービス（AWSのlambdaみたいなものです）
 * 今回はFirebase連携を使用するため、Cloud Functions for Firebaseで実装
 * (余談ですが) 
  * **AppEngineがnode.jsのスタンダード環境の提供を始めたら、そちらを使用するほうが筋が良いか気がするので乗り換える予定**

#### データベース: [Google Cloud Datastore](https://cloud.google.com/datastore/docs/?hl=ja)
 * Cloud DatastoreはGoogleが提供するNoSQLデータベース
 * 個人利用で無料利用枠を超えることがほぼないので、気軽に使用できる
 * 「OR」や「IN」や「!=」等のクエリが使用できないので、サービス開発に使用する際は注意

#### 言語: [Node.js](https://nodejs.org/ja/about/)
 * backendの言語は、選択肢が幾らでもあるので基本開発メンバーの好みで良いと思いますが、今回は以下の理由からNode.jsを採用しました
    * 将来的にSSR（サーバーサイドレンダリング）を実装することになった場合に、現状Node.js以外の選択肢が無いため
    * Node.jsはGraphQLの公式がサポートしているため

#### API実装方式: [GraphQL](https://graphql.org/learn/)
 * REST APIに比べ、GraphQLでは厳密に仕様が定義でき使いやすい
 * [graphiql](https://github.com/graphql/graphiql)という、API開発ツール（RESTのpostmanみたいなもの）の出来が良い
    * **特に右サイドのドキュメントツールがめっちゃ使える** :thumbsup: (コードからの自動生成なので実装との乖離がない) 
         <img width="600" alt="スクリーンショット 2018-05-23 22.36.52.png" src="https://qiita-image-store.s3.amazonaws.com/0/170824/207a78eb-0792-b30b-be33-951ced25bd7f.png">
 * 実装に迷った際は、[GitHub API v4](https://developer.github.com/v4/)のドキュメントを見れば、正解が書いてあるので要確認

#### 認証: [Firebase](https://firebase.google.com/docs/auth/?hl=ja)
 * 今回はFirebaseのサービスは認証以外は使用していませんが、web、native共に便利サービスが充実しているので、今後の拡張を想定し組み込みました 
 * (余談ですが) 
  * 単に認証を行いたいというだけであれば、[Auth0](https://auth0.com/jp/)の方が高性能です

### frontend(web)

#### 実装: [React](https://reactjs.org/)
 * Facebookが開発しているViewライブラリ
 * React v16.3.0で追加された[Official Context API](https://reactjs.org/blog/2018/03/29/react-v-16-3.html#official-context-api)により、React単体で扱えるアプリケーションの幅が広まった :thumbsup: 

#### GraphQLクライアント: [react-apollo](https://www.apollographql.com/docs/react/)
 * GraphQLのクライアントライブラリ
 * 現状、GraphQLクライアントは**apollo**と**[relay](https://facebook.github.io/relay/)**の2択で、かつGraphQLの公式はrelay側なので悩ましいところですが、relayはrelay-compiler等の強い縛りがあり柔軟性に欠けると感じ、今回はapolloを採用

#### 認証: [Firebase](https://www.npmjs.com/package/firebase)
 * [公式のドキュメント](https://firebase.google.com/docs/auth/web/firebaseui?hl=ja)が充実しているので、楽に実装可能
 * 今回は、公式で認証のReactコンポーネント([react-firebaseui](https://github.com/firebase/firebaseui-web-react))を提供しているので、そちらを採用

#### 実装環境: [Google App Engine](https://cloud.google.com/appengine/docs/whatisgoogleappengine?hl=ja)
 * 自作のwebアプリを簡単公開できるPaaS（yamlに設定書いてデプロイコマンドを実行するだけでOK）
 * 今回は、jsとhtmlの置き場のためだけに使用

### frontend（ iOS  &  Android ）

#### 実装: [React Native](https://facebook.github.io/react-native/)
 * ReactでiOS、Androidアプリが書けるライブラリ(コードはjavascript)
 * 構文的にはReactと一緒なので、React経験者なら簡単に始められる
 * **が、簡単に始められるというだけで、リリースまでの実装にはnativeコード側のObjective-Cやjavaやgradleを修正可能性が高いので、覚悟を決めてから、始めた方が良いです**
  * それでも今からSwift & Kotlinを1から勉強するよりはコスパ良いと思います

#### GraphQLクライアント: [react-apollo](https://www.apollographql.com/docs/react/)
 * webと同様にapolloを採用
 * nativeとwebは全く同じコードで実装できる

#### 認証: [react-native-firebase](https://rnfirebase.io/)
 * react-nativeのfirebaseSDK
 * Firebase公式では無いが、サービス自体は一通りサポートしている
 * **導入にはnativeコードを修正する必要があります**
 * また今回はGoogleアカウントログインも実装しており、それには[react-native-google-sign-in](https://github.com/joonhocho/react-native-google-sign-in)を導入し、連携されせる必要があります
    * [react-native-firebaseとreact-native-google-sign-inの連携方法](https://rnfirebase.io/docs/v4.2.x/auth/social-auth#Google)
    * **さらにreact-native-google-sign-inを導入するのにもnativeコードを修正する必要があります**

#### データストレージ: [AsyncStorage](https://facebook.github.io/react-native/docs/asyncstorage.html)
 * react-nativeの標準で含まれている簡易データストレージ
 * 今回は、Auth Tokenの保持にのみに使いたかったので、簡単に使用できるAsyncStorageを採用

#### ルーティング: [react-native-navigation](https://wix.github.io/react-native-navigation/#/)
 * ルーティングライブラリ
 * 他のルーティングライブラリと比較しリッチなアニメーションが搭載されている
 * 今回は、アプリらしい見た目を考慮しreact-native-navigationを採用
 * **導入にはnativeコードを修正する必要があります**

#### UIライブラリ: [react-native-elements](https://react-native-training.github.io/react-native-elements/docs/getting_started.html)  &  [react-native-elements](https://wix.github.io/react-native-ui-lib/)
 * 基礎となるUIライブラリは一つに絞りたいと所ですが、どちらも少しづつ足りないコンポーネントがある感じなので、今回は併用で採用
 * ちなみに[NativeBase](https://nativebase.io/)という強力なUIライブラリがあるが、他のコンポーネント群との併用が困難だと感じたため、今回は不採用

#### iOSのbetaアプリ配信: [fastlane] (https://github.com/fastlane/fastlane)  &  [TestFlight](https://developer.apple.com/testflight/)
 * fastlaneはiOSのリリースを自動化できるツール
 * TestFlightはiOSアプリのテスター向け配信をサポートしてくれるサービス
 * 現状は、以下のコマンドで「fastlaneでbetaアプリを更新し、TestFlightからテスターに配信」できるようにしている
 
```
cd native
npm run ios:bate
```
 * [Fabric](https://get.fabric.io/)も実装していますが、今回はより簡単なTestFlightでの配信を採用

#### Androidのbetaアプリ配信: 手動apkファイルをダウンロードで運用
 * こちらも[Fabric](https://get.fabric.io/)等のツール自動化できそうですが、apkファイルを出力して実機Androidでダウンロードすれば事足りるかなと思い手動で運用
 * お手軽実装でよければ、apkファイルをビルド後に[google cloud storage](https://cloud.google.com/storage/)にアップロードして、それをダウンロードできるWebサイトをApp Engineで立てるくらいで良いかなーと思っている

#### iOS & AndroidのDEMO実行: [appetize.io](https://appetize.io/)
 * アプリをアップロードすると(謎技術により)、Webブラウザでネイティブアプリを動かすことのできるサービス
 * 無料利用でのアクセス制限は存在するが、個人開発レベルなら無料で使用できる
 * 動作も、かなりサクサクで動くので気軽にDEMOを見せたい時に使える
 * また、fastlaneを使用することで自動アップロードも可能


# 一通りの開発を終えての総評
 * [Google Cloud Platform](https://cloud.google.com/why-google-cloud/)は**超簡単にアプリケーションを作って公開できる**
    *  AppEngineやDatastoreのお手軽感は、AWSでは体験できなかった間隔で素晴らしい
    *  個人開発なら、ほぼ無料で使えるのも :thumbsup: 
 * [GraphQL](http://graphql.org/)は**REST APIの曖昧な部分をカバーできる仕様になっており、API仕様として優れている**
    *  以下の点でAPI仕様として優れている
        *  REST APIではrequestパラメータやresponseパラメータに厳密に型やプロパティを保証することができない
         *  GraphQLではrequest、response共に厳密に定義する設計になっているため解決
        *  REST APIにもswagger等のドキュメント生成ツールが存在するが、そのドキュメントと実装が乖離していないことを保証することができない
         *  GraphQLでは、graphiql等のツールにより実装に沿ったドキュメントを確認することができるので解決
 * [react-native](https://facebook.github.io/react-native/)は**不満を感じることも多いいが、魅力的に感じることも多いい**
    * 不満
         *  **native codeを触れる必要が出た時にひたすらハマる**（今回の開発期間の1/2はnative code関連の修正対応）
         *  StyleSheetがwebに比べるとショボい
            *  https://facebook.github.io/react-native/docs/stylesheet.html
         *  スタンダートなコンポーネントが全て揃っているUIライブラリが無い
         *  **iOSで動いてAndoridで動かない、Andoridで動いてiOSで動かないが事がナチュラルに発生する**
         *  （当たり前だけど）betaビルドやリリースでは、やはりネイティブの知識が必要
    * 魅力
        * Reactの構文が分かれば、AndroidとiOSアプリを作成する事ができる
        * jsコードに関しては、AndroidとiOSは（ほぼ）ワンコードで実装できる
        * swiftやKotlinと比べて、開発スピードが早い（はず）
        * 一般的なGUIに必要なコンポーネントは一通り揃っている（はず）