This package allows you to create a "server" application that interacts with the Fitbit API in Go.
The prerequisite is to follow the Getting Started official guide.
Once you have created a Fitbit Developer account you have to register a new application, of server type. Then, there are 2 required steps:
-
Server application Authorization flow.
galeone/fitbit
gives you the basic functionalities for implementing the Authorization Code Grant Flow with PKCE. You need to be familiar with some Web Framework for implementing what's described in the Server application Authorization flow.) -
Client usage.
Once the user granted the permissions to your application, you can use the authorized client for querying the Fitbit API. NOTE: only the GET queries are supported right now. It means that you can fetch everything (in a very convenient format, using annotated Go Structs), but you can't do POST/PUT/DELETE operations.
You also need to be familiar with some Web Framework (not shown).
- Create a type that implements the
fitbit.Storage
interface. You can see an implementation based on PostgreSQL, through the package galeone/igor here: galeone/fitbit-pgdb. - Create a
fitbit.Authorizer
object - Create the endpoint for the authorization flow. The content should look like
fitbitAuthorizer := fitbit.NewAuthorizer(_db, _clientID, _clientSecret, _redirectURL) authorizing := types.AuthorizingUser{ CSRFToken: uuid.New().String(), // Code verifier for PKCE // https://dev.fitbit.com/build/reference/web-api/developer-guide/authorization/#Authorization-Code-Grant-Flow-with-PKCE Code: fmt.Sprintf("%s-%s", uuid.New().String(), uuid.New().String()), } fitbitAuthorizer.SetAuthorizing(&authorizing) // Potentially set cookie for identifying the authorizing user c.SetCookie(&http.Cookie{ Name: "authorizing", Value: fitbitAuthorizer.CSRFToken().String(), // No Expires = Session cookie HttpOnly: true, }) if err = _db.InsertAuthorizingUser(&authorizing); err != nil { return err } var auth_url *url.URL if auth_url, err = fitbitAuthorizer.AuthorizationURL(); err != nil { return err } c.Redirect(http.StatusTemporaryRedirect, auth_url.String())
- Create the endpoint for the Redirect URI. The content should look like
state := c.QueryParam("state") if state != fitbitAuthorizer.CSRFToken().String() { return c.Redirect(http.StatusTemporaryRedirect, "/error?status=csrf") } code := c.QueryParam("code") var token *types.AuthorizedUser var err error if token, err = fitbitAuthorizer.ExchangeAuthorizationCode(code); err != nil { return c.Redirect(http.StatusTemporaryRedirect, "/error?status=exchange") } // Update the fitbitclient. Now it contains a valid token and HTTP can be used to query the API fitbitAuthorizer.SetToken(token) // Save token and redirect user to the application if err = _db.UpsertAuthorizedUser(token); err != nil { return err } // Cookie used to identify the user that authorized the application cookie := http.Cookie{ Name: "token", Value: token.AccessToken, Domain: _domain, Expires: time.Now().Add(time.Second * time.Duration(token.ExpiresIn)), HttpOnly: true, } c.SetCookie(&cookie) // Redirect the user to your application endpoint c.Redirect(http.StatusTemporaryRedirect, "/app")
That's all.
After the user authorized the application, you can re-create the fitbit.Authorizer
fetching the data from the database (using your Storage
implementation) and create the authorized fitbit.Client
.
fitbitAuthorizer := fitbit.NewClient(_db, _clientID, _clientSecret, _redirectURL)
// Auhtorization token (after exhange)
cookie, err = c.Cookie("token")
var dbToken *types.AuthorizedUser
if dbToken, err = _db.AuthorizedUser(cookie.Value); err != nil {
return err
}
// Set the valid token
fitbitAuthorizer.SetToken(dbToken)
// Create the client
var fb *client.Client
if fb, err = client.NewClient(fitbitAuthorizer); err != nil {
return err
}
// Use it!
var logs *types.ActivityLogList
if logs, err = fb.UserActivityLogList(&types.Pagination{
Offset: 0,
BeforeDate: types.FitbitDateTime{Time: time.Now()},
Limit: 10,
Sort: "desc",
}); err != nil {
return
}
for _, activity := range logs.Activities {
if activity.TcxLink != "" {
var tcxDB *tcx.TCXDB
if tcxDB, err = fb.UserActivityTCX(activity.LogID); err != nil {
return
}
// So something with the tcxDB
}
// Do something with the activity
}