次の方法で共有


C++

C++ の開発者に RESTful サービスを

Sridhar Poduri

コード サンプルのダウンロード

今回は、OAuth をサポートする標準の C++ クラスと C++ REST SDK を使って、ファイルを Dropbox にアップロードするシンプルな Windows ベースのクライアント アプリを作成する方法を紹介します。

接続型デバイスの環境では、ネイティブ アプリや Web アプリ、さらにはクラウドベースのサービスとクラウドベースでないサービスが混在して接続してくる Web サイトなど、異種混在環境になる傾向がますます強まっています。これらのアプリは、このように多種多様なデバイスやサービスのデータを共有および使用して、充実した没入型のエクスペリエンスをエンド ユーザーに提供します。アプリを利用するエンド ユーザーは、個人のデバイス (スマートフォン、タブレット、PC など) にアプリをインストールすることが増えています。開発者の仕事は、このようなアプリにデータの共有、整理、および表示を容易にする (そしてユーザーが満足する) シームレスなエクスペリエンスを構築することです。

アプリは、さまざまなプログラミング言語で記述されます。PHP、C#、Java といった一部の言語は、既定で Web に対応しており、データの共有と使用に関連する一般的なシナリオのニーズを満たします。ニーズを満たさない場合は、専用のライブラリを利用してサーバー側でコンピューティング、処理、および分析を実行し、クライアント アプリに応答を返します。

Herb Sutter は論文「Welcome to the Jungle」(ジャングルへようこそ、bit.ly/uhfrzH、英語) の中で、メインストリームから柔軟性のある分散コンピューティングへの移行は、マルチコア コンピューティングや異種コンピューティングをメインストリームに押し上げたのと同じ拡張性やパフォーマンスに関する傾向の自然な進化であると明確に記しています。

設計上、複数のプラットフォームによるコードの共有とパフォーマンスを考慮するときは、プログラミング言語として C++ が好まれます。しかしクラウド コンピューティングになると、C++ に本来備わっている力を完全に発揮できないようです。このようにあたかも機能不全のように言われる主な理由の 1 つは、C++ の開発者が既存の C コードや C++ コードをクラウド環境にシームレスに統合できる、クロスプラットフォーム対応でパフォーマンスが高く、効率的でスケーラビリティのあるライブラリがないことにあります。

C++ REST SDK (bit.ly/VI67I5、英語) は、ネイティブ コードをクラウド環境に移行できるようにするためにマイクロソフトが踏み出した最初の 1 歩で、このような移行に関する日常の問題を解決するツールや API を開発者に提供することが目的です。最初のリリースは、REST サービスにアクセスするためのクライアント側のクロスプラットフォーム ライブラリです。目標は、C++ REST SDK を真のクロスプラットフォーム ライブラリにすることで、クラウドにおけるネイティブ コードの真の可能性を解き放つことです。C++ REST SDK は、より専門性の高いライブラリ (Windows Azure サービス作成をサポートするライブラリなど) を作成する基盤になります。また、この SDK によって、クラウドベースの仮想マシン (VM) に追加のフレームワークやランタイムを展開しなくても、移植可能な C++ で軽量かつ高パフォーマンスな Web サービスを記述できるようになります。

C++ REST SDK を選ぶ理由

REST サービスにアクセスする場合、C++ 開発者は、Windows での C スタイルの API (WinINet や WinHTTP など) や他のプラットフォームでの同様の API の抽象化を行うことができます。このような選択肢を踏まえると、即答を求められる 1 つの疑問が生まれます。なぜ開発者は C++ REST SDK を選ぶべきなのでしょう。

C++ REST SDK は、土台から最新の C++ を使用して設計および記述されており、次のような機能があります。

  • HTTP、JSON、XML、URI などに対する非同期バインドを指定することで、Windows Vista、Windows 7、Windows 8、Windows ストア アプリ、および Linux のネイティブ コードから REST ベース サービスにアクセスできる。
  • Windows ストア アプリで SDK を使用できるようにする Visual Studio 拡張機能 SDK。
  • C++11 の標準機能を基盤として非同期操作を構成するための一貫性のある強力なプログラミング モデル。
  • ファイル/デバイスのストリームに対する読み取りと書き込みに使用可能な非同期ストリームとストリーム バッファーの実装。

