進行状況の追跡を始めよう
Trailhead のホーム
Trailhead のホーム

REST API による Salesforce データへのアクセス

学習の目的

この単元を完了すると、次のことができるようになります。

  • RestClient インターフェースを使用して REST 要求を発行する。
  • Salesforce から REST 応答を受信する。
  • Mobile SDK を使用して REST 応答を処理する。

REST 要求の送信

RootViewController クラスで、Mobile SDK の REST API クラスのしくみを少しだけ見ることができます。REST API クラスの使用方法を詳しく見てみましょう。

RestClient オブジェクトと RestRequest オブジェクトの使用

Mobile SDK REST API を使用して Salesforce データにアクセスするには、Salesforce に要求を送信してアプリケーションで応答を受信します。では、RootViewController はネットワーク要求をどのように送信するのでしょうか?

RestClient は、すべての REST サービスへのエントリポイントとなるものです。Mobile SDK アプリケーションは、RestClient メソッドを使用して、REST 要求を作成して送信します。このクラスは常に共有インスタンス

RestClient.shared() を介してアクセスします。

loadView() メソッドで実施される標準の「送信要求」シーケンスは次のようになります。
  1. RestRequest インスタンスを作成して初期化します。RestClient は、この目的で数多くのファクトリメソッドを用意しています。この例では SOQL クエリ要求を作成していますが、目的に合わせて任意の RestClient メソッドを選択できます。
  2. 要求オブジェクトを Salesforce に送信します。RestClient は、現在のユーザのログイン情報を使用して自動的に要求を認証します。
では、コードを詳しく見てみましょう。
  1. Xcode で、RootViewController.swift ファイルを開きます。
  2. loadView() メソッドを検索します。実装は、次のようになります。
    override func loadView() {
        super.loadView()
        self.title = "Mobile SDK Sample App"
        let request = RestClient.shared.request(forQuery: "SELECT Name FROM Contact LIMIT 10")        
        RestClient.shared.send(request: request) { [weak self] (result) in
            switch result {
                case .success(let response):
                    self?.handleSuccess(response: response, request: request)
                case .failure(let error):
                     SalesforceLogger.d(RootViewController.self, 
                         message:"Error invoking: \(request) , \(error)")
            }
        }
    }
スーパークラスメソッドをコールしてビュータイトルを設定した後、このメソッドは REST 要求を作成して送信します。このために、次の 2 つを使用します。
  • RestClient 共有インスタンスは、ネットワーク経由で Salesforce に送信される要求オブジェクトを生成する。
  • 生成された RestRequest オブジェクトには、所定の SOQL 文字列に基づいて実行された REST API 要求が含まれる。
REST 応答を処理するために、RootViewController は次のメソッドを使用します。
send(request: Request, _ completionBlock: @escaping (Result<RestResponse, RestClientError>) -> Void)
このメソッドを使用して、成功または失敗を処理するトレイリングクロージャを提供します。トレイリングクロージャ構文のしくみは次のとおりです。クロージャは構文上、関数ブロックになり、引数を取って値を返すことができます。関数の最後の引数種別がクロージャの場合は、パラメータリストからその項目をドロップできます。代わりに、コールの閉じ括弧の直後にクロージャを追加します。トレイリングクロージャを使用すると、構文が簡潔になり、後続の関数コールの予想される結果が独立したものになります。

この場合は、トレイリングクロージャが、result 引数の success メンバーと failure メンバーを読み取って応答状況を判断します。成功の場合は、クロージャが応答データを受信し、別の処理関数に渡します。エラーの場合は、クロージャがエラーメッセージを受信し、記録したうえで戻ります。

