しっぽを追いかけて

ぐるぐるしながら考えています

Unity と猫の話題が中心   掲載内容は個人の私見であり、所属組織の見解ではありません

UP by Jawbone のライフログを Windows アプリで取得する(4)

UP by Jawbone のライフログWindows アプリで取得する(3)の続きです

WebView に無理やり?リダイレクトを通して code が取得できたので、ここからアクセストークンを取得します

前回の JawboneService をカスタマイズ!

/// <summary>
/// Jawbone アクセスサービス
/// </summary>
public class JawboneService
{
    /// <summary>
    /// トークン要求 Uri
    /// </summary>
    private static readonly string RequestTokenBaseUri = @"https://jawbone.com/auth/oauth2/auth?response_type=code&client_id={0}&scope={1}&redirect_uri={2}";

    /// <summary>
    /// Client ID
    /// </summary>
    private static readonly string ClientId = @"登録アプリの Client ID";

    /// <summary>
    /// App Secret
    /// </summary>
    private static readonly string AppSecret = @"登録アプリの App Secret";

    /// <summary>
    /// アクセス範囲
    /// </summary>
    private static readonly string Scopes = @"extended_read sleep_read mood_read";

    /// <summary>
    /// リダイレクト Uri(ダミー)
    /// </summary>
    private static readonly string RedirectUri = @"https://localhost:5555";

    /// <summary>
    /// トークン問い合わせ Uri
    /// </summary>
    private static readonly string TokenBaseUri = @"https://jawbone.com/auth/oauth2/token?client_id={0}&client_secret={1}&grant_type={2}&code={3}";

    /// <summary>
    /// API エンドポイント Uri
    /// </summary>
    private static readonly string ApiBaseUri = @"https://jawbone.com/nudge/api/v.1.1/{0}";

    /// <summary>
    /// トークン要求用 Uri を構成する
    /// </summary>
    /// <returns>トークン要求用 Uri</returns>
    public string GetRequestTokenUri()
    {
        return string.Format(RequestTokenBaseUri, Uri.EscapeDataString(ClientId), Uri.EscapeDataString(Scopes), Uri.EscapeDataString(RedirectUri));
    }

    /// <summary>
    /// アクセストークンを取得
    /// </summary>
    /// <param name="redirectUri">リダイレクトされた Uri</param>
    /// <returns>Task</returns>
    public async Task GetToken(string redirectUri)
    {
        try
        {
            var decoder = new WwwFormUrlDecoder(new Uri(redirectUri).GetComponents(UriComponents.Query, UriFormat.Unescaped));

            var request = WebRequest.CreateHttp(string.Format(TokenBaseUri, ClientId, AppSecret, @"authorization_code", decoder.GetFirstValueByName("code")));
            var response = await request.GetResponseAsync() as HttpWebResponse;

            string content = string.Empty;
            if (response.StatusCode != HttpStatusCode.OK)
            {
                throw new InvalidOperationException();
            }
            using (var stream = new StreamReader(response.GetResponseStream()))
            {
                content = await stream.ReadToEndAsync();
                App.AppSettings.Settings.AccessToken = JsonConvert.DeserializeObject<JawboneAccessToken>(content, new JsonSerializerSettings() { Culture = new CultureInfo("ja-jp") });
                await App.AppSettings.SaveAsync();
            }
        }
        catch (Exception ex)
        {
            Debug.WriteLine(ex.ToString());
        }
    }

    /// <summary>
    /// API でデータを取得する
    /// </summary>
    /// <param name="path">エンドポイントパス</param>
    /// <returns>取得データ</returns>
    public async Task<string> GetDataAsync(string path)
    {
        try
        {
            var request = WebRequest.CreateHttp(string.Format(ApiBaseUri, path.Trim('/')));
            var accessToken = App.AppSettings.Settings.AccessToken;
            request.Headers["Authorization"] = string.Format("{0} {1}", accessToken.TokenType, accessToken.Token);

            var response = await request.GetResponseAsync() as HttpWebResponse;

            string content = string.Empty;
            if (response.StatusCode != HttpStatusCode.OK)
            {
                throw new InvalidOperationException();
            }
            using (var stream = new StreamReader(response.GetResponseStream()))
            {
                content = await stream.ReadToEndAsync();
            }
            return content;
        }
        catch (Exception ex)
        {
            Debug.WriteLine(ex.ToString());
        }

        return string.Empty;
    }
}

下記の GetToken メソッドでアクセストークンの情報が JSON で取得できます

    /// <summary>
    /// アクセストークンを取得
    /// </summary>
    /// <param name="redirectUri">リダイレクトされた Uri</param>
    /// <returns>Task</returns>
    public async Task GetToken(string redirectUri)
    {
        try
        {
            var decoder = new WwwFormUrlDecoder(new Uri(redirectUri).GetComponents(UriComponents.Query, UriFormat.Unescaped));

            var request = WebRequest.CreateHttp(string.Format(TokenBaseUri, ClientId, AppSecret, @"authorization_code", decoder.GetFirstValueByName("code")));
            var response = await request.GetResponseAsync() as HttpWebResponse;

            string content = string.Empty;
            if (response.StatusCode != HttpStatusCode.OK)
            {
                throw new InvalidOperationException();
            }
            using (var stream = new StreamReader(response.GetResponseStream()))
            {
                content = await stream.ReadToEndAsync();
                App.AppSettings.Settings.AccessToken = JsonConvert.DeserializeObject<JawboneAccessToken>(content, new JsonSerializerSettings() { Culture = new CultureInfo("ja-jp") });
                await App.AppSettings.SaveAsync();
            }
        }
        catch (Exception ex)
        {
            Debug.WriteLine(ex.ToString());
        }
    }

JSONaccess_token、token_type、expires_in、refresh_token のプロパティが含まれるので、このプロパティに合わせた JsonProperty 属を付与した Model クラスに JSON.NET でデシリアライズしています

    /// <summary>
    /// API でデータを取得する
    /// </summary>
    /// <param name="path">エンドポイントパス</param>
    /// <returns>取得データ</returns>
    public async Task<string> GetDataAsync(string path)
    {
        try
        {
            var request = WebRequest.CreateHttp(string.Format(ApiBaseUri, path.Trim('/')));
            var accessToken = App.AppSettings.Settings.AccessToken;
            request.Headers["Authorization"] = string.Format("{0} {1}", accessToken.TokenType, accessToken.Token);

            var response = await request.GetResponseAsync() as HttpWebResponse;

            string content = string.Empty;
            if (response.StatusCode != HttpStatusCode.OK)
            {
                throw new InvalidOperationException();
            }
            using (var stream = new StreamReader(response.GetResponseStream()))
            {
                content = await stream.ReadToEndAsync();
            }
            return content;
        }
        catch (Exception ex)
        {
            Debug.WriteLine(ex.ToString());
        }

        return string.Empty;
    }

あとはこんな感じで各 API のエンドポイントに向けて、「Authorization」HTTP ヘッダを付与したリクエストを送るだけ!

試しに https://jawbone.com/nudge/api/v.1.1/users/settings にアクセスしてみるとこんな JSON が返ってきました

{
  "meta": {
    "user_xid": "zXsLRB653S6dHUwObgQ9QA",
    "message": "OK",
    "code": 200,
    "time": 1402576212},
    "data": {
      "metric": 1,
      "xid": "zXsLRB653S6dHUwObgQ9QA",
      "share_sleep": true,
      "share_mood": true
  }
}

リダイレクトさえ解決すればライフログ取得も簡単ですね!