C++ REST クライアント クラス

C++ REST は、最新の C++ と非同期プログラミングのパターンを使用することを前提に構築されています。Dropbox を使用した今回の実験では、http_client クラス、Task クラス、および非同期ストリーム クラスを使用しています。ここではこの 3 つのクラスそれぞれについて説明します。

http_client クラス: web::http 名前空間の http_client クラスは名前が示すとおり、HTTP Web サービスへの接続をセットアップおよび維持するために使用します。http_client のインスタンスとサービス エンドポイントへの URI を作成すれば、オブジェクト インスタンスを使用してクライアントの代わりに要求を作成できます。非同期処理が組み込まれている C++ REST ライブラリは、応答をタスクとして返します。

Task クラス: タスクとはやがて完了する可能性のある 1 つの操作を表します。ただし、そのタスクを作成する関数からは既に戻っています。タスクはすべて完了するまで実行されるとは限らず、完了する順序も保証されません。各 Task オブジェクトには、ブール値を返すメンバー関数 is_done があります。タスクが完了するまで実行されると is_done によって true が返され、それ以外の場合は false が返されます。タスクの実行が完了 (is_done メンバー関数が返すブール値により示される) したら、タスクに対して get 関数を呼び出してタスクから値を取得します。is_done 関数で false が返されるときは、get 関数を呼び出さないよう注意してください。このような状態で get 関数を呼び出すとスレッドがブロックされ、コードで非同期パターンを構築するという目的全体が台無しになります。

is_done を絶えず確認するよりも、then 関数を使用する方が効率的です。then 関数は、Windows ストア アプリ向け JavaScript 拡張機能の promise と同様、タスクへのハンドラー関数のアタッチを利用するため、Windows ランタイム (WinRT) 非同期操作のプログラミングに使う PPL タスクを使用している開発者には使いやすく感じるでしょう。then 関数に渡すハンドラー関数は T 型または task<T> 型の引数を受け取ります。task<T> 型の引数を使用すると、さらなるメリットが得られます。タスク自体で発生する例外を唯一キャッチできるのは、task<T> 型の引数を使用する場合です。

then 関数のハンドラーはタスクの完了後にのみ呼び出されるため、ハンドラー内部で get 関数を呼び出せば安全であり、スレッドがブロックされません。

非同期ストリーム: C++ REST ライブラリには、ストリームやストリーム バッファーとしてカプセル化されたオブジェクトとの間で読み取りと書き込みを行う一連のヘルパー クラスが含まれています。標準 C++ ライブラリに設定されたパターンと優先順位によると、C++ REST のストリームとバッファーでは、データ入出力の書式設定に関する考慮事項と、基盤となる媒体 (TCP ソケット、ディスク ファイル、またはメモリ バッファー) に対するバイト列やバイトのコレクションの書き込みおよび読み取りに関する考慮事項は区別されます。ストリームは、ある意味、データの読み取りと書き込みに使用する基盤の媒体から切り離されています。C++ REST のストリームと標準 C++ クラスの大きな違いは、読み取りと書き込みの非同期操作がサポートされている点です (標準 C++ クラスはブロック操作です)。C++ REST の他のオブジェクトを使用する設計と同様に、stream クラスの非同期メソッドは値ではなく task<T> を返します。

C++ REST の基礎を学習したところで、次は Dropbox REST API について考えましょう。ここからは、C++ REST を使用して Dropbox REST API にアクセスし、Windows を実行しているローカル コンピューターからユーザーの Dropbox フォルダーにファイルをアップロードする方法について説明します。

Dropbox REST API

Dropbox では、API (bit.ly/ZJLP4o、英語) へのすべての要求を認証するのに OAuth バージョン 1 が使用されるため、すべての要求は SSL 経由で行う必要があります。OAuth をサポートする標準 C++ ライブラリをインターネットで検索すると、OAuth ライブラリの liboauth しか見つかりません。liboauth には OpenSSL (bit.ly/BpfcH、英語) または Mozilla Network Security Services (NSS) (mzl.la/abU77o) のいずれかが必要です。今回は OAuth をサポートする軽量かつクロスプラットフォームのクラスを求めていたため、Dropbox 認証をサポートするクラスを作成することにしました。

