APIを使って自社サービスのアカウント情報をSalesforceに自動で登録する

こんにちは、開発の渡邊です。

先日、弊社でSalesforce(Service cloud)を導入しました。

Salesforceを運用するにあたり、自社サービスであるsmartroundのアカウント情報を、サポート・マーケティング・営業活動などに利用したい、という要望がありました。アカウント情報のデータ連携を行うことで、例えば、以下のようなことが可能になります。

・ smartroundの登録情報を元にサポートの返答を行う
例えば、「ログインができない」というお問い合わせがあったとして、サインアップが仮登録で止まっているユーザーには本登録をご案内し、本登録が完了しているユーザーにはパスワード変更のご案内をするなど。

・smartroundにサインアップしていないリードに対してのみ、マーケティングのメールを送る

この記事では、Webアプリケーションエンジニアの方向けに、「Salesforceに自社サービスのデータを自動で登録して参照したい」という要望を受けた際に、データ連携システムを開発するための情報を紹介します。

Salesforceの知識レベルは、名前だけは聞いたことがある、ぐらいの想定です。(依頼受けた時点の僕のことです)

記事が長くなったので、最初にざっくりまとめを書いときますと、以下のようになります。

1. Salesforceの基礎知識を学ぶ
2. 要件を洗い出す
 ・ 実際のWebUIを見ながら要件を確認すると良い
3. Salesforceのオブジェクト設計・設定
 ・ クロスオブジェクト数式が便利
4. SalesforceのREST API/Bulk API 2.0を使って連携システムを開発
 ・ 外部IDをうまいこと使う

最低限必要なSalesforceの知識と用語

僕の非常にざっくりした理解では、データ(例えば顧客情報など)を登録して、それを参照・操作するというのがSalesforceの大まかな利用方法です。
データを登録して参照というと、我々的にはRDBが馴染み深いと思いますが、Salesforceにも似たような概念があるので、まずはそういった基本概念や用語を解説します。

WebUIを含めた全体的なサービスの雰囲気を知りたい場合は、下記の入門動画を見ていただくのが良いと思います。https://help.salesforce.com/articleView?id=000315841&type=1&mode=1

オブジェクト
オブジェクトという概念があります。Salesforceでいうオブジェクトは、RDBでいうところのテーブルのようなもので、オブジェクトに複数件のデータを登録して参照できます。この1件1件のデータはレコードと呼ばれます。(RDBと一緒ですね)

また、オブジェクトのデータ項目は、そのまま項目と呼ばれており、これはRDBでいうところのカラムに対応します。項目はユーザーが自由に追加することができ、それらはカスタム項目と呼ばれます。

対応関係はこんな感じです。
・テーブル(RDB)  <-> オブジェクト(Salesforce)
・ カラム(RDB)     <-> 項目(Salesforce)
・ レコード(RDB) <-> レコード(Salesforce)

標準オブジェクト
オブジェクトには、Salesforceがデフォルトで用意しているものがあり、それらは標準オブジェクトと呼ばれます。(Salesforceの製品やエディションによって、利用可能な標準オブジェクトの種類やそれに付随する機能に差異があります)

今回の開発では、以下の標準オブジェクトを利用しました。

・取引先:会社単位のデータを保持する。取引先に紐づく商談を管理する、などの使い方ができる。
・取引先責任者:人単位のデータを保持する。取引先責任者にメールを送る、などの使い方ができる。

カスタムオブジェクト
オブジェクトはユーザーが自由に作成することができます。
こちらは、標準オブジェクトに対してカスタムオブジェクトと呼ばれます。

今回の開発では、以下のカスタムオブジェクトを作成しました。

・SRユーザー:smartroundのユーザーアカウント単位のデータを保持する
・SR会社:smartroundの会社アカウント単位のデータを保持する

Sandbox
開発のためにSalesforceの設定を変更したいけど、運用中の本番のデータに影響は与えたくない、ということがあると思います。

SalesforceのSandbox環境を作ることで、本番のデータに影響を与えることなく、設定を試行錯誤しながら開発が可能です。
開発中は、基本的にSandbox環境に対して作業を行うことになります。

また、変更セットの機能を使うことで、Sandbox環境に行った変更を本番環境に適用することも可能です。https://help.salesforce.com/apex/HTViewHelpDoc?id=data_sandbox_create.htm&language=ja

組織
組織は、Salesforceのデータの隔離単位です。
組織の中にオブジェクトやレコードが存在し、組織毎にそれらは独立しています。マルチテナントで言うところのテナントと同じような概念という認識です(違ってたらごめんなさい)。本番の組織の設定やデータをコピーして、Sandboxの組織を作ることができます。

最低限必要なsmartroundの知識と用語

smartroundは資本政策や経営情報などの、スタートアップの運用に必要なデータを管理するためのサービスです。

