REST API による Salesforce データへのアクセス
学習の目的
この単元を完了すると、次のことができるようになります。
- RestClient インターフェースを使用して REST 要求を発行する。
- Salesforce から REST 応答を受信する。
- Mobile SDK を使用して REST 応答を処理する。
一緒にトレイルを進みましょう
エキスパートの説明を見ながらこのステップを実行したい場合は、次の動画をご覧ください。これは「Trail Together」(一緒にトレイル) シリーズの一部です。
(この動画は 16:05 の時点から始まります。戻して手順の最初から見直す場合はご注意ください。)
REST 要求の送信
カスタムビューでは、Salesforce API 経由で Salesforce 組織のデータにアクセスします。Mobile SDK Swift アプリケーションで Salesforce API をコールする方法を詳しく見ていきましょう。
RestClient パブリッシャーの使用
Salesforce データにアクセスするには、Salesforce に REST 要求を送信してアプリケーションで応答を受信します。ネットワーク要求をコーディングして送信し、応答を処理するにはどうすればよいのでしょうか?
Swift UI アプリケーションでは、ビュー-モデルアーキテクチャを使用します。ビュークラスは SwiftUI で画面のレイアウトを定義し、実行時に、インターフェースに入力するデータの関連付けられたモデルクラスをコールします。Mobile SDK Swift テンプレートプロジェクトで、モデルクラスは Models プロジェクトフォルダーに存在します。たとえば、ContactsForAccountModel.swift ファイルは、取引先の取引先責任者リストを要求するコードを定義します。応答が届くと、ContactsForAccountModel
クラスが返されたレコードを処理して、取引先責任者情報のリストを ContactsForAccountListView
クラスに送信します。
RestClient
は、すべての REST サービスへのエントリポイントです。Mobile SDK アプリケーションは、RestClient メソッドを使用して REST 要求を作成して送信します。このクラスには常に、次の共有インスタンス経由でアクセスします。
RestClient.shared()
fetchContactsForAccount(_:)
メソッドで実施される標準の「送信要求」シーケンスは次のようになります。RestRequest
インスタンスを作成して初期化します。RestClient
は、この目的で数多くのファクトリーメソッドを用意しています。この例では SOQL クエリ要求を作成していますが、目的に合わせて任意のRestClient
メソッドを選択できます。- 要求オブジェクトを Salesforce に送信します。
RestClient
は、現在のユーザーのログイン情報を使用して自動的に要求を認証します。
- Xcode で、ContactsForAccountModel.swift ファイルを開きます。
fetchContactsForAccount(_:)
メソッドを検索します。実装は次のようになります。class ContactsForAccountModel: ObservableObject { @Published var contacts: [Contact] = [] var account: Account? private var contactsCancellable: AnyCancellable? func fetchContactsForAccount(){ guard let acct = self.account else {return} let request = RestClient.shared.request(forQuery: "SELECT id, firstName, lastName, phone, email, mailingStreet, mailingCity, mailingState, mailingPostalCode FROM Contact WHERE AccountID = '\(acct.id)'", apiVersion: nil) contactsCancellable = RestClient.shared.publisher(for: request) .receive(on: RunLoop.main) .tryMap({ (response) -> Data in response.asData() }) .decode(type: ContactResponse.self, decoder: JSONDecoder()) .map({ (record) -> [Contact] in record.records }) .catch( { error in Just([]) }) .assign(to: \.contacts, on:self) } } }
RestClient
共有インスタンスを使用します。このコールは、次のコードで始まる長いステートメントで確認できます。 let request = RestClient.shared.request(forQuery:...
RestRequest
オブジェクトには、所定の SOQL 文字列に基づいてフォーマット済みの REST 要求が含まれます。RestClient
パブリッシャー) を活用して、このどちらの手順も簡素化しています。このパブリッシャーをコールすることで、実質的には単に「これが私の要求です」と告げることになります。要求を受け取ったパブリッシャーがネットワークコールを処理して Salesforce に要求を送信し、ネットワーク応答を整理したうえで元の待機コードに配信します。パブリッシャーのコールは、次のコードで始まる行で確認できます。
contactsCancellable = RestClient.shared.publisher(for: request)
コールチェーンとして続く一連のコールを見たことがあるかもしれません。SwiftCombine のパブリッシャーでこうしたコールは一般的な構造で役に立ちます。このコールチェーンは非同期ネットワーク応答を、最終的に終了または失敗のいずれかになる Future
オブジェクトとして処理します。コールチェーンごとに、現在のデフォルトオブジェクトでアクションが実行されます。このオブジェクトは、チェーンの前のコールの戻り値でリセットできます。ネットワークコールに失敗した場合や Salesforce がエラーを返した場合は、処理が .catch
ブロックにフォールスルーします。
コールチェーンがどのように機能するのかを把握できるように、細かくコメントされたシーケンスのリストを以下に示します。
// Use the RestClient publisher to send the request and return the raw REST response contactsCancellable = RestClient.shared.publisher(for: request) // Receive the raw REST response object .receive(on: RunLoop.main) // Try to convert the raw REST response to Data // Throw an error in the event of failure .tryMap({ (response) -> Data in // Return the response as a Data byte buffer response.asData() }) // Decode the Data object as JSON to produce an array // of Contacts formatted as a ContactResponse object .decode(type: ContactResponse.self, decoder: JSONDecoder()) // Map the JSON array of Contacts .map({ (record) -> [Contact] in // Copy the Contact array to the records // member of ContactResponse record.records }) // If an error is thrown, publish an empty array .catch( { error in Just([]) // Combine publisher that rescues a failed publisher }) // Store the array of contacts in the model’s published contacts // property for use by ContactsForAccountListView .assign(to: \.contacts, on:self) }
その他のオプション
テンプレートアプリケーションで他のモデルクラスを使用する場合、RestClient.shared.publisher
が Salesforce データを取得する唯一の手段ではありません。たとえば、AccountsListModel
は他の 2 つのパブリッシャーを使用します。
- SmartStore パブリッシャー
- Mobile Sync パブリッシャー
現時点で SmartStore と Mobile Sync について認識している必要はありませんが、簡単に言うと、これらは Mobile SDK の 2 つのオフライン機能です。SmartStore は、Salesforce レコードのオフラインリポジトリとして機能するローカルストレージ設定です。暗号化されたリポジトリである SmartStore はモバイルデバイス上に存在するため、ネットワーク接続に障害が発生した場合でも顧客が作業を続行できます。他方、Mobile Sync は次の面倒な処理を実行します。
- Salesforce レコードを取得する
- レコードを SmartStore スープ (データベーステーブルのようなもの) に保存する
- 顧客が新しいレコードをダウンロードしたり、ローカルの変更をアップロードしたときに、SmartStore レコードとサーバーレコードが常に同期するようにする
Mobile SDK は Swift クラス拡張でこれらのパブリッシャーを定義します。どのようなしくみになっているのかに関心がある場合は、Xcode のいずれかの publisher
変数を右クリックして、[Jump to Definition (定義へ移動)] を選択します。どちらの場合もコードはスパースで、実際の機能は SmartStore メソッドまたは Mobile Sync メソッドに従います。これらのパブリッシャー、その基盤となるテクノロジー、REST API インタラクションをコーディングするその他の手段についての詳細は、「リソース」のリンク先を参照してください。スマートで効率的なパブリッシャーを使い続けるうちに手放せなくなるかもしれません!