興味のある読者は、C++ で Win 32 から Twitter OAuth にアクセスする方法について Brook Miles がすばらしいブログ記事のシリーズ (bit.ly/137Ms6y) を投稿しているので、参照してみてください。今回は彼の基本的な考え方を基盤として作成していますが、Dropbox API を使用するために、C++ REST でサポートされている標準 C++ 型を可能な限り使用してコードをリファクタリングしています。また、Web 要求を実行するのに WinINet や WinHTTP を使用すると、Windows プラットフォームに限定されて C スタイルの API の使用を余儀なくされることから、今回はどちらの使用も想定していません。

それでは、OAuth をサポートする単純な C++ クラスを作成する方法と、Dropbox を呼び出してファイルを Dropbox にアップロードする Win32 アプリを C++ REST を使用して作成する方法について説明します。次回は、Windows ストア アプリから C++ REST を使用して、ファイルを Dropbox にアップロードする方法を紹介する予定です。

Dropbox にアクセスするアプリを作成するには、アプリを Dropbox に登録する必要があります。登録は、Dropbox アプリ コンソール ポータル (bit.ly/R14tjq) で行うことができます。無料の Dropbox アカウントに登録し、アプリ コンソール ポータルにログインして、[Create app] (アプリの作成) をクリックして新しいアプリを作成します。

このプロセスでは、アプリ名、アプリの種類、およびアクセス許可の種類を指定します。今回は名前を「test」と入力し、アプリの種類には Core を選択しました (図 1 参照)。アプリの種類には、他にも Dropbox Chooser (JavaScript 開発者が重宝) と Sync API (iOS と Android の開発者に最適) があります。最後に、アクセス許可の種類を Full Dropbox にします。これは、アクセス許可の種類を "sandbox" App folder にすることで提供される特定のフォルダーに比べて、Dropbox 上のすべてのフォルダーへの読み取り、書き込み、および同期に関する柔軟性がもたらされるためです。

Choices for Creating a Dropbox App
図 1 Dropbox アプリの作成に関する選択肢

[Create app] (アプリの作成) をクリックすると、Dropbox によりアプリが作成され、アクセスに必要な詳細情報 (アプリ キー、アプリ シークレットなど) が提供されます (図 2 参照)。これらの詳細情報は、OAuth を使用する認証要求と承認要求をプログラムから実行するのに必要なため書き留めておきます。

Choosing Dropbox App Details
図 2 Dropbox アプリに関する詳細情報の選択

OAuth 向けクロスプラットフォーム対応のシンプルな C++ クラス

では実際にやってみましょう。前述のとおり、今回は、Windows と Linux の両方で使用できるクロスプラットフォーム対応のクラスを作成します。C++ REST SDK の最新リリースでは、Linux コンピューターから HTTPS 要求を行うことはサポートされません。これは残念でしたが、Linux 向けの完全な HTTPS サポートは近日提供されるようです。今回説明する C++ クラスでは、大きな変更を加えなくても Windows と Linux の両方で機能するようにします。Dropbox に対する OAuth ベースの認証をサポートするには、主に次のような要件を満たす必要があります (すべての要件については、Dropbox サイトを参照してください)。

  • すべての要求を SSL 経由で行う (つまり、HTTP ではなく HTTPS のみを使用する)。
  • OAuth では、HMAC-SHA1 と RSA-SHA1 のいずれかの暗号化を使用して、要求が SSL 経由で実行される場合はプレーンテキストを使用して、要求の URI およびパラメーターに署名することが求められる。

実験の目的から、プレーン テキスト署名のトランスポートを使用して、HTTPS 経由で要求を行うことにします。Windows と Linux の両方で機能する暗号化 API の作成は、複雑で時間のかかる作業であり、詳しい説明が必要になります。

