Когда я кодировал свой личный веб-сайт, я искал способы персонализировать проект. Я не хотел, чтобы это было просто место для постов в блогах и пошаговых инструкций по проектам. Я хотел поделиться частичкой себя там также.

Имея это в виду, я интегрировал RSS-канал Goodreads, так как книги — одна из моих страстей. Пока я работал над своим портфолио, я также готовился к своему первому полумарафону и пробежал ТОННУ, которую записал на Strava. Я подумал про себя, почему бы не добавить эти данные и на мой сайт?

Я видел, что у них есть API, использующий OAuth2, с которым у меня не было большого опыта. После небольшого количества проб и ошибок, а также различных интернет-ресурсов, я смог все настроить и запустить.

Чтобы сэкономить вам время, я решил написать простое руководство по процессу. Strava предоставляет информацию здесь, но я буду сокращать ее для вас шаг за шагом. Вот документация Strava, если хотите полное изложение.

Давайте начнем!

1. Получите учетные данные приложения из Strava
Первый шаг, который вам нужно сделать, — это зайти в Strava, чтобы зарегистрировать приложение (это намного проще, чем кажется), а затем получить доступ. ключи. URL-адрес для этого может быть трудно найти, поэтому вот он для справки: https://www.strava.com/settings/api.

Когда вы окажетесь там, вам нужно будет заполнить несколько полей, чтобы получить свои учетные данные. Поля, заполненные здесь, не очень важны.

Поле, которое сбило меня с толку, было Authorization Callback Domain. Это используется только один раз для следующего шага, поэтому вы можете установить его на localhost, чтобы все заработало. Вам не нужно запускать локальный хост или предпринимать какие-либо дополнительные шаги, чтобы заставить Authorization Callback Domain работать, просто заполните эту форму localhost как Authorization Callback Domain и все.

2. Авторизация учетных данных в браузере
Этот шаг выполняется только один раз и включает посещение определенного URL-адреса в браузере, чтобы вы могли авторизовать использование учетных данных, которые Strava предоставила вам на предыдущем шаге. .

Моей целью при использовании API было использование конечной точки Список действий спортсменов, для которой требуется read_all доступ. Вам нужно будет выполнить этот шаг для любого уровня доступа, который вы хотите, но следующий URL-адрес будет специально для доступа read_all.

Что вам нужно сделать здесь, так это вставить этот URL-адрес в свой браузер: // https://localhost/exchange_token?state=&code=1c49f418910a609b0097ae5ce0016c9b8141e8cd&scope=read,activity:read_all. Идите вперед и укажите URL-адрес с client_id из вашей учетной записи Strava.

3. Получите код доступа Strava
Отлично! Когда вы перейдете по указанному выше URL-адресу, вам будет предложено авторизовать свой проект в Strava:

Как только вы нажмете Authorize, вы будете перенаправлены на новый URL-адрес, который выглядит следующим образом: https://localhost/exchange_token?state=&code=1c49xxxxxxxxxxxxxxxxxxxxxxx&scope=read,activity:read_all.

Вы не увидите ничего отображаемого на этой странице, и это нормально. Все, что вам нужно, это новый URL.

Я отредактировал некоторое значение code, которое я получил там в качестве параметра запроса, но это поле, которое вы захотите сохранить для следующего шага.

4. Получите токены доступа и обновления Strava
После того, как вы соберете значение code, вам нужно будет сделать запрос API (вы можете использовать Postman, cURL или любой другой Инструмент запроса API или сервер для этого), чтобы получить актуальную информацию о маркере доступа.

Запрос будет POST для этой конечной точки:

https://www.strava.com/oauth/token

В качестве параметров запроса вы должны указать следующее:

client_id: вы можете получить это из своей учетной записи Strava
client_secret: вы можете получить это из своей учетной записи Strava
code: вы должны были получить это на последнем шаге из URL-адреса
grant_type: установите это до authorization_code

Полный URL-адрес будет выглядеть так (я отредактировал собственные значения):

