例外処理

Thing-IF SDK の API には、呼び出しによって例外が発生するものがあります。ここでは、例外への対処処理の詳細について示します。

サンプルコードでの記載

本ガイドのサンプルコードでは、エラーハンドリングの必要箇所のみを示し、詳細(メッセージの出力やエラーからの回復処理など)は省略しています。また、例外は Java の基本的な例外処理の構文に合わせて trycatch を使って記述しています。

たとえば、コマンド送信の解説では、次のようなサンプルコードを扱っています。

try {
  Command command = api.postNewCommand("AirConditioner-Demo", 1, actions);
} catch (ThingIFException e) {
  // Handle the error.
}

モバイルアプリの実装に、JDeferred を使用する場合、例外処理は Promise の fail() メソッドに例外処理のハンドラーを渡すことで実現します。

例外処理では、例外オブジェクトの型を確認後、目的の型にダウンキャストすることで、例外の詳細情報を取得できます。

mAdm.when(executeApi1()
).fail(new FailCallback<Throwable>() {
  @Override
  public void onFail(final Throwable tr) {
    if (tr instanceof ForbiddenException) {
      // The token was invalid.
    } else if (tr instanceof ThingIFRestException) {
      // An error occurred in Thing Interaction Framework.
      ThingIFRestException restException = (ThingIFRestException)tr;
      Log.i(TAG, "HTTP Status:" + restException.getStatusCode());
    } else if (tr instanceof ThingIFException) {
      // An error occurred in the Thing-IF SDK.
    }
  }
});

例外の型

Thing-IF SDK を利用する際は、ThingIFException クラス、または、そのサブクラスによって例外の情報を取得します。ThingIFException は Thing-IF SDK で扱う例外クラスのルート階層に位置するクラスです。

Thing-IF SDK が扱う例外クラスには以下のものがあります。

Thing-IF SDK では、com.kii.thingif.exception パッケージの例外クラスを使用します。このうちのいくつかは、Kii Cloud SDK の com.kii.cloud.storage.exception.app パッケージなどに同名のクラスが存在するため、API を併用する際にご注意ください。

REST API の実行エラー

API の呼び出しにより、Thing Interaction Framework の REST API がエラーを返すと、ThingIFRestException クラス、または、そのサブクラスで例外が通知されます。

Thing-IF SDK では、REST API が返した HTTP のステータスコードに応じて、以下の例外を返します。REST API が返す HTTP のステータスコードは Thing-IF REST API ドキュメント を参照してください。

HTTP ステータス 例外の型
400 BadRequestException
401 UnauthorizedException
403 ForbiddenException
404 NotFoundException
409 ConflictException
500 InternalServerErrorException
503 ServiceUnavailableException
504 GatewayTimeoutException
それ以外 ThingIFRestException

入力された文字列の長さや文字種などはアプリ側で事前チェックしたものを API に渡す必要があります。通常、パラメータエラーなどはクライアント SDK でチェックされ、問題がある場合は java.lang.IllegalArgumentException などの RuntimeException 系の例外によって通知されます。特に、サンプルコードのとおり、ThingIFException クラスの trycatch で実装する場合、入力パラメータをアプリ側で事前にチェックしておかないと、RuntimeException がキャッチされず、モバイルアプリが異常終了することになるため、ご注意ください。

各 API において送出される例外やエラーコードのすべてを事前に定義しておくことは困難です。ユーザーの重複や通信エラーのように対処したい例外のみ特別に扱い、それ以外は一般的なエラーとして扱うことをおすすめします。例外やエラーコードは、SDK やサーバーのバージョンアップによって追加、変更されることがあります。

なお、オーナーのアクセストークンを取得する処理などでは、Kii Cloud SDK の API を使用します。これらの API で発生する例外の処理方法は、Kii Cloud SDK の 例外処理と調査方法 を参照してください。

詳細情報の取得

API の実行に伴って REST API がエラーを返した場合、その詳細情報を取得できる場合があります。詳細情報は、特に開発時において問題の原因を特定する作業に役立ちます。

ここでは、エラーのうち、REST API の実行に伴うエラーからの詳細情報の取得方法について説明します。

REST API の実行に伴うエラーは、ThingIFRestException クラス、または、そのサブクラスで受け取ることができます。

詳細情報の例

たとえば、コマンドを送信する直前にオーナーユーザーの 無効化 を行うと、アクセストークンが無効になってコマンドの送信に失敗します。この際、エラー情報は次のように取得できます。

try {
  Command command = api.postNewCommand("AirConditioner-Demo", 1, actions);
} catch (ThingIFRestException e) {
  System.out.println("-- class");
  System.out.println(e.getClass());
  System.out.println("-- getStatusCode()");
  System.out.println(e.getStatusCode());
  System.out.println("-- getErrorCode()");
  System.out.println(e.getErrorCode());
  System.out.println("-- getMessage()");
  System.out.println(e.getMessage());
} catch (ThingIFException e) {
  // Handle the error.
}
-- class
class com.kii.thingif.exception.ForbiddenException
-- getStatusCode()
403
-- getErrorCode()
WRONG_TOKEN
-- getMessage()
curl -v -X POST -H 'Content-Type:application/json' -H 'X-Kii-SDK:sn=at;sv=0.11.0;pv=23' -H 'X-Kii-AppID:11111111' -H 'X-Kii-AppKey:22222222222222222222222222222222' -H 'Authorization:Bearer AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' 'https://api-jp.kii.com/thing-if/apps/11111111/targets/thing:th.0123456789ab-cdef-0123-4567-89abcdef/commands' -d '{"actions":[{"turnPower":{"power":true}}],"issuer":"user:abcdef012345-6789-abcd-ef01-23456789","schema":"AirConditioner-Dema","schemaVersion":1}'    ## Server Returned HttpStatus:403        The provided token is not valid

この例は無効なアクセストークンを使用した場合の実行結果です。記載されているすべての例外情報はすべての状況で常に取得できるとは限らないため、プログラムから利用する場合は null 等の応答も想定してください。

  • getStatusCode() メソッド

    REST API が返した HTTP のステータスコードを返します。

  • getErrorCode() メソッド

    エラーの原因を示す文字列を返します。モバイルアプリのプログラムで、エラーの内容ごとに処理を振り分けたい場合などに使用できます。

    REST API が返した詳細情報のうち、errorCode フィールドの文字列に対応します。

  • getMessage() メソッド

    デバッグ用の詳細情報を返します。

    詳細情報はエラーの内容に依存しますが、エラーを再現する際に参考にできる curl コマンドのサンプルや、REST API のデバッグ用メッセージ(message フィールドの文字列)が含まれます。

サポートに問い合わせを行う際には、これらの情報も提示することをおすすめします。

負荷集中時のエラー

サーバーに対して、一定時間内に通常の負荷を大きく超えるアクセスが発生した場合、そのアプリケーションでは API がエラーを返します。この制限値は、利用契約に基づいてアプリケーションごとに定められます。

この制限値には余裕があるため、通常の運用負荷の変動では問題なく動作する設計ですが、例えば特定の時刻にアクティブユーザーが一斉にリクエストを行うような機能はエラーの発生につながります。

上限に達した場合、各 API は ThingIFRestException クラス(ThingIFException のサブクラス)でエラーを返します。この際、getStatusCode() メソッドは 429 を、getErrorCode() メソッドと getMessage() メソッドはそれぞれ null を返します。

通常、モバイルアプリでは、このエラーをサーバーでの想定外エラーとして処理できますが、輻輳を防止するため、API の再試行は避けるように実装してください。