要件を決めたら、次はクラスの作成です。便宜上 Authentication という名前空間を高いレベルで宣言し、その名前空間のクラスを oAuth という名前で宣言しました。その名前空間のレベルには、URI エンド ポイント用に宣言するいくつかの定数文字列、アプリの登録プロセスで提供されたアプリ キーとアプリ シークレット、およびいくつかのヘルパー メソッドがあります (図 3 参照)。

図 3 OAuth クラスの作成

// Dropbox consumer key and secret
const std::wstring consumerKey = L"Your app key";
const std::wstring consumerSecret = L"Your app secret";
// List of Dropbox authenticate, authorize, request and file upload URIs
const std::wstring DropBoxRequestTokenURI =
  L"https://api.dropbox.com/1/oauth/request_token";
const std::wstring DropBoxAuthorizeURI =
  L"https://www.dropbox.com/1/oauth/authorize";
const std::wstring DropBoxAccessTokenURI =
  L"https://api.dropbox.com/1/oauth/access_token";
const std::wstring DropBoxFileUploadURI =
  L"https://api-content.dropbox.com/1/files_put/dropbox/<your file name here>";
const std::wstring LocalFiletoUpload = L"Your local file goes here";

OAuth プロトコルのサポートは、すべて oAuth クラスの BuildSignedOAuthParameters メソッドに実装します。このメソッドは、エンドポイント URI、HTTP メソッドの種類 (GET、POST、PUT など)、アプリ キー、アプリ シークレット、要求トークン、およびトークン シークレットを受け取り、各要求と共に Dropbox に送信する署名を作成します。Dropbox は、HTTPS 要求によって渡されたパラメーターを使用して Dropbox 側で正確な署名を作成し、照合します。署名が一致しなければ、HTTP エラー コードを返します。

署名は、要求のタイム スタンプ、サポート対象の OAuth プロトコルのバージョン、署名の種類を含む乱数 (OAuth 用語では nonce) を使用して作成されます。メソッドでは、名前順に並べ替えられたすべての必須パラメーターのリストを、エンコードされた署名 URL と一緒に返します (図 4 参照)。

図 4 署名の作成

HTTPParameters BuildSignedOAuthParameters( 
  const HTTPParameters& requestParameters,
  const std::wstring& url,
  const std::wstring& httpMethod,
  const HTTPParameters* postParameters,
  const std::wstring& consumerKey,
  const std::wstring& consumerSecret,
  const std::wstring& requestToken = L"",
  const std::wstring& requestTokenSecret = L""
  )
{
  std::wstring timestamp = OAuthCreateTimestamp();
  std::wstring nonce = OAuthCreateNonce();          

  m_oauthParameters[L"oauth_timestamp"] = timestamp;
  m_oauthParameters[L"oauth_nonce"] = nonce;
  m_oauthParameters[L"oauth_version"] = L"1.0";
  m_oauthParameters[L"oauth_signature_method"] = L"PLAINTEXT";
  m_oauthParameters[L"oauth_consumer_key"] = consumerKey;

  // Add the request token if found
  if (!requestToken.empty())
  {
    m_oauthParameters[L"oauth_token"] = requestToken;
  }

            
  // Create a parameter list containing both oauth and original
  // parameters; this will be used to create the parameter signature
  HTTPParameters allParameters = requestParameters;
  if(Compare(httpMethod, L"POST", false) && postParameters)
  {
    allParameters.insert(postParameters->begin(), 
      postParameters->end());
  }
  allParameters.insert(m_oauthParameters.begin(), 
    m_oauthParameters.end());

  // Prepare a signature base, a carefully formatted string containing 
  // all of the necessary information needed to generate a valid signature
  std::wstring normalUrl = OAuthNormalizeUrl(url);
  std::wstring normalizedParameters = 
    OAuthNormalizeRequestParameters(allParameters);

  std::wstring signatureBase = 
    OAuthConcatenateRequestElements(httpMethod, 
    normalUrl, 
    normalizedParameters);

  // Obtain a signature and add it to header requestParameters
  std::wstring signature = OAuthCreateSignature(signatureBase, 
    consumerSecret,
    requestTokenSecret);

  m_oauthParameters[L"oauth_signature"] = UrlEncode(signature);

  return m_oauthParameters;
}

