· HARUBOUYA · dataflow · 15 min read

SalesforceのデータをAPIでGCPに持ってきてレポートにする

標準レポートでは他のデータと突き合わせられません。接続アプリケーションの作り方から、SOQLでの取得、ページング、BigQueryへの取り込み、上限の避け方までを順に書きます。

SalesforceとGCPがデータ連携でつながっている様子のイラスト

Salesforceには標準のレポート機能があります。それでも外に出したくなる理由は1つで、他のデータと突き合わせられないからです。受注、在庫、Web行動、広告の数字と並べたい瞬間に、Salesforceの中だけでは完結しません。

ここでは、APIでデータを取り出し、BigQueryに入れて、ダッシュボードにするまでを順に書きます。

全体像

Cloud Scheduler(毎日決まった時刻に起動)
  ↓
Cloud Run(Salesforce の REST API を呼ぶ)
  ↓
Cloud Storage(取得した生データを日付つきで置く)
  ↓
BigQuery(読み込む。日付で分割して保持)
  ↓
Looker Studio(ダッシュボードとして表示)

一度に作らないでください。まず1オブジェクトだけを手で取ってBigQueryに入れるところまで通します。そこから自動化します。

なお、BigQuery Data Transfer Service にもSalesforceからの取り込み機能があります。要件が単純なら自前で作らない選択肢もあるため、着手前に公式ドキュメントで対応範囲を確認します。ここでは自前で組む場合の話を書きます。

1. 接続アプリケーションを作る

APIでつなぐには、Salesforce側に「このプログラムからのアクセスを許可する」という登録が要ります。これを接続アプリケーションと呼びます。

手順

  1. Salesforceの右上の歯車から「設定」を開きます
  2. 左メニューで「アプリケーション」→「アプリケーションマネージャ」を開きます
  3. 右上の「新規接続アプリケーション」を押します
  4. 必須項目を入力します
項目入れるもの
接続アプリケーション名用途が分かる名前(例:BigQuery連携)
API参照名名前を入れると自動で入ります。そのままでよいです
取引先責任者メール管理者のメールアドレス
  1. 「OAuth設定の有効化」にチェックを入れます
  2. コールバックURLを入れます。https:// で始まるURLが必要
  3. 「許容するOAuthの範囲」で必要な権限を選ぶ(データへのアクセスと管理、など)
  4. 保存します。「変更が有効になるまで最大10分かかる場合があります」と出るので待ちます
  5. 作成した接続アプリケーションの管理画面で、コンシューマ鍵とコンシューマの秘密を控えます

この2つがプログラム側で使う資格情報です。パスワードと同じ扱いにして、コードには書かずSecret Managerに保存します。

認証の方式

ユーザー名とパスワードを毎回送る方式でもトークンは取れます。ただし、サーバー間の定期処理ではログイン情報を送らなくて済むOAuthのフローを使います。どのフローを選ぶかはSalesforceのヘルプに一覧があるため、そこから要件に合うものを選びます。

認証に成功すると、次の2つが返ります。

返るもの使い道
アクセストークンAPIを呼ぶときのヘッダーに付けます
インスタンスURLAPIを呼ぶ先のホスト。組織ごとに異なります

インスタンスURLを固定値で持たないでください。組織の移行や設定変更で変わることがあるため、認証時に返る値を使います。

2. データを取る

エンドポイント

GET <インスタンスURL>/services/data/vXX.X/query?q=<SOQL>

ヘッダーに認証を付けます。

Authorization: Bearer <アクセストークン>

vXX.X はAPIのバージョンです。組織が対応しているバージョンは /services/data/ を叩けば一覧で返ります。最新を常に指すのではなく、使うバージョンを固定します。上げるときは検証してから上げます。

SOQLの書き方

SQLに似ていますが別物です。URLに載せるため、クエリ中のスペースは + か %20 に置き換えます。

SELECT+Id,Name,Amount,CloseDate,LastModifiedDate+FROM+Opportunity

構文が不正な場合は MALFORMED_QUERY が返ります。

レスポンスの形

{
  "totalSize": 3222,
  "done": false,
  "nextRecordsUrl": "/services/data/vXX.X/query/01gRO0000016PIAYA2-500",
  "records": [ ... ]
}
項目意味
totalSize条件に合う総件数
doneこれ以上続きが無ければ true
nextRecordsUrl続きを取るためのパス
records取得したレコードの配列

ページングが必須

同期のクエリで一度に返るのは最大2,000件です。レコードの大きさによってはそれより少なくなります。

done が false の間、
  nextRecordsUrl をインスタンスURLに連結して GET を繰り返す

ここを実装し忘れると、2,000件で静かに切れたデータが毎日入り続けます。エラーにならないため気づきにくいです。

3. 件数が多い場合

2,000件以上を返すクエリは、Bulk API 2.0 が用意されています。非同期で、ジョブを作って結果を後から取りに行く方式です。

方式向く場面
同期のクエリ+ページング数千件までの日次差分
Bulk API 2.0初回の全件取得、数万件以上の抽出

初回に全件を取り、以降は差分だけを同期のクエリで取る、という組み合わせが現実的です。

4. 差分と削除の扱い

毎日全件を取ると、API呼び出しの上限に当たります。差分だけを取ります。

更新分を取る

LastModifiedDate で絞ります。

SELECT+Id,Name,Amount+FROM+Opportunity
+WHERE+LastModifiedDate+>+2026-01-01T00:00:00Z

前回いつまで取ったかを、BigQuery側かファイル側に記録しておき、次回はそこから取ります。

削除分を取る

差分取得の弱点は、削除されたレコードが永遠に残ることです。更新日時で絞る限り、消えたものは引っかかりません。