https://www.strava.com/oauth/token?client_id=xxxxxxx&client_secret=xxxxxxxxxxxxxxxxxxxxxx&code=1c49xxxxxxxxxxxxxxxxxxxxxxx&grant_type=authorization_code

Если вы используете Postman, вот как должен выглядеть интерфейс:

Выполнение этого запроса приведет к ответу, который выглядит следующим образом:

{
    "token_type": "Bearer",
    "expires_at": 1681350948,
    "expires_in": 21600,
    "refresh_token": "25bdxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    "access_token": "87b0xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    "athlete": {
        "id": xxxxxx,
        "username": "xxxxxxx",
        "resource_state": 2,
        "firstname": "Spencer",
        "lastname": "Attick",
        "bio": null,
        "city": "Oakland",
        "state": "California",
        "country": "United States",
        "sex": null,
        "premium": false,
        "summit": false,
        "created_at": "2015-04-01T00:46:54Z",
        "updated_at": "2023-04-11T18:24:23Z",
        "badge_type_id": 0,
        "weight": 0.0,
        "profile_medium": "https://graph.facebook.com/1226490129/picture?height=256&width=256",
        "profile": "https://graph.facebook.com/1226490129/picture?height=256&width=256",
        "friend": null,
        "follower": null
    }
}

Важными полями, на которые следует обратить внимание, являются expires_at, refresh_token и access_token.

access_token Strava истечет в expires_at времени, которое является отметкой времени эпохи Unix. Мы поговорим об обновлении позже, а пока давайте получим данные Strava.

5. Получить данные о тренировках из Strava
Хорошо! Наконец-то мы можем сделать запрос на получение нужных нам данных из Strava!

Здесь вам нужно сделать запрос GET, который выглядит следующим образом:

curl --location 'https://www.strava.com/api/v3/athlete/activities' \
 --header 'Authorization: Bearer <ACCESS_TOKEN>'

Вы будете использовать access_token, который вы получили выше, в качестве жетона носителя здесь. Убедитесь, что у вас вообще нет тела запроса для этого шага, так как это вызовет ошибку.

Посмотрите ответ на этот запрос. У вас есть данные Strava, с которыми вы можете работать! Вы можете добавить это на свой личный веб-сайт, создать панель тренировок для себя, создать таблицу лидеров с друзьями или что-то еще, что вы можете придумать!

7. Управление обновлением токена доступа
Последнее, о чем мы хотим позаботиться, — это убедиться, что вы можете обновить свой токен по истечении срока его действия. Для этого вам нужно отслеживать последнее полученное поле expires_at. Когда текущее время больше, чем значение значения expires_at, пришло время для нового access_token.

Вы сделаете этот запрос POST, чтобы получить новый токен:

curl --location --request POST 'https://www.strava.com/oauth/token

Вот параметры запроса, которые вы будете использовать, и их значения:

client_id: вы можете получить это из своей учетной записи Strava
client_secret: вы можете получить это из своей учетной записи Strava
code: вы должны были получить это на последнем шаге по URL-адресу
grant_type: установите это to refresh_token
refresh_token
: refresh_token из вашего последнего успешного запроса аутентификации

Вот полный запрос с заданными параметрами запроса:

?client_id=xxxxxxx&client_secret=xxxxxxxxxxxxxxxxxxxxxx&grant_type=refresh_token&refresh_token=25bd1cf38exxxxxxxxxxxxxxxxxxxxx'

Ответ будет выглядеть так:

{
    "token_type": "Bearer",
    "access_token": "6e6e9xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    "expires_at": 1681430228,
    "expires_in": 21600,
    "refresh_token": "25bdxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
}

Теперь все готово! Вы можете отправлять запросы в Strava, чтобы получить значимые данные о своих действиях, и вы можете создать новый токен доступа!

Отсюда вы захотите собрать все вместе во что-то, что вы можете использовать на своем сервере. Вот код, который я использую для интеграции Strava, который я написал для своего личного веб-сайта:

const isStravaTokenExpired = (currentExpirationTime) => {
  const currentEpochTime = Date.now();
  if (currentExpirationTime === 'undefined') {
      return `There is an error with the currentEpirationTime, it's value is: ${currentExpirationTime}.`
  }
  return currentEpochTime > currentExpirationTime;
}

const generateNewToken = async () => {
  console.log('Generating new token...');
  const requestOptions = {
      method: 'POST',
      redirect: 'follow'
    };
  const requestURL = `https://www.strava.com/oauth/token?client_id=${process.env.STRAVA_CLIENT_ID}&client_secret=${process.env.STRAVA_CLIENT_SECRET}&grant_type=refresh_token&refresh_token=ReplaceWithRefreshToken&refresh_token=${process.env.STRAVA_CACHED_REFRESH_TOKEN}`;

  try {
      let response = await fetch(requestURL, requestOptions);
      response = await response.json(); 
      if (response.message === 'Bad Request') {
        console.log(response);
          return;
      }
      return {
          refreshToken: await response.refresh_token, 
          expirationTime: await response.expires_at,
          accessToken: await response.access_token
      }
  } catch (error) {
      console.log(error);
  }

}



const persistNewTokenData = async (newTokenData) => {
  // Read the .env file
  const envBuffer = fs.readFileSync('.env');
  const envConfig = dotenv.parse(envBuffer);

  // Update the relevant key with the new value
  envConfig['STRAVA_EXPIRATION_TIME'] = newTokenData.expirationTime,
  envConfig['STRAVA_CACHED_REFRESH_TOKEN'] = newTokenData.refreshToken,
  envConfig['STRAVA_CACHED_TOKEN'] = newTokenData.accessToken

  // Write the updated key-value pair to the file
  const envText = Object.keys(envConfig).map(key => `${key}=${envConfig[key]}`).join('\n');
  await fs.promises.writeFile('.env', envText);
};



const getStravaActivityData = async () => {
  console.log('Requesting activity data from Strava...');
  let myHeaders = new Headers();
  myHeaders.append("Authorization", `Bearer ${process.env.STRAVA_CACHED_TOKEN}`);

  const requestOptions = {
    method: 'GET',
    headers: myHeaders,
    redirect: 'follow'
  };

  try {
      const response = await fetch("https://www.strava.com/api/v3/athlete/activities", requestOptions);
      return response.json();

  } catch (error) {
      console.log('error', error)
  }   
}

//check to see if the expiration time has passed
const executeStravaLogic = async () => {
  const isTokenExpired = isStravaTokenExpired(process.env.STRAVA_EXPIRATION_TIME);

  if (typeof isTokenExpired === 'string') {
      console.log('Please resolve the error with the current expiration time stored in the .env file.');
      return;
  } else if (isTokenExpired) {
      console.log('The expiration time has passed. Generating a new token...');
      //if yes - generate a new token
      const newTokenData = await generateNewToken();
      if (!newTokenData.expirationTime) {
          console.log('There was an error getting refresh token data.')
          return;
      } 
      //save the new token info to .env
      persistNewTokenData(newTokenData);

  } 
  //make request to Strava activities endpoint
  const stravaActivityData = await getStravaActivityData();
  return stravaActivityData;
};

app.get('/api/strava', executeStravaLogic);

Не стесняйтесь использовать то, что работает для вас, и отказываться от того, что не работает.

Наслаждаться!

Повышение уровня кодирования

Спасибо, что являетесь частью нашего сообщества! Перед тем, как ты уйдешь:

  • 👏 Хлопайте за историю и подписывайтесь на автора 👉
  • 📰 Смотрите больше контента в публикации Level Up Coding
  • 💰 Бесплатный курс собеседования по программированию ⇒ Просмотреть курс
  • 🔔 Подписывайтесь на нас: Twitter | ЛинкедИн | "Новостная рассылка"

🚀👉 Присоединяйтесь к коллективу талантов Level Up и найдите прекрасную работу