OAuth のサポートとは別に、Dropbox 上のファイルにアクセスするクライアント コードを記述し、4 つのメソッドを作成します。

  1. oAuthLoginAsync: アプリ キーとアプリ シークレットを使用して Dropbox にログインします。
  2. AuthorizeDropBoxAccess: Internet Explorer を起動して、Dropbox へのアプリのアクセスを承認します。Windows 固有のメソッドで、Internet Explorer が既定のブラウザーかどうかに関係なく Internet Explorer を起動します。
  3. oAuthAcquireTokenAsync: Dropbox の実際のアクセス トークンを取得する処理を実行します。
  4. UploadFileToDropBoxAsync: ローカル システムから Dropbox クラウド ストレージにファイルをアップロードします。

これらの各操作は、C++ REST クライアント クラスを使用して非常に簡単かつシームレスに行われます。

クライアント コード

さて、最新の C++ を使用して作成した、非同期タスクを含むクライアント コードを C スタイルの API の使用に適合させるにはどうすればよいでしょう。これを調べていきましょう。

WinINet などの C スタイルの API を使用する場合は、アプリを動作させるために次の WinINet API 呼び出しを行う必要があります。

  • HTTP 要求ヘッダーを手動で作成する。
  • InternetCrackUrl を呼び出して REST エンドポイント URL を解決する。
  • InternetOpen を呼び出して、インターネット接続へのハンドルを取得する。通常、このハンドルは HINTERNET インスタンスとして返されます。
  • 有効な HINTERNET ハンドルを取得したら、HINTERNET の別のインスタンスを返す Http­OpenRequest を呼び出す。
  • 次に、ヘッダー情報が HTTP 要求に正常に追加されたかどうかを示すブール値を返す HttpAddRequestHeaders を呼び出す。
  • 配置した適切なエラー処理と共に上記の手順をすべて正常に完了したら、実際に要求を送信する HttpSendRequest を呼び出す。
  • 前の要求に対する応答の受信時に、InternetReadFile を呼び出して応答ストリームを読み取る。

以前のすべての API は、最新 C++ のプログラミング手法 (共有ポインター、ラムダ、組み込みの非同期パターンなど) がサポートされていない C スタイルの API だったことに留意してください。

次に、C++ REST SDK を使用して実際のコードを考えます。Dropbox へのログイン操作を実行する oAuthLoginAsync 関数 (図 5 参照) と、ローカル システムから Dropbox にファイルをアップロードする UploadFileToDropBoxAsync 関数を示します。

図 5 oAuthLoginAsync 関数

