A complete client library for the Strava V3 API
Go
Permalink
Failed to load latest commit information.
cassettes Add activities/following endpoint May 20, 2015
examples Fix minor json parsing issues (thanks to go vet) Jul 29, 2015
.travis.yml Travis Take 3 Jan 2, 2014
README.md fixes typo in readme Dec 23, 2015
activities.go Add VirtualRide, correct EBikeRide ids Jan 23, 2016
activities_test.go
athletes.go Weight to athlete detail May 20, 2015
athletes_test.go No need to manually parse times. time.Time does it. May 20, 2015
clubs.go
clubs_test.go Update tests to use reflect.DeepEqual May 30, 2014
comments.go No need to manually parse times. time.Time does it. May 20, 2015
comments_test.go Rename kudos and comments Post to Create Jun 1, 2014
current_athlete.go Add activities/following endpoint May 20, 2015
current_athlete_test.go Add activities/following endpoint May 20, 2015
doc.go
efforts.go
errors.go
gear.go Fix minor json parsing issues (thanks to go vet) Jul 29, 2015
gear_test.go Update tests to use reflect.DeepEqual May 30, 2014
kudos.go
kudos_test.go
lap_efforts.go
oauth.go No need to manually parse times. time.Time does it. May 20, 2015
oauth_test.go error message missprint Aug 30, 2015
photos.go No need to manually parse times. time.Time does it. May 20, 2015
polyline.go Formatting and comments May 30, 2014
polyline_test.go Add polyline type Jan 8, 2014
ratelimit.go Update ratelimit to provide only Exceeded() and FractionReached() Mar 19, 2015
ratelimit_test.go Update ratelimit to provide only Exceeded() and FractionReached() Mar 19, 2015
segment_efforts.go
segment_efforts_test.go No need to manually parse times. time.Time does it. May 20, 2015
segments.go Fix minor json parsing issues (thanks to go vet) Jul 29, 2015
segments_test.go No need to manually parse times. time.Time does it. May 20, 2015
service.go
service_test.go add missing 'r' May 19, 2015
splits.go Second Initial Commit! Jan 2, 2014
streams.go
streams_test.go A re-refactor of streams Jun 1, 2014
uploads.go No need to manually parse times. time.Time does it. May 20, 2015
uploads_test.go
zones.go

README.md

go.strava

Go.strava provides a complete, including upload, wrapper library for the Strava V3 API. Structs are defined for all the basic types such as athletes, activities and leaderboards. Functions are provided to fetch all these values.

Please note: Every effort is made to keep the API Documentation up to date, however this package may lag behind. If this is impacting your development, please file an issue and it will be addressed as soon as possible.

To install

go get github.com/strava/go.strava

To use, imports as package name strava:

import "github.com/strava/go.strava"


Build Status     Coverage Status     Godoc Reference     Official Strava API Documentation


This document is separated into three parts

Examples

Make sure to check out the source code as it provides many helpful comments.

  • segment_example.go

    This example shows how to pull segment descriptions and leaderboards. To run:

    cd $GOPATH/src/github.com/strava/go.strava/examples
    go run segment_example.go -token=<your-access-token>
    

    A sample access token can be found on the API settings page.

  • oauth_example.go

    This example shows how to use OAuthCallbackHandler to simplify the OAuth2 token exchange, as well as how to handle the errors that might occur. To run:

    cd $GOPATH/src/github.com/strava/go.strava/examples
    go run oauth_example.go -id=<your-client-id> -secret=<your-client-secret>
    
    Visit http://localhost:8080/ in your favorite web browser
    

    Your client id and client secret can be found on the API settings page.

  • upload.go

    This example shows how to upload data to Strava. It will upload a random GPX file. To run:

    cd $GOPATH/src/github.com/strava/go.strava/examples
    go run upload.go -token=<your-access-token>
    

    The access token must have 'write' permissions which must be created using the OAuth flow, see the above example.

Service Documentation

For full documentation, see the Godoc documentation. Below is a overview of how the library works, followed by examples for all the different calls.

  1. All requests should start by creating a client that defines the access token to be used:

    client := strava.NewClient("<an-access-token>", optionalHttpClient)
    

    The library will use the http.DefaultClient by default. If the default client is unavailable, like in the app engine environment for example, you can pass one in as the second parameter.

  2. Then a service must be defined that represents a given API request endpoint, for example:

    service := strava.NewClubsService(client)
    
  3. Required parameters are passed on call creation, optional parameters are added after, for example:

    call := service.ListMembers(clubId).Page(2).PerPage(50)
    
  4. To actually execute the call, run Do() on it:

    members, err := call.Do()
    if e, ok := err.(*strava.Error); ok {
        // this is a strava provided error
    } else {
        // regular error, could be internet connectivity problems
    }
    

    This will return members 50-100 of the given clubs. All of these things can be chained together like so:

    members, err := strava.NewClubsService(strava.NewClient(token)).
        ListMembers(clubId).
        PerPage(100).
        Do()
    

