Help us understand the problem. What is going on with this article?

StravaのAPIにアクセスしてアカウント情報を取得する

はじめに

StravaにAPIがある!でも日本語ドキュメントがない!わかりづらい!
という状況に陥り、自分が割と苦労したので、アスリートエンジニアのために記録を残したいと思います。
みんなで運動して健康な体でコーディングしよう!!

Stravaとは

アスリート向けのSNSです。
ランニングや自転車、水泳など様々なアクティビティを記録することができます。
APIが提供されており、このAPIを使うことでアスリート情報や登録してある自転車やシューズの情報を取得できます。
https://developers.strava.com/
(自分が少し前に見たときより大分わかりやすくなってる...)

この記事の内容

Stravaにアプリを登録し、HTTPリクエストを投げて自転車の情報を取得するまでを記載しています。
GET?POST?なにそれ?っていう状態から作ったので、初心者の方でもわかりやすい内容になっているかと思います。

開発環境

特に今回は開発環境に依存しないかとは思いますが一応記載しておきます。
OS:mac OS HighSierra
Eclipse4.8
Tomcat 9.0.26
JDK 1.8.0

Stravaにアプリを登録

以下のURLにアクセスすると自分のアプリを登録することができます。
https://www.strava.com/settings/api

Stravaを起動し、設定画面へ行くと設定画面の一番下に[My APIアプリケーション]という項目があります。
この時点では別にアプリが出来ていなくても大丈夫なので、適当に登録しちゃいましょう。
ウェブサイトのURLや、認証コールバックドメインなどもとりあえずはなんでもOKです。

localohost(自分自身を表すIP)を指定しておこうと思ったのですがなぜか弾かれたので、127.0.0.1としておきます。
(localhostと127.0.0.1はほぼイコールなイメージです。厳密には違うかもしれないですが。)
:8080はtomcat使ってアプリ作るつもりだったのでついてます。(8080はtomcatで利用するポート番号です。)
スクリーンショット 2019-09-22 21.42.37.png

そしてアイコンも適当に登録するとクライアントIDや、クライアントシートなどの値が与えられます。
スクリーンショット 2019-09-22 21.49.00.png

WebAPIにアクセス

作業としては大きく分けて2つです
・WebAPIを叩くために必要となるアクセストークンを取得します。
・その次にそのトークンを利用してWebAPIにアクセスし、情報を取得します。

アクセストークンの取得

StravaではOauth2.0という仕組みを導入しています。
Oauthに関しては以下のQiitaの記事がめちゃめちゃわかりやすかったので、こちらを参照ください。
https://qiita.com/TakahikoKawasaki/items/e37caf50776e00e733be

以下の公式ドキュメントに沿ってやっていきます。
https://developers.strava.com/docs/authentication/

トークンを取得するためには以下のURLにヘッダー情報を加えたものをGETメソッドを利用してHTTPリクエストを飛ばします
"https://www.strava.com/oauth/mobile/authorize"

GETメソッドにおいて情報を追加する場合はURLの後ろに追加して行きます。
今回トークンの取得に当たって必要となる情報が次の5つです。
①clientid
先ほどのStravaにアプリを登録した際に表示されていたクライアントIDの値です。

②redirect_uri
このURLでHTTPアクセスしたときにStravaのサイトに飛び認証が行われます。
認証完了後にリダイレクトされる先のURLを与えます。
注意:このリダイレクト先のURLのドメインと、Stravaにアプリを登録した際の認証コールバックドメインに含まれていないとリクエストが失敗します
なので今回であればredirect_uriのドメインも127.0.0.1である必要があります。

③response_type
この値は必ず"code"です。(ならなんで入力させるんだって感じですが。)

④approval_prompt
"force"と"auto"のどちらかを選択します。
forceの場合、毎回認証が行われます。
autoの場合、一度認証が通ればしばらく(?)は自動的に認証が行われます。

⑤scope
ユーザー情報にたいしてアクセスできる範囲を決められます。
"read","read_all","profile:read_all"など様々なものが用意されているので
自分のアプリでやりたいことに適したものを選択しましょう。

例としてヘッダーを加えたURを以下のようなものとします。
https://www.strava.com/oauth/authorize?client_id=****&response_type=code&redirect_uri=http://127.0.0.1:8080/hoge&scope=read&approval_prompt=auto

するとこのような画面が表示されるかと思います。
スクリーンショット 2019-09-22 22.21.22.png