HTTPParameters BuildSignedOAuthParameters(
  const HTTPParameters& requestParameters,
  const std::wstring& url,
  const std::wstring& httpMethod,
  const HTTPParameters* postParameters,
  const std::wstring& consumerKey,
  const std::wstring& consumerSecret,
  const std::wstring& requestToken = L"",
  const std::wstring& requestTokenSecret = L""
  )
{
  std::wstring timestamp = OAuthCreateTimestamp();
  std::wstring nonce = OAuthCreateNonce();                                         
  m_oauthParameters[L"oauth_timestamp"] = timestamp;
  m_oauthParameters[L"oauth_nonce"] = nonce;
  m_oauthParameters[L"oauth_version"] = L"1.0";
  m_oauthParameters[L"oauth_signature_method"] = L"PLAINTEXT";
  m_oauthParameters[L"oauth_consumer_key"] = consumerKey;
  // Add the request token if found
  if (!requestToken.empty())
  {
    m_oauthParameters[L"oauth_token"] = requestToken;
  }
  // Create a parameter list containing both oauth and original
  // parameters; this will be used to create the parameter signature
  HTTPParameters allParameters = requestParameters;
  if(Compare(httpMethod, L"POST", false) && postParameters)
  {
    allParameters.insert(postParameters->begin(), 
      postParameters->end());
  }
  allParameters.insert(m_oauthParameters.begin(), 
    m_oauthParameters.end());
  // Prepare a signature base, a carefully formatted string containing
  // all of the necessary information needed to generate a valid signature
  std::wstring normalUrl = OAuthNormalizeUrl(url);
  std::wstring normalizedParameters =
    OAuthNormalizeRequestParameters(allParameters);
  std::wstring signatureBase =
    OAuthConcatenateRequestElements(httpMethod,
    normalUrl,
    normalizedParameters);
  // Obtain a signature and add it to header requestParameters
  std::wstring signature = OAuthCreateSignature(signatureBase,
    consumerSecret,
    requestTokenSecret);
  m_oauthParameters[L"oauth_signature"] = UrlEncode(signature);
  return m_oauthParameters;
}
task<void> oAuthLoginAsync(std::shared_ptr<app_credentials>& creds)
{           
  uri url(DropBoxRequestTokenURI);
  std::shared_ptr<oAuth> oAuthObj = std::make_shared<oAuth>();
  auto signatureParams =
   oAuthObj->CreateOAuthSignedParameters(url.to_string(),
   L"GET",
   NULL,
   consumerKey,
   consumerSecret
   );
  std::wstring sb = oAuthObj->OAuthBuildSignedHeaders(url);
  http_client client(sb);   
  // Make the request and asynchronously process the response
  return client.request(methods::GET)
    .then([&creds](http_response response)
  {                                          
    if(response.status_code() != status_codes::OK)
    {                             
      // Handle error cases ...
      return pplx::task_from_result();
    }
    // Perform actions here reading from the response stream ...
    // in this example, parse the response body and
    // extract the token and token secret
    istream bodyStream = response.body();
    container_buffer<std::string> inStringBuffer;
    return bodyStream.read_to_end(inStringBuffer)
      .then([inStringBuffer, &creds](pplx::task<size_t> previousTask)
    {
      const std::string &text = inStringBuffer.collection();
      // Convert the response text to a wide-character
      // string and then extract the tokens
      std::wstring_convert
        <std::codecvt_utf8_utf16<wchar_t>, wchar_t> utf16conv;
      std::wostringstream ss;
      std::vector<std::wstring> parts;
      ss << utf16conv.from_bytes(text.c_str()) << std::endl;
      Split(ss.str(), parts, '&', false);
      unsigned pos = parts[1].find('=');
      std::wstring token = parts[1].substr(pos + 1, 16);
      pos = parts[0].find('=');
      std::wstring tokenSecret = parts[0].substr(pos + 1);
      creds->set_Token(token);
      creds->set_TokenSecret(tokenSecret);
    });
  });
}

oAuthLoginAsync 関数では、まず、ログイン URI エンドポイントの文字列表記から URI インスタンスを構築します。次に、oAuth クラスのインスタンスを作成し、必要な OAuth 要求パラメーターをすべて含むマップを作成するメンバー関数 CreateOAuthSignedParameters を呼び出します。最後に、OAuthBuildSignedHeaders メンバー関数を呼び出してヘッダーに署名します。ヘッダーへの署名は OAuth 仕様により必須です。これで HTTP 通信が開始されます。必要なのは、http_client のインスタンスを作成して、このインスタンスに署名した要求文字列を渡すことだけです。Dropbox は要求文字列とヘッダー情報を使用し、サーバー側で同じ要求文字列を作成して HTTP 要求の一部として送信した要求文字列と照合します。文字列が一致すると成功のリターン コードを返し、一致しない場合はエラーを返します。

http_client クラスのインスタンスを作成して通信プロセスを開始し、request メンバー関数を呼び出します。HTTP メソッドは GET に指定します。要求メソッドの実行が完了すると、app_credentials クラス インスタンスに格納されているトークンとトークン シークレットの解析と抽出に使用する http_response オブジェクトが返されます。このトークンは、Dropbox に対するこれ以降の API 要求すべてと一緒に送信します。