REST APIには次が用意されています。

リソース用途
QueryAll削除済み・アーカイブ済みを含めて取得します
sObject Get Deleted期間を指定して、削除されたレコードのIDを取得します
sObject Get Updated期間を指定して、更新されたレコードのIDを取得します

削除を反映しないなら、その旨をダッシュボードに明記します。黙って古い件数を出し続けるのが一番まずいです。

5. API呼び出しの上限

Salesforceには24時間あたりの呼び出し回数の上限があります。組織単位の集計で、ユーザーごとではありません。

エディション24時間あたりの上限
Developer Edition15,000
Enterprise / Professional(API有効)100,000 +(ライセンス数 × ライセンス種別ごとの数)+ 購入分
Unlimited / Performance100,000 +(ライセンス数 × ライセンス種別ごとの数)+ 購入分
Full Sandbox5,000,000

Enterprise Edition で Salesforce ライセンスが15個なら、100,000 + 15 × 1,000 = 115,000件です。REST API も Bulk API もこの枠に入ります。

その他の制限は次のとおりです。

制限値
20秒以上かかる同時リクエスト数本番・Sandboxは25、Developer Editionは5
タイムアウトクエリ以外は10分
URIとヘッダーの合計サイズ16,384バイト

長いSOQLをURLに載せると、最後の制限に当たります。取得する項目を絞るだけで回避できることが多いです。

使用量の見方

方法手順
応答ヘッダーREST APIの応答に付く Sforce-Limit-Info を記録しておきます
専用のリソース/services/data/vXX.X/limits を叩きます
管理画面設定 → システムの概要 → 「API 使用状況」
通知「API 使用状況通知」を設定すると、一定割合を超えたときにメールが届きます

通知は最初に設定します。上限に当たってから気づくと、その日はもう取れません。

6. BigQueryに入れる

取得したデータは、いったんCloud Storageに置いてから読み込みます。

gs://<バケット名>/salesforce/opportunity/dt=2026-01-15/data.json

日付でフォルダを分けると、後から特定の日だけ作り直せます。直接BigQueryに書き込むより、この一段を挟むほうが復旧が楽になります。

テーブルの持ち方

決めること選択肢目安
更新方法全件洗い替え/差分の追記+重複排除件数が数万までなら洗い替えが単純で安全
分割取り込み日/レコードの日付クエリで絞る列に合わせます
型日時はTIMESTAMP、金額はNUMERIC文字列のまま入れません

洗い替えにする場合、取得が途中で失敗したときに前日分まで消えないようにします。新しいテーブルに書いてから差し替える形にします。

日時の扱い

SalesforceのAPIが返す日時はUTCです。日本時間で見たいなら、BigQuery側で変換します。

SELECT
  DATETIME(close_date, 'Asia/Tokyo') AS close_date_jst
FROM
  `<データセット>.opportunity`

保存はUTCのまま、表示のときだけ変換します。保存時に変換すると、後から取り直したデータと混ざります。

7. レポートにする

Looker Studio でBigQueryのテーブルをつなぎます。

  1. Looker Studio を開き、「作成」→「レポート」を押します
  2. データに接続する画面で「BigQuery」を選びます
  3. プロジェクト → データセット → テーブルの順に選びます
  4. 「追加」を押します

閲覧されるたびにBigQueryへのクエリが走ります。見る人が増えるほど費用が増えるため、集計済みのテーブルを別に作り、ダッシュボードはそれだけを見る形にします。

失敗例

失敗何が起きるか代わりにやること
ページングを実装しません2,000件で切れたデータが毎日入ります。エラーは出ませんdone が true になるまで繰り返します
毎日全件を取りますAPI呼び出しの上限に当たり、その日は取れなくなりますLastModifiedDate で差分だけ取ります
削除を取り込みません消えたレコードが残り、件数が合いませんQueryAll か Get Deleted を併用します。対応しないなら明記します
SOQLをURLエンコードしませんクエリが途中で切れる、または不正になりますスペースを + か %20 に置換します
インスタンスURLを固定値で持ちます組織の変更で一斉に動かなくなります認証時に返る値を使います
APIバージョンを最新に追従させます予告なく挙動が変わります使うバージョンを固定し、上げるときは検証します
資格情報をコードに書きますリポジトリの履歴に残り、消せませんSecret Managerに置きます
上限の通知を設定しません当たってから気づきます「API 使用状況通知」を先に設定します

まとめ

  • 外に出す理由は、他のデータと突き合わせるためです。それ以外なら標準レポートで足ります
  • 接続アプリケーションを作り、コンシューマ鍵と秘密を取得します。資格情報はSecret Managerへ
  • 同期のクエリは一度に最大2,000件です。ページングは必須で、忘れると静かにデータが欠けます
  • 初回の全件はBulk API 2.0、以降は LastModifiedDate の差分取得
  • 削除は差分では取れません。QueryAll か Get Deleted を併用します
  • API呼び出しの上限は組織単位で24時間集計です。使用量の通知を最初に設定します
  • 日時はUTCのまま保存し、表示のときだけ日本時間に変換します

最初にやることは設計ではなく、1オブジェクトを手で1回取ってみることです。件数・項目・日時の形を見てからでないと、設計の前提が決まりません。

Share:

参考になったら、いいねを押してください。

コメント

    お名前とコメントは、確認後にこのページで公開されます。メールアドレスや電話番号などは書かないでください。

    Back to Blog

    Related Posts

    View All Posts »
    Dataformでデータ変換を管理する

    Dataformでデータ変換を管理する

    画面に貼り付けたSQLは、誰がいつ何のために変えたのか追えなくなります。SQLをファイルとして持ち、依存関係を自動で解決して実行する仕組みの入り方を書きます。