Polyline decoding
Activities and segments come with summary polylines encoded using the Google Polyline Format. These can be decoded into a slice of [2]float64 using Decode(), for example: activity.Map.Polyline.Decode(), segment.Map.Polyline.Decode(), or segmentExplorerSegment.Polyline.Decode().

Examples for all the possible calls can be found below:

Authentication

Related objects: OAuthAuthenticator, AuthorizationResponse.

authenticator := &strava.OAuthAuthenticator{
    CallbackURL: "http://yourdomain/strava/authorize",
}

path, err := authenticator.CallbackPath()
http.HandleFunc(path, authenticator.HandlerFunc(oAuthSuccess, oAuthFailure))

func oAuthSuccess(auth *strava.AuthorizationResponse, w http.ResponseWriter, r *http.Request) {
    // Success
}

func oAuthFailure(err error, w http.ResponseWriter, r *http.Request) {
    // Failure, or access was denied
}

For a more detailed example of how to handle OAuth authorization see oauth_example.go

Athletes

Related objects: AthleteDetailed, AthleteSummary, AthleteMeta. AthleteStats. PersonalSegmentSummary.

For the athlete associated with the access token, aka current athlete:

service := strava.NewCurrentAthleteService(client)

// returns a AthleteDetailed object
athlete, err := service.Get().Do()

// returns a AthleteDetailed object
athlete, err := service.Update().
    City(city).
    State(state).
    Country(country).
    Gender(gender).
    Weight(weight).
    Do()


// returns a slice of ActivitySummary objects
activities, err := service.ListActivities(athleteId).
    Page(page).
    PerPage(perPage).
    Before(before).
    After(after).
    Do()

// returns a slice of ActivitySummary objects
activities, err := service.ListFriendsActivities(athleteId).
    Page(page).
    PerPage(perPage).
    Before(before).
    Do()

// returns a slice of AthleteSummary objects
friends, err := service.ListFriends().Page(page).PerPage(perPage).Do()

// returns a slice of AthleteSummary objects
followers, err := service.ListFollowers().Page(page).PerPage(perPage).Do()

// returns a slice of ClubSummary objects
clubs, err := service.ListClubs().Do()

// returns a slice of PersonalSegmentSummary objects
segments, err := service.ListStarredSegments().Do()

For other athletes:

service := strava.NewAthletesService(client)

// returns a AthleteSummary object
athlete, err := service.Get(athleteId).Do()

// returns a slice of AthleteSummary objects
friends, err := service.ListFriends(athleteId).Page(page).PerPage(perPage).Do()

// returns a slice of AthleteSummary objects
followers, err := service.ListFollowers(athleteId).Page(page).PerPage(perPage).Do()

// returns a slice of AthleteSummary objects
bothFollowing, err := service.ListBothFollowing(athleteId).Do()

// returns an AthleteStats objects
stats, err := service.Stats(athleteId).Do()

// returns a slice of SegmentEffortSummary objects
efforts, err := service.ListKOMs(athleteId).Do()

// returns a slice of ActivitySummary objects
// athleteId must match authenticated athlete's
activities, err := service.ListActivities(athleteId).Do()

// returns a slice of PersonalSegmentSummary objects
segments, err := service.ListStarredSegments(athleteId).Do()

Activities

Related objects: ActivityDetailed, ActivitySummary, PhotoSummary, ZonesSummary, LapEffortSummary, Location.
Related constants: ActivityTypes.

service := strava.NewActivitiesService(client)

// returns a AthleteDetailed if the activity is owned by the requesting user
// or an ActivitySummary object otherwise.
// The Type is defined by Activity.ResourceState, 3 for detailed, 2 for summary.
activity, err := service.Get(activityId).
    IncludeAllEfforts().
    Do()

// create a manual activity entry. To upload a file see Upload below.
activity, err := service.Create(name, type, startDateLocal, elapsedTime).
    Description(description).
    Distance(distance).
    Do()

activity, err := service.Update(activityId).
    Name(name).
    Description(description).
    Type(ActivityTypes.Ride).
    Private(true).
    Communte(true).
    Trainer(false).
    Gear(gearId).
    Do()

// returns a slice of PhotoSummary objects
photos, err := service.ListPhotos(activityId).Do()

// returns a slice of ZonesSummary objects
zones, err := service.ListZones(activityId).Do()

// returns a slice of LapEffortSummary objects
laps, err := service.ListLaps(activityId).Do()

Comments

Related objects: CommentDetailed, CommentSummary.

