Coder Social home page Coder Social logo

go.strava's Introduction

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.

Starting June 2018

Find the new Strava V3 API at https://github.com/strava/developers.strava.com/. You can generate Go client following the Client code section. This repository is no longer getting updated and may be removed in the near future.

To install

go get github.com/strava/go.strava

To use, imports as package name strava:

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

[![Build Status](https://travis-ci.org/strava/go.strava.png?branch=master)](https://travis-ci.org/strava/go.strava)     [![Coverage Status](https://coveralls.io/repos/strava/go.strava/badge.png?branch=master)](https://coveralls.io/r/strava/go.strava?branch=master)     [![Godoc Reference](https://godoc.org/github.com/strava/go.strava?status.png)](https://godoc.org/github.com/strava/go.strava)     [Official Strava API Documentation](http://strava.github.io/api)
### This document is separated into three parts

Examples

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

  • 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.

  • 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.

  • 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.

go.strava's People

Contributors

davidalee avatar ferguzz avatar jolivares avatar lalyos avatar mjanda avatar paulmach avatar yantonov avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

go.strava's Issues

Better message errors / ability to logging request & response

When trying to upload an existing activity file I get an empty error message. It's not easy to tell from the error message what happened. So it would be great if the error messages were more descriptive, and it would also be great to have the ability to log the request & response message (http status code, headers, and bodies if possible).

Feature Request: Auto-Strava

It is widely reported that the COVID vaccines will contain a 5G chip.

I would like a service that automatically uploads data from my 5G chip to my Strava account. The benefits of this service will be:

1. Reduced risk of data loss: User no longer needs to manually press buttons to track their activities. Many users forget to do this in current workflows.

2. Weight savings Users currently need to bring bulky phones or watches on bike rides. The iphone 11 weighs 194g. There is no published weight data for the 5g chip. Based on the name, it likely weighs 5 grams.

Return api error codes

Hi,

I would like to know, when I fetch an activity and that I get an error, if it is recoverable or not (i.e. if I should keep trying later or not). For example, if somebody delete an activity, and I got a webhook push just before that, I'll get an error when trying to fetch the activity later. Of course, in that case, it isn't recoverable.

But if the activity still exists and it was a strava server error, it would probably be recoverable and I should try again later.

I'm guessing the responses I'd get would be a 404 in the first case, and a 500 in the second.

However the go client doesn't propagate the HTTP response code up to the API (see in service.go, the defaultErrorHandler function)

I see two options:

  • It's almost possible as far as I can tell to provide a custom error handler, but not quite (there is a default error handler, but I can't change it). So the first option, is to make this overridable in the Client type.
  • The other option, is to change the default ErrorHandler to return a custom error type. This would not change the api itself, but it would be possible for clients to extract info out of the custom error type.

I'm happy to send pull requests for either options if you would like that.

Thanks,

CloudQuery Plugin?

Hi Team, hopefully this is right place to ask, if not, I'd appreciate if you can direct me.

I'm the founder of cloudquery.io, a high performance open source ELT framework.

Our users are interested in a Strava plugin, but as we cannot maintain all the plugins ourselves, I was curious if this would be an interesting collaboration, where we would help implement an initial source plugin, and you will help maintain it.

This will give your users the ability to sync Strava data to any of their datalakes/data-warehouses/databases easily using any of the growing list of CQ destination plugins.

Best,
Yevgeny

How should one get a Refresh token?

I want to get and store a refresh token after allowing a user to authenticate and link accounts, so my application can pull data when it wants without user interaction.

To do this, I have to get and store a refresh token which I can use to refresh the access token when I want. The access token only lasts six hours.

However, I can't find where the refresh token is exposed.

I tried using the access token returned from a Success from OAuthAuthenticator, but I only get "Status:400 Bad Request StatusCode:400 " to my call to my PostForm call to "https://www.strava.com/oauth/token".

How should I proceed?

support to get/set segment_leaderboard_opt_out on activities

It doesn't look like the api supports getting/setting the new segment_leaderboard_opt_out attribute on activities. Do you know if/when support for that will be added?

I found the name by looking at what the front end does, when it PUTs to https://www.strava.com/athlete/training_activities/xxxxxxxx

Thanks so much

"json: cannot unmarshal number" with zones for run activities

Example api body causing error:

$ curl -G https://www.strava.com/api/v3/activities/95352413/zones     -H "Authorization: Bearer xxx"
[{"score":null,"distribution_buckets":[{"max":1.8331809410114008,"min":0,"time":117},{"max":2.156683460013413,"min":1.8331809410114008,"time":67},{"max":2.4435539047991397,"min":2.156683460013413,"time":71},{"max":2.869924875495906,"min":2.4435539047991397,"time":121},{"max":-1,"min":2.869924875495906,"time":413}],"type":"pace","resource_state":3,"sensor_based":true}]

Wrong upload_id example in the specification at /athlete/activities

The developers site states that, at /athlete/activities the returned upload_id through SummaryActivity has type long. Yet, the response example you provide:

[ {
  "resource_state" : 2,
  "athlete" : {
    "id" : 134815,
    "resource_state" : 1
  },
  "name" : "Happy Friday",
  "distance" : 24931.4,
  "moving_time" : 4500,
  "elapsed_time" : 4500,
  "total_elevation_gain" : 0,
  "type" : "Ride",
  "sport_type" : "MountainBikeRide",
  "workout_type" : null,
  "id" : 154504250376823,
  "external_id" : "garmin_push_12345678987654321",
  "upload_id" : 987654321234567891234,
[...]

Provides an upload_id which doesn't complain with the specification, as int64's max value is 9223372036854775807, which is less than 987654321234567891234. This may be important because it makes more complex to create integration tests mocking the API using the provided examples.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.