RESTful Web サービスの使用

Web サービスをアプリケーションに統合することは、一般的なシナリオの 1 つです。 この記事では、Xamarin.Forms アプリケーションから RESTful Web サービスを使用する方法について説明します。

Representational State Transfer (REST) は、Web サービスをビルドするためのアーキテクチャ スタイルです。 REST 要求は、Web ブラウザーが Web ページの取得やサーバーへのデータの送信に使用するのと同じ HTTP 動詞を使用して HTTP 経由で実行されます。 次の動詞があります。

  • GET – この操作は、Web サービスからデータを取得するために使用されます。
  • POST – この操作は、Web サービスに新しいデータ項目を作成するために使用されます。
  • PUT – この操作は、Web サービスのデータ項目を更新するために使用されます。
  • PATCH – この操作は、項目の変更方法に関する一連の命令を記述することにより、Web サービスのデータ項目を更新するために使用されます。 この動詞は、サンプル アプリケーションでは使用されていません。
  • DELETE – この操作は、Web サービスのデータ項目を削除するために使用されます。

REST に準拠する Web サービス API は RESTful API と呼ばれ、次のものを使用して定義されます。

  • ベース URI。
  • GET、POST、PUT、PATCH、DELETE などの HTTP メソッド。
  • JavaScript Object Notation (JSON) などの、データのメディアの種類。

RESTful Web サービスにより、通常は JSON メッセージを使用してクライアントにデータが返されます。 JSON は、データの送受信時に帯域幅要件を減らせる、コンパクトなペイロードを生成するテキスト ベースのデータ交換形式です。 サンプル アプリケーションでは、オープンソース NewtonSoft JSON.NET ライブラリを使用してメッセージをシリアル化/逆シリアル化します。

REST は、そのシンプルさもあって、モバイル アプリケーションで Web サービスにアクセスするための主要な方法となっています。

サンプル アプリケーションが実行されると、次のスクリーンショットに示すように、ローカルでホストされている REST サービスに接続されます。

サンプル アプリケーション

Note

iOS 9 以降では、App Transport Security (ATS) により、インターネット リソース (アプリのバックエンド サーバーなど) とアプリの間にセキュリティで保護された接続が適用されるため、機密情報の漏洩が防止されます。 iOS 9 用に構築されたアプリ内では ATS が既定で有効なため、すべての接続が ATS セキュリティ要件の対象となります。 接続がこれらの要件を満たさない場合は、例外を伴って失敗します。

HTTPS プロトコルを使用してインターネット リソースの通信をセキュリティで保護できない場合は、ATS をオプトアウトできます。 これは、アプリの Info.plist ファイルを更新することで実現できます。 詳細については、アプリ トランスポート セキュリティに関する記事を参照してください。

Web サービスを使用する

REST サービスは、ASP.NET Core を使用して記述され、次の操作を提供します。

操作 HTTP メソッド 相対 URI パラメーター
To Do アイテムのリストの取得 GET /api/todoitems/
新しい To Do 項目を作成する 投稿 /api/todoitems/ JSON 形式の ToDo 項目
To Do アイテムの更新 PUT /api/todoitems/ JSON 形式の ToDo 項目
To Do アイテムの削除 DELETE /api/todoitems/{id}

URI の大半には、パスに TodoItem ID が含まれています。 たとえば、ID が 6bb8a868-dba1-4f1a-93b7-24ebce87e243TodoItem を削除するために、クライアントは DELETE 要求を http://hostname/api/todoitems/6bb8a868-dba1-4f1a-93b7-24ebce87e243 に送信します。 サンプル アプリケーションで使われるデータ モデルの詳細については、データのモデリングに関する記事を参照してください。

要求を受信すると Web API フレームワークは、要求をアクションにルーティングします。 これらのアクションは、TodoItemsController クラスの単なるパブリック メソッドです。 フレームワークは、ルーティング ミドルウェアを使って、受信した要求の URL を照合し、アクションにマップします。 REST API では、属性ルーティングを使用して、HTTP 動詞でその操作が表されるリソースのセットとしてアプリの機能をモデル化する必要があります。 属性ルーティングでは、属性のセットを使ってアクションをルート テンプレートに直接マップします。 属性ルーティングの詳細については、「Attribute routing for REST APIs」をご覧ください。 ASP.NET Core を使用した REST サービスの構築の詳細については、「ネイティブ モバイル アプリケーションのバックエンド サービスの作成」を参照してください。

HttpClient クラスは、HTTP 経由で要求を送受信するために使用されます。 これは、HTTP 要求を送信し、URI で識別されたリソースから HTTP 応答を受信するための機能を提供します。 これらの各要求は、非同期操作として送信されます。 非同期操作の詳細については、「非同期サポートの概要」を参照してください。

HttpResponseMessage クラスは、HTTP 要求が行われた後に Web サービスから受信した HTTP 応答メッセージを表します。 これには、状態コード、ヘッダー、本文など、応答に関する情報が含まれます。 HttpContent クラスは、HTTP 本文とコンテンツ ヘッダー (Content-TypeContent-Encoding など) を表します。 コンテンツは、データの形式に応じて、ReadAsStringAsyncReadAsByteArrayAsync などの ReadAs メソッドのどれかを使用して読み取ることができます。

HTTPClient オブジェクトを作成する

次のコード例に示すように、HttpClient インスタンスはクラスレベルで宣言されているため、アプリケーションが HTTP 要求を行う必要がある限り、オブジェクトは存続します。

public class RestService : IRestService
{
  HttpClient client;
  ...

  public RestService ()
  {
    client = new HttpClient ();
    ...
  }
  ...
}

データを取得する