service := strava.NewActivityCommentsService(client, activityId)

// returns a slice of CommentSummary objects
comments, err := service.List().
    Page(page).
    PerPage(perPage).
    IncludeMarkdown().
    Do()

// create a comment if your application has permission
comment, err := service.Create("funny comment").Do()

// delete a comment if your application has permission
comment, err := service.Delete(commentId).Do()

Kudos

Related objects: AthleteSummary.

service := strava.NewActivityKudosService(client, activityId)

// returns a slice of AthleteSummary objects
comments, err := service.List().
    Page(page).
    PerPage(perPage).
    Do()

// create/give a kudo
comment, err := service.Create().Do()

// delete/take back a kudo
comment, err := service.Delete().Do()

Clubs

Related objects: ClubDetailed, ClubSummary.

service := strava.NewClubService(client)

// returns a ClubDetailed object
club, err := service.Get(clubId).Do()

// returns a slice of AthleteSummary objects
members, err := service.ListMembers(clubId).
    Page(page).
    PerPage(perPage).
    Do()

// returns a slice of ActivitySummary objects
activities, err := service.ListActivities(clubId).
    Page(page).
    PerPage(perPage).
    Do()

Gear

Related objects: GearDetailed, GearSummary.
Related constants: FrameTypes.

// returns a GearDetailed object
gear, err := strava.NewGearService(client).Get(gearId).Do()

Segments

Related objects: SegmentDetailed, SegmentSummary, SegmentLeaderboard, SegmentLeaderboardEntry, SegmentExplorer, SegmentExplorerSegment.
Related constants: AgeGroups, ActivityTypes, ClimbCategories, DateRanges, WeightClasses.

service := strava.NewSegmentsService(client)

// returns a SegmentDetailed object
segment, err := service.Get(segmentId).Do()

// return list of segment efforts
efforts, err := service.ListEfforts(segmentId).
    Page(page).
    PerPage(perPage).
    AthleteId(athleteId).
    DateRange(startDateLocal, endDateLocal).
    Do()

// returns a SegmentLeaderboard object
leaderboard, err := service.GetLeaderboard(segmentId).
    Page(page).
    PerPage(perPage).
    Gender(gender).
    AgeGroup(ageGroup).
    WeightClass(weightClass).
    Following().
    ClubId(clubId).
    DateRange(dateRange).
    ContextEntries(count).
    Do()

// returns a slice of SegmentExplorerSegment 
segments, err := service.Explore(south, west, north, east).
    ActivityType(activityType).
    MinimumCategory(cat).
    MaximumCategory(cat).
    Do()

Segment Efforts

Related objects: SegmentEffortDetailed, SegmentEffortSummary.

// returns a SegmentEffortDetailed object
segmentEffort, err := strava.NewSegmentEffortsService(client).Get(effortId).Do() 

Streams

Related objects: StreamSet, LocationStream, IntegerStream, DecimalStream, BooleanStream, Stream.
Related constants: StreamTypes.

// Activity Streams
// returns a StreamSet object
strava.NewActivityStreamsService(client).
    Get(activityId, types).
    Resolution(resolution).
    SeriesType(seriesType).
    Do()

// Segment Streams
// returns a StreamSet object
strava.NewSegmentStreamsService(client).
    Get(segmentId, types).
    Resolution(resolution).
    SeriesType(seriesType).
    Do()

// SegmentEffort Streams
// returns a StreamSet object
strava.NewSegmentEffortStreamsService(client).
    Get(effortId, types).
    Resolution(resolution).
    SeriesType(seriesType).
    Do()

Uploads

Related objects: UploadDetailed, UploadSummary.
Related constants: FileDataTypes,

service := strava.NewUploadsService(client)

// returns a UploadDetailed object
upload, err := service.Get(uploadId).
    Do()

// returns a UploadSummary object
// gzips the payload if not already done so,
// use .Get(uploadId) to check progress on the upload and eventually get the activity id
upload, err := service.Create(FileDataType, "filename", io.Reader).
    ActivityType(ActivityTypes.Ride).
    Name("name").
    Description("description").
    Private().
    Trainer().
    ExternalId("id").
    Do()

// typical ways to create an io.Reader in Go
fileReader, err := os.Open("file.go")
byteReader, err := bytes.NewReader(binarydata)
stringReader := strings.NewReader("stringdata")

Testing

To test code using this package try the StubResponseClient. This will stub the JSON returned by the Strava API. You'll need to be familiar with raw JSON responses, so see the Documentation

client := strava.NewStubResponseClient(`[{"id": 1,"name": "Team Strava Cycling"}`, http.StatusOK)
clubs, err := strava.NewClubsService(client).Get(1000)

clubs[0].Id == 1

This will return the club provided when creating the client even though you actually wanted club 1000.