サービスの詳細は一旦置いておいて(ご興味ある方は是非こちらのサイトをご覧ください)、今回の連携システムで重要になるのは、そのアカウントのデータ構造です。

smartroundでは、1つの会社アカウントに複数のユーザーアカウントが所属する、というデータ構造になっています。
新規にサインアップすることで会社アカウントと自身のユーザーアカウントを作り、そこに自社のメンバーを招待することで、会社アカウントに所属するユーザーアカウントを増やしていくことができます。

簡単のため、以降の文では、smartroundの会社アカウントのことを「SR会社」、smartroundのユーザーアカウントのことを「SRユーザー」と呼ぶことにします。

要件

Salesforceを主に利用する社員へのヒアリングの結果、今回の連携システムの要件はざっくりと以下のようになりました。

1. smartround上のユーザーアカウント(SRユーザー)と会社アカウント(SR会社)の情報をsalesforce上で確認したい
・例えば、特定のメールアドレスがsmartroundにサインアップ済みか、といった情報
・新規にサインアップしたSR会社・SRユーザーのアカウント情報は、即時でSalesforceに登録したい
・利用中のアカウントのデータは、1日に1回程度の頻度でSalesforceに登録したい(サービスを退会した場合のステータス反映などはこのタイミングになる)

2. SRユーザーの情報を取引先責任者の項目として表示し、絞り込みや検索に利用したい

要件を固める際には、WebUIレベルでどういう操作をしたいのか、実際に利用する人に使い方を見せてもらうと、イメージが掴みやすかったです(当然といえば当然ですが)。
例えば、「SRユーザーの情報を取引先責任者の項目として表示し、絞り込みや検索に利用したい」という上記の要件は、具体的には、以下のような画面で絞り込みを行うことを想定しています。

スクリーンショット 2020-08-03 13.43.01

データ連携システムの概観

連携システムの概観は下図のようになります。

画像2

今回のデータ連携システムの方針として、まずは、オブジェクトのレコード管理の責務を明確に分けました。

具体的には、「取引先」と「取引先責任者」に関しては、ビジネスサイドのメンバーなどが手動またはCSVインポートなどで管理します。

一方、「SRユーザー」と「SR会社」に関しては、連携システムのみがデータの管理を行うこととしました。また、「取引先責任者」と「SRユーザー」の関連付けも、連携システムの責務と決めました。

この方針は、データの編集経路を一本化することで、データの編集結果が予測可能になり、運用時の負荷が下がることを狙っています。例えば、手動管理していた取引先責任者レコードのデータを、お試しで作ったsmartroundのユーザーアカウント情報で上書きしてしまう、といったことがなくなります。

また、標準オブジェクトとカスタムオブジェクトの関連を、なるべく疎結合にすることで、将来的なオブジェクトのスキーマ変更の柔軟性向上も目的としています。

それっぽく理由を書きましたが、以前に別のCRMとの連携で、手動編集と自動連携で同じデータを管理していた時に、上述のような問題に何度も直面した、という経験則による判断も大きいです。

Salesforceでのオブジェクト設計

実際に行った全てのオブジェクト設定を紹介すると長くなりすぎるので、「SRユーザー」と「取引先責任者」のオブジェクト設定の重要な部分だけ解説します。

まずは、SRユーザーです。SRユーザーというカスタムオブジェクトを作成し、オブジェクト名は「SrUser」としておきます。

また、SRユーザーの項目設定は以下です。SRユーザーIDの外部IDという属性は後述するBulk APIの利用に必要になります。

・SRユーザーID
項目名:srUserId
データ型:数値
備考:必須、ユニーク、外部ID

・メールアドレス
項目名:email
データ型:テキスト
備考:必須。ユーザーのメールアドレス(メール型もあるけど実装の都合上テキスト型)

次に、取引先責任者に追加した項目設定です。

・SRユーザー
項目名:srUser
データ型:参照関係
備考:必須にはしない。参照しているSRユーザーレコードが消された場合は、この項目の値をクリアする

・SRユーザーID
項目名:srUserId
データ型:数式
備考:クロスオブジェクト数式でSRユーザーの情報を参照する

クロスオブジェクト数式という用語が出てきました。
この機能を使うことで、取引先責任者の項目として、参照しているSRユーザーの項目値を表示したり、検索に利用することが可能になります。

srUser__r.srUserId__c が数式部分です。参照先のカスタムオブジェクト名には __r を付加する必要があります。

スクリーンショット 2020-08-03 15.31.20

参考:https://help.salesforce.com/articleView?id=customize_cross_object.htm&type=5

データ連携システムの設計と実装

ここまでくれば、あとはAPIを使って、サービスのデータをSalesforceに登録するだけです。ここでは、要件の一つである、日次でのデータの登録の開発について解説します。