次のコード例に示すように、HttpClient.GetAsync メソッドは、URI で指定された Web サービスに GET 要求を送信した後、Web サービスから応答を受信するために使用されます。

public async Task<List<TodoItem>> RefreshDataAsync ()
{
  ...
  Uri uri = new Uri (string.Format (Constants.TodoItemsUrl, string.Empty));
  ...
  HttpResponseMessage response = await client.GetAsync (uri);
  if (response.IsSuccessStatusCode)
  {
      string content = await response.Content.ReadAsStringAsync ();
      Items = JsonSerializer.Deserialize<List<TodoItem>>(content, serializerOptions);
  }
  ...
}

REST サービスは、HTTP 要求が成功したか失敗したかを示すために、HttpResponseMessage.IsSuccessStatusCode プロパティで HTTP 状態コードを送信します。 この操作では、REST サービスは応答に HTTP 状態コード 200 (OK) を送信します。これは、要求が成功し、要求された情報が応答にあることを示します。

HTTP 操作が成功した場合、応答の内容が読み取られます (表示用)。 この HttpResponseMessage.Content プロパティは HTTP 応答の内容を表し、HttpContent.ReadAsStringAsync メソッドは HTTP コンテンツを文字列に非同期的に書き込みます。 その後、このコンテンツは JSON から TodoItem インスタンスの List に逆シリアル化されます。

警告

ReadAsStringAsync メソッドを使用して大きな応答を取得すると、パフォーマンスに悪影響を及ぼす可能性があります。 このような状況では、応答を完全にバッファー処理しないように、応答を直接逆シリアル化する必要があります。

データの作成

次のコード例に示すように、HttpClient.PostAsync メソッドは、URI で指定された Web サービスに POST 要求を送信した後、Web サービスから応答を受信するために使用されます。

public async Task SaveTodoItemAsync (TodoItem item, bool isNewItem = false)
{
  Uri uri = new Uri (string.Format (Constants.TodoItemsUrl, string.Empty));

  ...
  string json = JsonSerializer.Serialize<TodoItem>(item, serializerOptions);
  StringContent content = new StringContent (json, Encoding.UTF8, "application/json");

  HttpResponseMessage response = null;
  if (isNewItem)
  {
    response = await client.PostAsync (uri, content);
  }
  ...

  if (response.IsSuccessStatusCode)
  {
    Debug.WriteLine (@"\tTodoItem successfully saved.");
  }
  ...
}

TodoItem インスタンスは、Web サービスに送信するために JSON ペイロードにシリアル化されます。 このペイロードは、PostAsync メソッドで要求が行われる前に Web サービスに送信される HTTP コンテンツの本文に埋め込まれます。

REST サービスは、HTTP 要求が成功したか失敗したかを示すために、HttpResponseMessage.IsSuccessStatusCode プロパティで HTTP 状態コードを送信します。 この操作の一般的な応答は、次のとおりです。

  • 201 (CREATED): 応答が送信される前に、要求によって新しいリソースが作成されたことを示します。
  • 400 (BAD REQUEST): 要求はサーバーによって認識されません。
  • 409 (CONFLICT): サーバー上の競合のために要求を実行できないことを示します。

データの更新

次のコード例に示すように、HttpClient.PutAsync メソッドは、URI で指定された Web サービスに PUT 要求を送信した後、Web サービスから応答を受信するために使用されます。

public async Task SaveTodoItemAsync (TodoItem item, bool isNewItem = false)
{
  ...
  response = await client.PutAsync (uri, content);
  ...
}

PutAsync メソッドの操作は、Web サービスでデータを作成するために使用される PostAsync メソッドと同じです。 ただし、Web サービスから送信される可能性のある応答は異なります。

REST サービスは、HTTP 要求が成功したか失敗したかを示すために、HttpResponseMessage.IsSuccessStatusCode プロパティで HTTP 状態コードを送信します。 この操作の一般的な応答は、次のとおりです。

  • 204 (NO CONTENT): 要求が正常に処理され、応答が意図的に空白になっていることを示します。
  • 400 (BAD REQUEST): 要求はサーバーによって認識されません。
  • 404 (NOT FOUND): 要求されたリソースはサーバーに存在しないことを示します。

データの削除

次のコード例に示すように、HttpClient.DeleteAsync メソッドは、URI で指定された Web サービスに DELETE 要求を送信した後、Web サービスから応答を受信するために使用されます。

public async Task DeleteTodoItemAsync (string id)
{
  Uri uri = new Uri (string.Format (Constants.TodoItemsUrl, id));
  ...
  HttpResponseMessage response = await client.DeleteAsync (uri);
  if (response.IsSuccessStatusCode)
  {
    Debug.WriteLine (@"\tTodoItem successfully deleted.");
  }
  ...
}

REST サービスは、HTTP 要求が成功したか失敗したかを示すために、HttpResponseMessage.IsSuccessStatusCode プロパティで HTTP 状態コードを送信します。 この操作の一般的な応答は、次のとおりです。

  • 204 (NO CONTENT): 要求が正常に処理され、応答が意図的に空白になっていることを示します。
  • 400 (BAD REQUEST): 要求はサーバーによって認識されません。
  • 404 (NOT FOUND): 要求されたリソースはサーバーに存在しないことを示します。

ローカル開発

ASP.NET Core Web API などのフレームワークを使用して REST Web サービスをローカルで開発している場合は、Web サービスとモバイル アプリを同時にデバッグできます。 このシナリオでは、iOS シミュレーターと Android エミュレーターのクリアテキスト HTTP トラフィックを有効にする必要があります。 通信を許可するようにプロジェクトを構成する方法については、「ローカル Web サービスに接続する」を参照してください。