##はじめに
StravaにAPIがある!でも日本語ドキュメントがない!わかりづらい!
という状況に陥り、自分が割と苦労したので、アスリートエンジニアのために記録を残したいと思います。
みんなで運動して健康な体でコーディングしよう!!
##Stravaとは
アスリート向けのSNSです。
ランニングや自転車、水泳など様々なアクティビティを記録することができます。
stravaでは開発者向けAPIが提供されており、このAPIを使うことでアスリート情報や登録してある自転車やシューズの情報を取得できます。
##この記事の内容
Stravaにアプリを登録し、HTTPリクエストを投げて自転車の情報を取得するまでを記載しています。
GET?POST?なにそれ?っていう状態から作ったので、初心者の方でもわかりやすい内容になっているのではないかと思います。
##開発環境
特に今回は開発環境に依存しないかとは思いますが一応記載しておきます。
- OS:mac OS HighSierra
- Eclipse4.8
- Tomcat 9.0.26
- JDK 1.8.0
##Stravaにアプリを登録
まずstravaにログインし、設定ページのMyAPIアプリケーションアクセスすると自分のアプリを登録することができます。
この時点では別にアプリが出来ていなくても大丈夫なので、適当に登録しちゃいましょう。
ひとまずウェブサイトを
とします。
:8080はtomcat使ってアプリ作るつもりだったので8080にしてあります。(8080はtomcatで利用するポート番号です。)
認証コールバックドメインも
127.0.0.1:8080
としておきます。
アイコンも適当に登録するとクライアントIDや、クライアントシートなどの値が与えられます。
##WebAPIにアクセス
作業としては大きく分けて2つです。
- WebAPIを叩くために必要となるアクセストークンを取得します。
- その次にそのトークンを利用してWebAPIにアクセスし、情報を取得します。
###1.アクセストークンの取得
StravaではOauth2.0という仕組みを導入しています。
Oauthに関しては以下のQiitaの記事がめちゃめちゃわかりやすかったので、こちらを参照ください。
一番分かりやすい OAuth の説明
基本的にはstravaの公式ドキュメントに沿ってやっていきます。
トークンを取得するためには以下のURLにヘッダー情報を加えたものをGETメソッドを利用してHTTPリクエストを飛ばします
GETメソッドにおいて情報を追加する場合はURLの後ろに追加して行きます。
今回トークンの取得に当たって必要となる情報が次の5つです。
-
clientid
先ほどのStravaにアプリを登録した際に表示されていたクライアントIDの値です。 -
redirect_uri
認証完了後にリダイレクトされる先の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など様々なものが用意されているので
自分のアプリでやりたいことに適したものを選択しましょう。
例としてヘッダーを加えたURLは以下のようなものになります。
このURLにアクセスすると、以下のような画面が表示されるかと思います。
ここで許可を押すと、Stravaのログイン画面に遷移し、ログインすると認証されリダイレクトURL先へと遷移します。
リダイレクトした先のURLに"code="という部分が含まれているかと思います。
hogehoge/state=&code=hogehogehogehoge&scope....
このコードの値を利用するので控えておいてください。
次に、以下のURLに対してPOSTメソッドを使ってHTTPリクエストを行います。
このPOSTメソッドのbodyに必要な情報を与えることで、アクセストークンが取得できます。
bodyに与える情報は以下の5つです。
-
clientID
Stravaにアプリを登録したときに与えられたクライアントIDの値 -
client_secret
Stravaにアプリを登録したときに与えられたクライアントシートの値
(クライアントシークレットの誤り?) -
code
先ほどのリダイレクト先のURLに含まれていたcodeの値 -
grant_type
必ずauthorization_codeとしてください。
POSTメソッドの実装はアプリを実装する環境によって異なるかと思いますが、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が存在しているので、このトークンを取得します。
サンプルコードとしては以下のような感じですかね。
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");
###2.情報の取得
先ほど取得したアクセストークンを使って実際に自転車情報を取得してみたいと思います。
自転車情報を取得するためには、アスリート情報を取得すればその中に書いてあるみたいなので、アスリート情報を取得してみます。
公式のドキュメントによると、
に対し、tokenをプロパティに与えてGETすればレスポンス返してあげるよ、と書いてあるので言われた通りにやってみます。
サンプルコードとしては以下のような感じですね。
tokenの頭に"Bearer"をつけるのを忘れないようにしてください。
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などを使って取得する必要があります。
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をうまく使って効率よく運動して行きましょう!