ここで許可を押すと、Stravaのログイン画面に遷移し、ログインすると認証されリダイレクトURL先へと遷移します。
リダイレクトした先のURLに"code="という部分が含まれているかと思います。
hogehoge/state=&code=hogehogehogehoge&scope....
このコードの値を利用するので控えておいてください。

ここで次に以下のURLに対してPOSTメソッドを使ってHTTPリクエストを行います。
https://www.strava.com/oauth/token”

このPOSTメソッドのbodyに必要な情報を与えることで、アクセストークンが取得できます。
bodyに与える情報は以下の5つです。
①clientID
Stravaにアプリを登録したときに与えられたクライアントIDの値

②client_secret
Stravaにアプリを登録したときに与えられたクライアントシートの値
(クライアントシークレットだと思うんだけどな)

③code
先ほどのリダイレクト先のURLに含まれていたcodeの値

④grant_type
必ず"authorization_code"としてください。
POSTメソッドの実装はアプリを実装する環境によって異なるかと思いますが、Javaの場合以下のような形で実装しました。

request_token.java
    URL url = new URL("https://www.strava.com/oauth/token");
    HttpURLConnection con = (HttpURLConnection)url.openConnection();
    con.setRequestMethod("POST");
    con.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
    con.setDoOutput(true);
    con.setDoInput(true);
    con.connect();

    String body = "client_id=****&client_secret=****&code=****&grant_type=authorization_code";
    byte[] postData = body.getBytes(StandardCharsets.UTF_8);
    try(DataOutputStream outputStream = new DataOutputStream(con.getOutputStream())){
        outputStream.write(postData);
    }

そして、このリクエストに対するレスポンスのなかに"access_token"が存在しているので、このトークンを取得します。
サンプルコードとしては以下のような感じですかね。

gettoken.java
    String responseData = "";
    InputStream stream = con.getInputStream();
    StringBuffer sb = new StringBuffer();
    String line = "";
    BufferedReader br = new BufferedReader(new InputStreamReader(stream, "UTF-8"));
    while((line = br.readLine()) != null) {
        sb.append(line);
    }
    try {
        stream.close();
    }catch(Exception e) {
        e.printStackTrace();
    }
    responseData = sb.toString();
    con.disconnect();

    JSONObject json = new JSONObject(responseData);
    String token = json.getString("access_token");

情報の取得

先ほど取得したアクセストークンを使って実際に自転車情報を取得してみたいと思います。
自転車情報を取得するためには、アスリート情報を取得すればその中に書いてあるみたいなので、アスリート情報を取得してみます。
https://developers.strava.com/docs/reference/#api-Athletes

公式ドキュメントによると、"https://www.strava.com/api/v3/athlete"に対して
GETメソッドでtokenをプロパティに与えてあげればレスポンス返してあげるよ、と書いてあるので言われた通りにやってみます。

サンプルコードとしては以下のような感じですね。
tokenの頭に"Bearer"をつけるのを忘れないようにしてください。

getathlete.java
    url = new URL("https://www.strava.com/api/v3/athlete");
    HttpURLConnection con = (HttpURLConnection)url.openConnection();
    con.setRequestMethod("GET");
    String authorization = "Bearer " + token;  //tokenは先ほど取得したtokenの値
    con.setRequestProperty("Authorization", authorization);
    con.setDoOutput(false);
    con.setDoInput(true);
    con.connect();

    responseData = "";
    stream = con.getInputStream();
    sb = new StringBuffer();
    line = "";
    br = new BufferedReader(new InputStreamReader(stream, "UTF-8"));
    while((line = br.readLine()) != null) {
        sb.append(line);
    }
    try {
        stream.close();
    }catch(Exception e) {
        e.printStackTrace();
    }
    responseData = sb.toString();
    con.disconnect();
    json = new JSONObject(responseData);

公式ドキュメント見てもらえればわかりますが、自転車情報に関してはbike[]という配列の入れ子構造となってます。
こういう場合はjsonarrayなどを使って取得する必要があります。

getbikes.java
    JSONArray BIKE = json.getJSONArray("bikes");
    int distance = BIKE.getJSONObject(Integer.parseInt(0)).getInt("distance");
    String bikeid = BIKE.getJSONObject(Integer.parseInt(0)).getString("id");
    String bikename = BIKE.getJSONObject(Integer.parseInt(0)).getString("name");

最後に

Stravaにアプリを登録してからAPIを叩いて情報を取得する一連の流れを書きました。
リクエストする部分によっては実装環境によって異なってくるかとは思いますが、おおまかな流れは同じではないでしょうか?
ぜひStravaのAPIをうまく使って効率よく運動して行きましょう!

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away