今回は主に一括処理の説明をするので、REST APIではなく、Bulk API 2.0というAPIを利用します。一括ではなく単体での処理をしたい場合は、下記リンク先のREST APIのドキュメントを参照してください。
https://developer.salesforce.com/docs/atlas.ja-jp.api_rest.meta/api_rest/intro_what_is_rest_api.htm

APIの認証
APIの認証方式はOAuthだけで、今回のケースだとユーザー毎の認可は不要なので、Client Credentials Grantが良さそうです。しかし、SalesforceではClient Credentials Grantはサポートされておらず、簡易なAPIキーによる認証もないです。

そこで、今回は、API用のユーザーにランダム生成した十分長いパスワードを設定し、Resource Owner Password Credentials Grantを利用することとしました。
https://developer.salesforce.com/docs/atlas.ja-jp.api_rest.meta/api_rest/quickstart_oauth.htm

※追記:salesforceではJWTベアラーフローをサポートしているそうなので、サーバ間連携ではResource Owner Password Credentialsではなく、JWTベアラーフローを使う方が良さそうです。
https://help.salesforce.com/articleView?id=remoteaccess_oauth_jwt_flow.htm&type=5

Bulk API 2.0
SalesforceのAPIには1日の実行回数に制限があるため、全ユーザーのデータ登録処理を1件1件REST APIで実施すると、制限に引っかかってしまいます。
この制限を回避するため、レコードを一括で処理可能なBulk API 2.0を利用しました。(日次バッチでの一括処理ではなく、即時でのデータ登録の要件では、REST APIを用いて1件ずつ処理しています。)

このAPIは、REST API用に取得したOAuthのアクセストークンをそのまま利用することができます。
https://developer.salesforce.com/docs/atlas.ja-jp.api_bulk_v2.meta/api_bulk_v2/introduction_bulk_api_2.htm

外部ID
SRユーザーオブジェクトのSRユーザーID項目で、外部IDという属性を指定しました。Bulk API 2.0では、この外部IDをレコードの同一性の判定に利用することで、一括でのUPSERT処理が可能になります。

外部IDには、連携元の自社サービス内でのユニークなIDを利用するのが、素直な設計かと思います。

実際のAPIリクエスト例
Bulk API 2.0では、所定の順でAPIを実行していくことで、レコードデータの一括処理が可能です。以下では、SRユーザーのデータを一括作成・更新する場合のリクエスト例を紹介します。

APIのエンドポイントはSandboxのものを想定しています。また、利用するAPIのバージョンはv48.0とします。

APIのURLに含まれる${instance}の部分は、組織によって可変です。アクセストークン取得時にレスポンスに含まれるinstance_urlを参照することで、リクエストの送り先を決定する必要があります。

1. UPSERTの一括処理ジョブを作成
まずは、一括処理のジョブを作成します。リクエストボディでジョブの設定内容を指定できます。

objectには、SRユーザーのオブジェクト名を指定します。
externalIdFieldNameは外部IDとして指定した、SRユーザーID項目の項目名を指定します。

カスタムオブジェクトのオブジェクト名や、カスタム項目の項目名には、__cが自動で付加されているのでご注意ください。

POST https://${instance}.salesforce.com/services/data/v48.0/jobs/ingest
{
  "object": "SrUser__c",
  "operation": "upsert",
  "externalIdFieldName": "srUserId__c"
}

2. CSVをアップロード
一括更新したいレコードのデータをCSVにしてアップロードします。
リクエストのContent-Typeヘッダの値をtext-csvにする必要があります。
URL内の${jobId}には、ジョブ作成APIのレスポンスに含まれるジョブIDを指定します。

PUT https://${instance}.salesforce.com/services/data/v48.0/jobs/ingest/${jobId}/batches
"srUserId__c","Name","email__c"
"1","test1","test1@example.com"
"2","test2","test2@example.com"
"3","test3","test3@example.com"

3. ジョブのステータスをUploadCompleteに変更
ジョブのステータスをUploadCompleteにすると、一括処理が開始されます。

PATCH https://${instance}.salesforce.com/services/data/v48.0/jobs/ingest/${jobId}
{
"state" : "UploadComplete"
}

以上のAPI実行により、一括処理ジョブが実行されます。
実行結果の詳細は、Salesforceの設定画面の「一括データ読み込みジョブ」の画面から確認が可能です。

また、APIでジョブの実行結果を確認することもできるので、ジョブ情報の取得APIをポーリングするなどして結果を取得して、その後の処理を分岐させても良いと思います。

おしまい

本記事では、SalesforceのAPIを使って、自社サービスのデータをSalesforceに登録するデータ連携システム開発について紹介しました。
似たような状況になる方はあまりいないかもですが、ばっちり状況が一致したWebアプリケーションエンジニアの方は、本記事を参考していただければ幸いです。


この記事が気に入ったらサポートをしてみませんか?