このようにして、要求を送信し、完了クロージャを使用して応答を転送します。ここで疑問が浮かぶかもしれません。たとえば、「この行は何を意味するのか?」
{[weak self] (response, urlResponse) in ...
「他にオプションはないのか?」といった疑問です。続けましょう。

REST 応答の処理

Salesforce からデータを受信して使用するには、非同期ネットワークコールバックをインターセプトする機能が必要です。Mobile SDK は、このタスクの次の 2 つのオプションを定義します。

RestClient メソッド
send 関数をコールするときに、トレイリングクロージャを提供します。Salesforce が、iOS オブジェクトとしてラップされたサーバ応答をクロージャに送信します。
RestClientDelegate プロトコル
成功応答と失敗応答を受信する 4 つのコールバック関数を定義します。アプリケーションが REST 要求を送信すると、このプロトコルをサーバの応答のターゲットとして実装するクラスが指定されます。

Objective-C では、インラインブロックコールバックではなく、SFRestDelegate プロトコルを使用するほうが明快でしょう。これは RestClientDelegate の Objective-C 版です。他方、Swift アプリケーションでは、トレイリングクロージャ構文を使用するメリットがあり、よりよい解決策となります。この手法を使用すると、要求の生成から応答の処理まで読み取りやすい自然なフローになります。インラインクロージャはまた、RestClientDelegate プロトコルよりもコーディングが簡単です。

RestClient send(request:_:) メソッドの使用

では、Swift テンプレートアプリケーションで send(request:_:) メソッドをコーディングする方法を詳しく見ていきましょう。

  1. RootViewController テンプレートクラスは Mobile SDK RestClient ファクトリメソッドを使用して SOQL 要求を作成します。
    let request = RestClient.shared.request(forQuery: "SELECT Name FROM User LIMIT 10")
  2. 次の行が、要求を Salesforce に転送する send メソッドをコールします。このメソッドは、クロージャの引数がサーバの応答を受信し、成功または失敗を処理することを想定しています。次に例を示します。
    let request = RestClient.shared.request(forQuery: "SELECT Name FROM User LIMIT 10")
    RestClient.shared.send(request: request) 
    { [weak self] (result) in
        switch result {
            case .success(let response):
                self?.handleSuccess(response: response, request: request)
            case .failure(let error):
                SalesforceLogger.d(RootViewController.self, 
                    message:"Error invoking: \(request) , \(error)")
        }
    }
    この時点で、メソッドの閉じ括弧の直後に、見つけやすい完了クロージャが追加されています。
  3. 応答を受信すると、クロージャのキャプチャリストが応答オブジェクト (result) を受信します。
    { [weak self] (result) in
        
    }
    暗黙の self 参照の代わりに [weak self] が明示的に使用されています。REST 応答は非同期に届くため、応答を受信した時点で、成功クロージャを定義したクラスが依然としてメモリにあるかどうかはわかりません。不要な保持サイクルを回避するために、[weak self] を使用し、self を使用前にクロージャで検証します。
  4. 応答で成功が示された場合は、アプリケーションが意図するフローを続行し、テーブルビューに取引先責任者名のリストを表示できます。テンプレートアプリケーションが、この応答を handleSuccess(response:request:): という別のローカルメソッドに渡します。
    case .success(let response):
        self?.handleSuccess(response: response, request: request)
  5. 失敗の場合は、Mobile SDK が .failure ケースを Error 種別の応答オブジェクト (error) に送信します。このアプリケーションがエラーメッセージを記録して戻ります。
    case .failure(let error):
        SalesforceLogger.d(RootViewController.self, 
            message:"Error invoking: \(request) , \(error)")
            // Nothing more to do, so just return
次に handleSuccess(response:request:) 関数を示します。
func handleSuccess(response: RestResponse, request: RestRequest) {
    guard let jsonResponse  = try? response.asJson() as? [String:Any], 
        let records = jsonResponse["records"] as? [[String:Any]]  else {
            SalesforceLogger.d(RootViewController.self, 
                message:"Empty Response for : \(request)")
            return
    }
    SalesforceLogger.d(type(of:self), message:"Invoked: \(request)")
    DispatchQueue.main.async {
        self.dataRows = records
        self.tableView.reloadData()
    }
}
この関数は応答オブジェクトのほか、元の要求オブジェクトも取ります。予想どおりにいった場合は、Mobile SDK が .success ケースを Dictionary<String, Any> 種別の応答オブジェクト (result) に送信します。ただし、削除要求を送信していた場合などは、要求が成功しても、サーバが有効ながら使用できない結果を返すことがあります。handleSuccess(response:request:) 関数は、guard ステートメントを使用して応答を予想される種別に変換するという方法で最悪の事態に備えます。変換に成功すると、この関数が要求されたレコードを dataRows ローカル変数に保存し、テーブルビューにそのデータを再読み込みするよう指示します。テーブルビューは、そのデータをどこで取得するのでしょうか? ご想像どおり、dataRows 変数から取得します。

RestClientDelegate プロトコルの使用

RestClientDelegate は、コードを明快にするほか、失敗のカテゴリを解析して、失敗応答をカテゴリ固有のハンドラに送信します。クラスが RestClientDelegate プロトコルを採用した場合は、4 つの応答ハンドラ関数を実装します。

  • request(_:didLoadResponse:) — 要求が処理されました。代理オブジェクトは JSON 形式の応答を受信します。このコールバックは成功を示します。send(request:onFailure:onSuccess:) メソッドの成功クロージャに配置したものと同じコードが含まれます。
  • request(_:didFailLoadWithError:) — 要求を処理できませんでした。代理オブジェクトはエラーメッセージを受信します。非デリゲートの send(request:onFailure:onSuccess:) メソッドでは、onFailure クロージャでこのエラーを検出します。
  • requestDidCancelLoad(_:) — システム管理者による操作、ネットワーク障害、他の予期しないイベントなど、外部要因により要求がキャンセルされました。代理オブジェクトは戻り値を受信しません。非デリゲートの send(request:onFailure:onSuccess:) メソッドでは、onFailure クロージャでこの失敗を検出します。
  • requestDidTimeout(_:) — Salesforce サーバが時間内に応答しませんでした。代理オブジェクトは戻り値を受信しません。非デリゲートの send(request:onFailure:onSuccess:) メソッドでは、onFailure クロージャでこの失敗を検出します。

Mobile SDK は成功応答を request(_:didLoadResponse:) コールバックに配信します。ネットワーク応答の復号化方法についての心配はもう不要です。デフォルトで、Mobile SDK は応答を辞書オブジェクト内の読みやすい JSON 形式にします。その辞書には、「レコード」キーが含まれます。このキーの値が、Salesforce レコードの配列になります。エラー、キャンセル、タイムアウトの条件はそれぞれ独自のハンドラで処理されるため、失敗の種類に基づいて特定のアクションを簡単に実装できます。

これで、ひととおり終わりました。ここでは、アプリケーションを初期化し、ユーザをログインし、REST 要求を発行して、REST 応答を表示しました。現在、アプリケーションは他に何をすればよいかわからないため、停止しています。次は、左スワイプによる削除のようなユーザ操作のサポートを追加して、アプリケーションをもう少し堅牢にしましょう。