Strava APIを利用してツーリングのデータを取得できるようになるまで

Stravaとは

www.strava.com

Stravaは自転車やランニングなど走ったGPSログを共有することができるスポーツマン向けのSNSのようなものです(勝手な解釈)。

自分はツーリングやサイクリングなどのライドに行くときはサイクルコンピュータを起動してGPSでどこを走ったかなどを記録しています。

ライドが終わったあとは、このデータをアクティビティとしてStravaにアップロードしています。

StravaのAPIはこれらのアクティビティをJSON形式で取得できます。

今回は今までのアクティビティを引っ張ってきて面白いことできないかなと思いAPIを使うことにしました。

ついでに自分のアカウントも載せておくか。

www.strava.com

APIを使えるようになるまで

最低限のスコープをもったアクセストークンの取得まで

この記事では、APIでアクティビティを取得できるまで説明するため

  • Stravaのアカウント
  • 最低1つのアクティビティ

が必要です。

持っていない人は新規登録してからひとっ走り行ってきてアクティビティをアップロードしてください。

伊豆大島がおすすめです

アカウントを持っている人は右上のアイコンから設定を押します。

設定画面を開いて左のメニューからMy API アプリケーションを選択します。

StravaのAPIを利用して開発する予定のアプリの情報を入力します。

まだ決まってない場合はこれらの情報をあとから変更できるのでとりあえず適当に入力します。

自分は適当に入力しました。

作成後、アプリのアイコンの設定が必要です。未設定のまま進められないので適当に設定します。

設定後、API利用に必要な各種パラメータが与えられます。

  • クライアントID
  • クライアントシークレット
  • アクセストーク
  • リフレッシュトーク

この中で、

  • クライアントID
  • クライアントシークレット

はずっと同じ値を使い続けますが

は有効期限があるので一定期間毎に変わっていきます。

今回の登録で取得したアクセストークンは認証に必要な最低限のスコープのみ与えられていて、叩けるAPIも限られています。

まずはアクセストークンが正しいか試します。

自分自身のプロフィール取得のAPIは現時点のスコープで叩けるので、取得したアクセストークンを使って取得してみます。

curl -X GET \ 
https://www.strava.com/api/v3/athlete \
-H 'Authorization: Bearer ${ACCESS_TOKEN}

${ACCESS_TOKEN}は自分のアクセストークンに書き換えてください。

実行するとレスポンスが返ってきます。

{"id":24719665,"username":"uhhyoi","resource_state":2,"firstname":"うっ","lastname":"ひょい","bio":"","city":"","state":"","country":"","sex":"M","premium":true,"summit":true,"created_at":"2017-09-03T09:46:56Z","updated_at":"2022-05-26T11:03:56Z","badge_type_id":1,"weight":62.0,"profile_medium":"https://dgalywyr863hv.cloudfront.net/pictures/athletes/24719665/7117793/2/medium.jpg","profile":"https://dgalywyr863hv.cloudfront.net/pictures/athletes/24719665/7117793/2/large.jpg","friend":null,"follower":null}%

Strava登録時に設定したプロフィールが返ってきます。

自分の体重などがバレてますが、まあ、現在はこれよりも痩せているので大丈夫です。

プロフィールが返ってきていたら成功です。

次にOAuth認証によって更に様々なAPIを叩けるアクセストークンとリフレッシュトークンを取得します。

OAuth認証

認証用のURLを組み立てる

以下のURLをベースにアクセスするURLを組み立てます。

http://www.strava.com/oauth/authorize?client_id=[REPLACE_WITH_YOUR_CLIENT_ID]&response_type=code&redirect_uri=http://localhost/exchange_token&approval_prompt=force&scope=activity:read

URL内の[REPLACE_WITH_YOUR_CLIENT_ID]は先程取得した自分のクライアントIDに置き換えます。 クエリパラメータにあるscope=activity:readには取得するアクセストークンのスコープを指定します。

指定できるscopeは developers.strava.com

公式のDocにあるDetails About Requesting Accessセクションのscopeの欄に記載があります。

現時点のscopeがreadしかないので、APIを通じて自分のアクティビティにはアクセスできません。

APIを叩くために必要なscopeについてはAPIリファレンスに載っているので参照してください。

例えば、自分のアクティビティを一覧取得するAPI

https://developers.strava.com/docs/reference/#api-Activities-getLoggedInAthleteActivities

Requires activity:read.

とあるので、アクセスするにはactivity:readというscopeが必要になります。

よってクエリパラメータにはscope=activity:readと指定します。

認証する

組み立てたURLにアクセスします。

このような画面が出るので「アクティビティに関するデータを表示する」にチェックが入っていることを確認して「許可する」を押します。

するとリダイレクトされてそのURLにcodeというクエリパラメータが入っています。 このcodeを元に認証を進めます。

ちなみにリダイレクト先はlocalhostなので、「このサイトにアクセスできません」と表示されているのは正常です。

次に認証に必要なPOSTリクエストを以下のように投げます。

