ボクココ

個人開発に関するテックブログ

外部サービスの API で取ってきたデータを一括でDB登録する

ども、@kimihom です。

f:id:cevid_cpp:20191024173445j:plain

最近はいろいろな企業が API を提供してくれるようになってきた。外部サービスの API で、例えば顧客情報などを一括で取り込みたいというケースはよくあることだろう。私はこうして実装したということで記事として起こしてみる。

バックグラウンド処理

こうした外部サービスとのやりとりは、外部サービス側のレスポンス速度などで実行時間が大きく変動するため、バックグラウンドで呼び出す流れが基本となるだろう。私はバックグラウンド処理は基本的に AWS Lambda 側に渡して実行させるようにしている。AWS Lambda 側で処理をさせると開発やテストなどが個人的には簡単でやりやすくて気に入っている。

サーバー => AWS Lambda => 外部サービスAPI 呼び出し => サーバー => データベース

AWS Lambda で外部API を呼んで一気にデータを取ってきた後、データを整えて JSON 形式にする。その JSON を AWS Lambda から自前のサーバーへ HTTP リクエストを送って、そのリクエストを判定してデータベースに保存していくという流れだ。

実装の中で、AWS Lambda 側の処理とサーバーでデータを受け取る部分の実装に関して記す。

データ取得における注意点

まずは AWS Lambda 側でデータ取得する際の注意点を記しておく。

一括取得の API はデータ数と API 側の制約に注意しよう

一括取得の API は、想像の通りそれだけでそれなりにサーバーに負荷がかかる。そのため、一部の API では秒間のリクエスト制限を設けているところもある。何も考えずに全データ一気に取ってくるぜ!ってことやっちゃうと、途中でデータ取得に失敗してうまくいかないことがよくある。ほとんどの API ドキュメントには、このような制限が記載されているので確認しよう。API からデータをリスト取得する際の ページごとの取得件数や上限なども確認しておこう。

テスト段階では、外部サービスの API で取ってくるデータ量ってのはテストデータ程度なので問題になることはない。ただ実際に使っているユーザーの中には想像を超えるような大量のデータを外部サービス側で保存していることがある。なので仮にデータが何万件あっても API で全部とってこれちゃうような場合でも、実装の中に最大の取得上限は設けておいたほうがいい。外部サービス側で万・億並のデータがあったら、それだけで自分たちのデータベースがパンクしてしまう恐れがある。全データ取ってこなきゃ意味がない!っていう API 連携を予定している場合には、それでも期間などで絞り込みをして全データ取得って手段は控えるべきだと思う。ここまで書いてそれでも全部取るってなら私は止めはしない。

用件に満たないデータは予め整備しよう

外部サービス側の API では データがない(NULL)って場合も多くある。そうしたデータのないものも とにかく API で全部とってきてしまうと、それだけで無駄なリクエストとなってしまう。例えば自分たちのサービスではメールアドレスが必須だけど外部サービス API 側ではメールアドレスが必須ではない場合、メールアドレスの存在するデータだけを API のパラメータで指定できるなら指定しよう。メールアドレスありだけっていう API パラメータが指定できない場合は、自分たちのサーバーに送る前のデータ整備の段階で、メールアドレスのない情報は予め削除しておこう。これだけで多くのリクエストの無駄を解消することができる。全部自前のサーバーでやればいいやって判断は後々痛い目を見ることになる。

一括でデータを送ることは控えよう

例えば外部サービス API で 4,000件のデータを取ってこれたとしよう。そのデータを一括で 自前のサーバーにリクエストを送ることは決してしないように。それだけで自前サーバーがパンクする恐れがある。

100件ごとに データを区切って、AWS Lambda => 自前サーバー のレスポンスがちゃんと返ってきたら、次のデータを送るって流れを取ろう。最近の AWS Lambda は10分以上も実行させ続けられるので、数千件程度であれば問題になることはないはずだ。

データ保存における注意点

では次に AWS Lambda から自前のサーバーに渡ってきたときのサーバー側の注意点を上げよう。

リクエストの認証をしよう

AWS Lambda から送られてきた HTTP リクエストのみをデータ保存するように実装しよう。仮にもし 一括登録の URL が外部に漏れて、データを一括で送信された場合、意図しないデータ登録が発生してしまうリスクがある。どこまで厳密にするかは実装次第ではあるけど、最低限リクエストのパラメータを確認することはちゃんとしよう。

同一データの扱いに気をつけよう

例えば自分たちのデータでは メールアドレスはユニークでなければならないケースなどだ。外部サービス側では当然そんな制約がないことも多くあるので、その場合のデータ登録について実装を考慮する必要がある。私の場合、メールアドレスが登録されていない場合にはデータ挿入、メールアドレスが既に存在する場合にはデータ更新 というところで実装を分けている。サーバーに送られてきた JSON を一つ一つチェックし、データ一括挿入枠と一件ずつ更新するデータ更新枠の2つに分ける。

データ一括挿入枠に入ったデータは、activerecord-import を使って一括登録する。データ更新枠に入ったデータは、一件ずつ Update をしていく。アップデートだけだったとしても、1リクエストにつき 100件なので、そこまで負荷がかかる処理でもない。

終わりに

今後、SaaS のビジネスがますます賑わっていくにつれ、こうした API による連携ってのはどんどん増えていくことだろう。

利用ユーザーさんがより便利に活用できるように、Cool な実装で問題を解決していこう。