Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

【2018/09/11】PAYでのReact Nativeにおける APIクライアント実装 について

2,845 views

Published on

【Kyash、Coiney、PAY】新しい支払いの形を作る、モバイル決済サービスの開発の裏側とは
というイベントでの発表です。時間があったら話すは話せなかった

Published in: Engineering
  • Be the first to comment

【2018/09/11】PAYでのReact Nativeにおける APIクライアント実装 について

  1. 1. PAYでのReact Nativeにおける APIクライアント実装 について 2018/09/11 【Kyash、Coiney、PAY】新しい支払いの形を作る、モバイル決済サービスの開発の裏側とは PAY 株式会社 山中夏樹 1
  2. 2. ● 名前:山中 夏樹 ● 所属:PAY株式会社 ● 担当:iOS, Androidの開発 ● 得意分野:広く浅く CentOS6系のサーバー・インフラ構築とかチャットサービスのNode.js, PHP, iOS, Android全部書いたりとかWebRTC Conferenceで登壇とか 自己紹介 2
  3. 3. 今日の内容 3
  4. 4. 主にReact Nativeに置ける 通信について 4
  5. 5. APIを実装する際 参考になれば 5
  6. 6. 1. React Nativeを使った経緯など 2. React NativeにおけるAPIクライアントの選択肢 3. OpenAPI(Swagger)について アジェンダ 6
  7. 7. React Nativeを使った経緯 7
  8. 8. ● モバイルは現在4人 ● PAY IDというQRコード決済アプリを開発していて、Swift、Kotlinを使って開発してい た(現在も開発中) PAYのモバイル開発体制 まだの方はLet’s Download! → 8
  9. 9. ● 中規模のアプリ ○ 50画面ほど ● 特にとがった機能はない ○ REST API、ユーザー認証、画像アップロード、プッシュ通知、 ListView、 タブ付きホーム etc... →新規技術を取り入れる機運…? 新規アプリを作ることになった 9
  10. 10. ● 時期的には2018年春頃 ● メンバーは割とiOS/Androidどっちもできる ● React Native、Flutterなどを検討 ● FlutterはまだBetaで、まだライブラリや事例も少なそうな印象 ● メンバーに触ったことがある人などもいたReactNativeに傾いた ● 機能として必要な部分を洗い出し、1,2週間ほどその実装が可能かどうか調査の期 間を設けてみて問題なさそうだった →採用 クロスプラットフォームへの挑戦 10
  11. 11. ● アーキテクチャ -> mobX ● プッシュ通知 -> react-native-firebase ● 画面遷移 -> react-native-navigation ● テスト -> jest ● API -> axiosからOpenAPIへ移行 ● その他 ○ ReactNative: v0.56.0 ○ React: 16.4.1 ○ TypeScript: 2.9.2 使用ライブラリ、アーキテクチャなど 11
  12. 12. ● TypeScript: Javascriptにトランスパイルできる型付き言語 ● TypeScript, VSC共にMicroSoftが開発していて相性がいい ● 自動補完、定義元の検索、tslint、prettierによる自動整形などが割と便利 ● auto importがmonorepoと相性が悪い ● TypeScript開発なら割とVSC一択 React Native + TypeScript + Visual Studio Code 12
  13. 13. プロジェクト構造 ● Lerna のmonorepo multi package構成 →1つのリポジトリに複数プロジェクトを入れている ● ハイブリッドではなく100% React Native + TypeScript 13
  14. 14. 今回のプロジェクトでのAPI実装 14
  15. 15. ● HTTP1.xでJSONを返す ● grpcでもGraphQLでもHTTP/2でもない ● プラットフォームはiOS / Androidのみ よくあるREST API 15
  16. 16. 基本的なAPI通信の実装が 必要だが、 16
  17. 17. どう実装するのがデファクトスタ ンダードなのか? 17
  18. 18. ● https://facebook.github.io/react-native/docs/network ● ↑公式でnetwork requestについて説明されている ● まずはここを一読することを推奨 公式の見解 18
  19. 19. ● ReactNativeで最初から使えるのは下記の二つ ● fetch ○ デフォルトのAPIクライアント ● XMLHttpRequest ○ ビルトインのAPIクライアント ○ JavaScriptで作られた他のライブラリ参照の為に使えるようになっている? ○ 基本的にはfetchが推奨 ○ fetchも中ではこれをcallしている デフォルトクライアント 19
  20. 20. ● 公式ページにも言及があるライブラリ ● axios ○ GitHubスター数:45,000超え (2018/08時点) IE10以降など、ブラウザなら大体動くやつ ● frisbee ○ GitHubスター数:650くらい React Nativeでの使用を想定して作られている ● 今回採用したもの ○ OpenAPI Generator 2.0(Swagger)で生成したクライアント これについては後述 サードパーティライブラリの選択肢 20
  21. 21. ● サクッと書き始めるにはfetch ● Webフロントエンドの人が多ければfetch、axiosとかが慣れてそう ● frisbeeはfetchの薄いラッパーのような感じ ● XMLHttpRequestはAndroidで言うURLConnection、iOSで言うURLSessionのよう なものなので直接使うのはオススメしない 選び方 21
  22. 22. ● RetrofitやAPIKit的なものが欲しい = interfaceがかっちり決められていて、endpointやpath、adapterだけ書けばいい ような作り ● 弊社では今回、そこらへんのコードを自動で生成できるOpenAPI(Swagger)を採用 実際の実装時にやりたいこと 22
  23. 23. OpenAPIについて 23
  24. 24. Open APIとは ● 今回の話ではOpen API Specificationのことを指しています ● APIの実装って同じような定義を少し変えるだけですよね ● 標準的なAPIを定義する為の仕様 = OpenAPI ● YamlやJSONで定義を記述できる ● 原文: The OpenAPI Specification is a community-driven open specification within the OpenAPI Initiative, a Linux Foundation Collaborative Project. ● Swaggerというプロジェクトが元になっている 24
  25. 25. ● OpenAPI Specificationに沿って定義された仕様から、クライアント/サーバー側の HTTP通信用コードを生成するGenerator ● https://github.com/OpenAPITools/openapi-generator ● これを使うと、Yamlだけ共有すればAPIの更新、共有などが楽に行える コードを生成するOpen API Generator 25
  26. 26. ● 使っているversionは2.0 ● https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md ● PetStoreというsampleが公開されているので、それを参考に Open APIの導入 26
  27. 27. Open APIの仕様定義サンプル ● 仕様詳細は公式を参照して下さい ● .yamlファイルで→みたいのを書く 27
  28. 28. ● ReactNative+TypeScriptなのでそれ用のテンプレートをgenerateコマンドの引数に 渡す $openapi-generator-cli generate -t typescript-fetch ● デフォルトだとfetchに依存しているが、クライアントの差し替えも可能 ● 採用してないですが、axiosとかもできるらしいです(swagger-axios-codegen) Open API Generatorのテンプレート 28
  29. 29. OpenAPIで生成された TypeScriptのコードを 眺めてみる 29
  30. 30. ● path毎に Apiクラスが 生成される {:/path}Apiクラス 30
  31. 31. Configuration ● Basic認証対応 ● endpointの変更可能 ● accessTokenを渡す 31
  32. 32. Model ● TypeScriptではinterfaceが定義される ● 型は公式のreferenceを参照 Yamlで指定するのは integer, dateTimeなど 32
  33. 33. Model 33
  34. 34. カスタマイズ ● 自動生成されたコードの処理を変えたい場合、カスタマイズもできるようになってい る ● 基本は.mustacheテンプレートを修正 (https://github.com/OpenAPITools/openapi-generator/tree/master/modules/ openapi-generator/src/main/resources あたりに各言語のテンプレートがありま す) ● 独自の型や概念を追加したい場合はJavaのGenerator Pluginなどを書くこともでき る(難易度高い) 34
  35. 35. ● Configurationに独自ヘッダー追加処理 →そのままでは条件付きでしかヘッダーを書き換えられないので ● HTTP Request実行前のintercept処理 ≒ OkHttpのintercepter →ここでもヘッダー追加できる、Network状態確認したりさせてる ● エラー発生時のハンドリング処理 ≒ RetrofitのCallAdapter →共通のエラー返したり、エラーレスポンスから独自エラーに変換したり PAYでのOpenAPIカスタマイズ 35
  36. 36. ● API定義のレポジトリがある ● React Nativeレポジトリ内からシェルを叩くとyamlを取ってきて同期する ● 手動で更新している ● 具体的にはmonorepoのAPIパッケージを作り、その中にAPIレポジトリ内のyamlの commit shaを保持して、yamlの更新があればscriptを叩いてgenerateコマンドを 実行して更新している 定義ファイルの管理 36
  37. 37. ● yamlの肥大化問題 ● TypeScriptのクライアント側生成コードがmappingに対応していない(Date型などを 定義してもstringが入ってしまう) ● yamlの parameters: の中にobjectを書くと型が反映されない(definitionsへのref にする) 微妙な点はある 37
  38. 38. OpenAPI使ってみて 38
  39. 39. ● 自動生成が便利 ○ クライアントコード ○ ドキュメント ○ モックサーバー ● 学習コストは高め ○ 型定義のノウハウが必要 ○ PAYではやりながら調べて対応してる感じ ● API仕様の共有は楽になった ● OpenAPIいいぞ! メリットは大きい 39
  40. 40. 時間があったら話す 40
  41. 41. React Native 開発中に困ったこととか 41
  42. 42. ● ネイティブモジュール ○ iOS: Cocoapods ○ Android: build.gradle ● npm package ○ package.json ○ monorepoだと各モジュールの依存も管理 ● Bundler ○ Gemfile 管理するライブラリの多さ 42
  43. 43. ● Aブランチ ● Xxxのネイティブライブラリ追加、Android | iOS react-native link済みだよ! ● Bブランチ ● CI用にGemfileにdanger追加させて頂きました! ● Cブランチ ● package.jsonにMobX投入したったで! ブランチの移動がつらい 43
  44. 44. ● ネイティブモジュールの更新時、 yarn install && bundle exec pod --project-directory=/ios install ● Gem更新時 bundle install ● ソースが変わったらTypeScriptのビルド tsc or tsc --watch ブランチの移動がつらい 44
  45. 45. ● React Nativeのdevelopment サーバーがキャッシュ持つので再起動 LAUNCH_PROCESS=`ps ax | grep react-native/scripts/launchPackager.command | grep -v grep | awk '{ print $1 }'` if [ -n "$LAUNCH_PROCESS" ] ; then #LAUNCH_PROCESSの子プロセスをkill pgrep -d' ' -P $LAUNCH_PROCESS | xargs kill # 親プロセスをkill kill $LAUNCH_PROCESS fi ● こんなシェル書いてる ブランチの移動がつらい 45
  46. 46. rm -rf dist && ./script/kill_background_yarn_build_watch.sh && ./script/kill_react_developmet_server.sh && ./script/kill_mock_swagger_server.sh && yarn install && yarn bootstrap && yarn i18n-ts && bundle install --clean --path vendor/bundle && bundle exec pod --project-directory=$MAIN_PACKAGE_DIR/ios install && yarn build && osascript -e "tell app "Terminal" to do script "yarn start"" && yarn build:watch みたいなシェルでがんばっている PAYでの対応: init.shというのがある 46
  47. 47. ● ローカルサーバーへの接続 ○ React NativeはDebugビルド時jsBundleをダウンロードさせることで書き換えたコードの反映をして いる ● 192.168.xxx.xxxのようなローカルIP ● Firewallの設定などによっては、実機が動かない ● PCI-DSS対応などで厳しい会社なので…急に繋がらなくなったりした React Nativeにおけるネットワーク問題 47
  48. 48. ● XMLHttpRequestの仕様らしい、バグかと思ってソースを追った ● そもそもHTTP Headerはどうするべきか? ● HTTP1.xでは大文字小文字はinsensitive ● HTTP/2の仕様だと小文字 ● なので小文字で統一するのは正しそう HTTP Headerが全部小文字になった 48
  49. 49. React NativeのRCTNetworkingとか 本当はソースを追ってみよう、みたいな資料を用意してましたが割愛しています。 公開する資料には載せようと思います。
  50. 50. 以上 弊社に興味があれば是非ご連絡下さい 50

×