Skip to main content

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(_:) メソッドで実施される標準の「送信要求」シーケンスは次のようになります。
  1. RestRequest インスタンスを作成して初期化します。RestClient は、この目的で数多くのファクトリーメソッドを用意しています。この例では SOQL クエリ要求を作成していますが、目的に合わせて任意の RestClient メソッドを選択できます。
  2. 要求オブジェクトを Salesforce に送信します。RestClient は、現在のユーザーのログイン情報を使用して自動的に要求を認証します。
では、コードを詳しく見てみましょう。
  1. Xcode で、ContactsForAccountModel.swift ファイルを開きます。
  2. 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)
            }
        }
    }
このメソッドが REST 要求を作成して Salesforce に送信し、応答を処理します。要求オブジェクトを作成するために、RestClient 共有インスタンスを使用します。このコールは、次のコードで始まる長いステートメントで確認できます。 
let request = RestClient.shared.request(forQuery:... 
生成された RestRequest オブジェクトには、所定の SOQL 文字列に基づいてフォーマット済みの REST 要求が含まれます。

要求がどのように送信され、応答がどのように受信されるかは、さほど明白ではありません。この例では、Mobile SDK Swift Combine のパブリッシャー (正確には 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 インタラクションをコーディングするその他の手段についての詳細は、「リソース」のリンク先を参照してください。スマートで効率的なパブリッシャーを使い続けるうちに手放せなくなるかもしれません!

無料で学習を続けましょう!
続けるにはアカウントにサインアップしてください。
サインアップすると次のような機能が利用できるようになります。
  • 各自のキャリア目標に合わせてパーソナライズされたおすすめが表示される
  • ハンズオン Challenge やテストでスキルを練習できる
  • 進捗状況を追跡して上司と共有できる
  • メンターやキャリアチャンスと繋がることができる