curl -X POST https://www.strava.com/oauth/token \
    -F client_id=${YOUR_CLIENT_ID} \
    -F client_secret=${YOUR_CLIENT_SECRET} \
    -F code=${AUTHORIZATION_CODE} \
    -F grant_type=authorization_code

${YOUR_CLIENT_ID},${YOUR_CLIENT_SECRET} にはそれぞれ最初に取得したクライアントIDとクライアントシークレットに置き換えます。

${AUTHORIZATION_CODE}はリダイレクト先に表示されていたクエリパラメータのcodeの値に置き換えます。

これでリクエストを送ると、以下のようなレスポンスが返ってきます。

{"token_type":"Bearer","expires_at":1655159199,"expires_in":21600,"refresh_token":"${REFRESH_TOKEN}","access_token":"${ACCESS_TOKEN},"athlete":{"id":24719665,"username":"uhhyoi","resource_state":2,"firstname":"うっ","lastname":"ひょい","bio":"","city":"","state":"","country":"","sex":"M","premium":true,"summit":true,"created_at":"2017-09-03T09:46:56Z","updated_at":"2022-05-26T11:03:56Z","badge_type_id":1,"weight":62.0,"profile_medium":"https://dgalywyr863hv.cloudfront.net/pictures/athletes/24719665/7117793/2/medium.jpg","profile":"https://dgalywyr863hv.cloudfront.net/pictures/athletes/24719665/7117793/2/large.jpg","friend":null,"follower":null}}%

${REFRESH_TOKEN},${ACCESS_TOKEN}は新しいスコープを持つリフレッシュトークンとアクセストークンです。

この新しいアクセストークンを使うことで自分のアクティビティを取得することができます。

早速、過去30件のアクティビティをAPIで取得してみます。

curl -X GET https://www.strava.com/api/v3/athlete/activities -H "Authorization: Bearer ${ACCESS_TOKEN}"

${ACCESS_TOKEN}は新しく取得しているアクセストークンです。

いろいろぐちゃぐちゃ返ってきたら成功です。JSON形式で返ってきているのでjqコマンドに通したりすると読みやすいと思います。

jqコマンド通したレスポンスの一部が以下です。

アクティビティっぽいデータが返ってきています。 ちなみにsummary_polylineというキーにあるグチャグチャ長い文字列はスタートからゴールまで走った位置情報をPolyline Encoding Algorithmという手法でエンコードしたものです。 デコードすると大量の緯度経度のデータになります。

各データの意味やAPIの利用方法は公式のリファレンスを参照してください。

developers.strava.com

これで一通りAPIが使えますが、注意点があります。

トークンのリフレッシュ

認証した際に返ってきたレスポンスに、expires_at, expires_inがありました。 これらはアクセストークンの有効期限を表しています。

{"token_type":"Bearer","expires_at":1655159199,"expires_in":21600,"refresh_token"...

expires_atは期限切れになる日時のUNIX Timeです。 expires_inはアクセストークンが持つ期間自体を秒で表したものです。 つまり 21600 / 3600 = 6  で6時間でアクセストークンは期限切れになります。

期限が切れたアクセストークンではAPIは叩けなくなります。

そのためアクセストークンのリフレッシュを定期的にする必要があります。

リフレッシュをすることでまた新たに同等のスコープのアクセストークンが発行されてそれをまた6時間使うことになります。

トークンのリフレッシュ方法は 公式DocのRefreshing Expired Access Tokensセクションに書いてあります。

developers.strava.com

以下のPOSTリクエストを送るだけです。

curl -X POST https://www.strava.com/api/v3/oauth/token \
  -d client_id=[YOUR_CLIENT_ID] \
  -d client_secret=[YOUR_CLIENT_SECRET]\
  -d grant_type=refresh_token \
  -d refresh_token=[YOUR_REFRESH_TOKEN]

[YOUR_CLIENT_ID],[YOUR_CLIENT_SECRET]は先程の認証で使ったものと同様のパラメータを使います。

[YOUR_REFRESH_TOKEN]codeを使って認証した際に取得したリフレッシュトークンに置き換えます。

StravaのMy APIアプリケーションに記載されているリフレッシュトークンは最低限のスコープに紐付いたリフレッシュトークンなので間違えないように気をつけてください。

置き換えてリクエストを投げると、認証のときと同様のレスポンスが返ってきます。

そのレスポンス内に新たなアクセストークンとリフレッシュトークンがあるのでAPIを投げるときはその新たなアクセストークンを使います。

そのアクセストークンも期限切れになったときは再びリフレッシュトークンを使って更に新しいアクセストークンとリフレッシュトークンを発行して使うといった流れになります。

プログラムを使ってAPIを叩くときは期限切れをチェックして自動的にトークンをリフレッシュするようにコードを書いておくのがおすすめです。

おわりに

これでStravaのAPIを使ってアクティビティを取得できます。このデータを取得してStrava側で集計して表示してくれないデータなどをプログラム組んで集計できたりします。

参考

Strava Developers

スポーツログアプリのStravaからAPIでアクティビティデータを取得してみる | DevelopersIO