strava-v3

repository·main·Indexed 18 days ago

https://github.com/node-strava/node-strava-v3

A Promise-based Node.js wrapper for the Strava v3 API. It provides a simplified interface for interacting with athlete, activity, club, gear, segments, and other Strava data. The library includes support for OAuth configuration, cursor-based and legacy pagination, file uploads, and rate limit monitoring. It utilizes json-bigint to handle large numeric IDs and provides specific error types, StatusCodeError and RequestError, for robust API error handling.

Tokens
6.4K
Snippets
27
Records
28
Agent score
63%

What's inside strava-v3

  1. Handle large numeric IDs (BigInt support)

    main

    Strava IDs can exceed Number.MAX_SAFE_INTEGER. This library uses json-bigint to parse responses, returning large integers as bignumber.js BigNumber objects rather than native JavaScript BigInt.

    To display or store these IDs, convert them to strings using .toString().

    const activity = await strava.activities.get({ id: '12345678901234567' });
    console.log(activity.id.toString());
  2. Configure OAuth for strava-v3

    main

    If building an app where users authorize their own accounts, you must provide OAuth credentials. You have three ways to configure these:

    1. Explicit configuration

    Use strava.config() to override environment variables and config files. This is required for OAuth flows.

    var strava = require('strava-v3')
    strava.config({
      "access_token"  : "Your apps access token (Required for Quickstart)",
      "client_id"     : "Your apps Client ID (Required for oauth)",
      "client_secret" : "Your apps Client Secret (Required for oauth)",
      "redirect_uri"  : "Your apps Authorization Redirection URI (Required for oauth)",
    });

    2. Environment variables

    Supply values using the STRAVA_ prefix:

    • STRAVA_ACCESS_TOKEN maps to access_token
    • STRAVA_CLIENT_ID maps to client_id
    • STRAVA_CLIENT_SECRET maps to client_secret
    • STRAVA_REDIRECT_URI maps to redirect_uri

    3. Config File (Deprecated)

    A strava_config JSON file in the module root can also be used.

  3. Handle errors in strava-v3

    main

    The library uses a Promise-based API where errors reject the Promise. Errors are categorized into two main types, which can be imported from strava.axiosUtility:

    1. StatusCodeError: Occurs when the Strava API returns a non-2xx HTTP status code.

      • name: 'StatusCodeError'
      • statusCode: The HTTP status code.
      • message: Status message and error details.
      • data: The response body (useful for debugging).
      • options: The request options used.
      • response: The full Axios response object.
    2. RequestError: Occurs due to technical issues (e.g., network failure, no response received, or request setup issues).

      • name: 'RequestError'
      • message: The error message.
      • options: The request options used.

    Note: Callback-style usage is not supported; only Promises are used.

    const strava = require('strava-v3');
    const { StatusCodeError, RequestError } = strava.axiosUtility;
    
    // Catch a non-2xx response with the Promise API
    badClient.athlete.get({})
        .catch((e) => {
            if (e.name === 'StatusCodeError') {
                // handle StatusCodeError
            }
        });
    
    // Or handle all errors
    badClient.athlete.get({})
        .catch((err) => {
            console.error(err);
        });
  4. Use specific user access tokens

    main

    In production, you should use the access_token of the specific user being queried. You can do this in two ways:

    Use the client constructor to create a new instance for a specific user.

    const stravaApi = require('strava-v3');
    // ... retrieve access_token for a specific user
    const strava = new stravaApi.client(access_token);
    const payload = await strava.athlete.get({})

    2. Pass token directly to API calls

    Pass the access_token as a property within the arguments object of an API call.

    const strava = require('strava-v3');
    const payload = await strava.athlete.get({'access_token':'abcde'})
    const stravaApi = require('strava-v3');
    const strava = new stravaApi.client(access_token);
    const payload = await strava.athlete.get({})
  5. Import strava-v3 library and interfaces

    main

    You can import the library directly or include the Strava interface for TypeScript support.

    Importing only the library:

    import strava from 'strava-v3';

    Importing the library and interfaces:

    import { default as strava, Strava } from 'strava-v3';
  6. Handle pagination in API calls

    main

    For endpoints that support pagination, you can control the results using either legacy or cursor-based arguments.

    Legacy Pagination

    Use page and per_page for endpoints that still require them.

    const payload = await strava.athlete.listActivities({
        page: 1,
        per_page: 2
    });

    Cursor-based Pagination

    For most modern endpoints, use page_size and after_cursor.

    const comments = await strava.activities.listComments({
      id: activityId,
      page_size: 20,
      after_cursor: "abc123%20"
    });
  7. Upload files to Strava

    main

    To upload files, provide the data_type (as per Strava API docs) and a file string representing the <filepath>/<filename>.

    By default, the promise resolves immediately with the initial response. To wait for the file to finish processing, set maxStatusChecks (e.g., 300 for ~5 minutes at 1s intervals). The promise will then resolve with the final upload result.

    Immediate resolution:

    const payload = await strava.uploads.post({
        data_type: 'gpx',
        file: 'data/your_file.gpx',
        name: 'Epic times'
    });

    Wait for processing:

    const result = await strava.uploads.post({
        data_type: 'gpx',
        file: 'data/your_file.gpx',
        name: 'Epic times',
        maxStatusChecks: 300
    });
  8. Monitor API rate limits

    main

    The library tracks rate limits via a global strava.rateLimiting object, which is updated with every request.

    Note: The API response payload only contains the data; rate limit info is tracked internally. If the required headers are missing from the response, rateLimiting methods return null.

    • strava.rateLimiting.exceeded(): Returns true if the most recent request exceeded the overall rate limit.
    • strava.rateLimiting.fractionReached(): Returns the current decimal fraction (0 to 1) of the overall rate used (the greater of short and long term limits).
    • strava.rateLimiting.readExceeded(): Returns true if the most recent request exceeded the read rate limit.
    • strava.rateLimiting.readFractionReached(): Returns the current decimal fraction (0 to 1) of the read rate used.
    // returns true if the most recent request exceeded the overall rate limit
    strava.rateLimiting.exceeded()
    
    // returns the current decimal fraction (from 0 to 1) of overall rate used
    strava.rateLimiting.fractionReached()
    
    // returns true if the most recent request exceeded the read rate limit
    strava.rateLimiting.readExceeded()
    
    // returns the current decimal fraction (from 0 to 1) of read rate used
    strava.rateLimiting.readFractionReached()
  9. Configure Strava credentials

    main

    The fetchConfig method allows you to provide Strava credentials using one of three methods. If no argument is passed to fetchConfig(), the module attempts to load credentials from a local JSON file and environment variables.

    1. Direct Configuration Object

    You can pass a StravaConfig object directly to fetchConfig to override all other sources.

    2. Configuration File

    If fetchConfig() is called without arguments, it looks for a JSON file at data/strava_config. The file should contain a JSON object with the following keys:

    • access_token
    • client_id
    • client_secret
    • redirect_uri

    3. Environment Variables

    If no object is provided and the config file is missing or incomplete, the module reads from the following environment variables:

    • STRAVA_ACCESS_TOKEN
    • STRAVA_CLIENT_ID
    • STRAVA_CLIENT_SECRET
    • STRAVA_REDIRECT_URI
    // Example: Direct configuration
    const authenticator = require('./lib/authenticator');
    
    authenticator.fetchConfig({
      access_token: 'YOUR_ACCESS_TOKEN',
      client_id: 'YOUR_CLIENT_ID',
      client_secret: 'YOUR_CLIENT_SECRET',
      redirect_uri: 'YOUR_REDIRECT_URI'
    });
  10. Reference: Supported API Endpoints

    main

    The following endpoints are supported by the library. All methods return Promises.

    #### OAuth
    * `strava.oauth.getRequestAccessURL(args)`
    * `strava.oauth.getToken(code)`
    * `strava.oauth.refreshToken(refreshToken)`
    * `strava.oauth.deauthorize(args)`
    
    #### Athlete
    * `strava.athlete.get(args)`
    * `strava.athlete.update(args)`
    * `strava.athlete.listActivities(args)`
    * `strava.athlete.listClubs(args)`
    * `strava.athlete.listZones(args)`
    
    #### Athletes
    * `strava.athletes.stats(args)`
    
    #### Activities
    * `strava.activities.get(args)`
    * `strava.activities.create(args)`
    * `strava.activities.update(args)`
    * `strava.activities.listZones(args)`
    * `strava.activities.listLaps(args)`
    * `strava.activities.listComments(args)`
    * `strava.activities.listKudoers(args)`
    
    #### Clubs
    * `strava.clubs.get(args)`
    * `strava.clubs.listMembers(args)`
    * `strava.clubs.listActivities(args)`
    * `strava.clubs.listAdmins(args)`
    
    #### Gear
    * `strava.gear.get(args)`
    
    #### Push Subscriptions
    *Note: These use Client ID/Secret and are NOT available on the `client` object.*
    * `strava.pushSubscriptions.list()`
    * `strava.pushSubscriptions.create({callback_url:...})`
    * `strava.pushSubscriptions.delete({id:...})`
    
    #### Routes
    * `strava.routes.getFile({ id: routeId, file_type: 'gpx' })`
    * `strava.routes.get(args)`
    
    #### Segments
    * `strava.segments.get(args)`
    * `strava.segments.listStarred(args)`
    * `strava.segments.listEfforts(args)`
    * `strava.segments.explore(args)`
    * `strava.segments.starSegment(args)`
    
    #### Segment Efforts
    * `strava.segmentEfforts.get(args)`
    
    #### Streams
    * `strava.streams.activity(args)`
    * `strava.streams.effort(args)`
    * `strava.streams.segment(args)`
    * `strava.streams.route(args)`
    
    #### Uploads
    * `strava.uploads.post(args)`