UploadFileToDropBoxAsync 関数を図 6 に示します。署名した OAuth ヘッダーを作成するまでは、oAuthLoginAsync 関数と同じような手順で処理が進みます。ヘッダー情報を作成したら、ローカル ファイル システムから file_stream オブジェクトにファイルを読み取り、HTTP 要求本文に file_stream オブジェクトを指定するタスクを作成します。これで、http_client クラスのインスタンスを作成し、本文に file_sream コンテンツを含む要求インスタンスを設定して、PUT 要求を発行できます。完了すると、成功したかどうかを解析できる http_response を含むタスクが完成します。実にシンプルです。

図 6 UploadFileToDropBoxAsync 関数

task<void> UploadFileToDropBoxAsync(std::shared_ptr<app_credentials>& creds)
{
  using concurrency::streams::file_stream;
  using concurrency::streams::basic_istream;
  uri url(DropBoxFileUploadURI);
  std::shared_ptr<oAuth> oAuthObj = std::make_shared<oAuth>();
  auto signatureParams =     
    oAuthObj->CreateOAuthSignedParameters(url.to_string(),
    L"PUT",
    NULL,
    consumerKey,
    consumerSecret,
    creds->Token(),
    creds->TokenSecret()
    );
  std::wstring sb = oAuthObj->OAuthBuildSignedHeaders(url);
  return file_stream<unsigned char>::open_istream(LocalFiletoUpload)
    .then([sb, url](pplx::task<basic_istream<unsigned char>> previousTask)
  {
    try
    {
      auto fileStream = previousTask.get();
      // Get the content length, which is used to set the
      // Content-Length property
      fileStream.seek(0, std::ios::end);
      auto length = static_cast<size_t>(fileStream.tell());
      fileStream.seek(0, 0);
      // Make HTTP request with the file stream as the body
      http_request req;                                    
      http_client client(sb);                
      req.set_body(fileStream, length);
      req.set_method(methods::PUT);
      return client.request(req)
        .then([fileStream](pplx::task<http_response> previousTask)
      {
        fileStream.close();
        std::wostringstream ss;
        try
        {
          auto response = previousTask.get();
          auto body = response.body();                  
          ss << L"Server returned returned status code "
            << response.status_code() << L"."
            << std::endl;      
          std::wcout << ss.str();
        }
        catch (const http_exception& e)
        {
          ss << e.what() << std::endl;
             }
        std::wcout << ss.str();
      });
      }                       
      catch (const std::system_error& e)
      {
        std::wostringstream ss;
        ss << e.what() << std::endl;
        std::wcout << ss.str();
        // Return an empty task
        return pplx::task_from_result();
      }
  });
}

Web 通信に C スタイルの API を使用したり、WinINet のようなプラットフォーム固有の API を使用してサポートの作成手順を進めたりするのに比べれば、最新の C++ を使用して記述したコードはより簡潔で、読みやすく、洗練されています。実のところ、レベルの低い実装の詳細は、すべてライブラリのパブリック インターフェイスから取り出したものです。C++ REST SDK は、最新 C++ の promise 上に構築されているため、同じ設計原則が RESTful 通信に適用されます。その結果、最新の C++ を使用する、非常に適切に設計されてパターン化されたライブラリが完成し、接続型アプリの作成プロセスは容易でシームレスになります。

次回: Windows ストア アプリ

今回は、ファイルを Dropbox にアップロードするシンプルな Windows ベースのクライアント アプリを C++ REST SDK を使用して作成する方法を確認しました。また、その過程で、OAuth をサポートする標準 C++ クラスの作成についても説明しました。次回は、C++ REST SDK を使用して Windows ストア アプリを作成する方法について紹介します。お見逃しなく。

Sridhar Poduri は、マイクロソフトの Windows チームでプログラム マネージャーを務めています。C++ を愛好しており、書籍『Modern C++ and Windows Store Apps』(Sridhar Poduri、2013 年) の著者でもある彼は、sridharpoduri.com (英語) で C++ と Windows ランタイムに関するブログ記事を定期的に投稿しています。

この記事のレビューに協力してくれた技術スタッフの Artur Laksberg (マイクロソフト) に心より感謝いたします。
Artur Laksberg は、C++ REST SDK チームのシニア開発責任者です。