{"id":15686203,"url":"https://github.com/galeone/fitbit","last_synced_at":"2025-03-31T17:31:29.410Z","repository":{"id":62867460,"uuid":"562108411","full_name":"galeone/fitbit","owner":"galeone","description":"Fitbit Web API - Go client. Create an OAuth2 server application that interacts with the Fitbit API","archived":false,"fork":false,"pushed_at":"2024-08-05T09:36:32.000Z","size":72,"stargazers_count":11,"open_issues_count":5,"forks_count":1,"subscribers_count":4,"default_branch":"main","last_synced_at":"2024-10-23T20:39:25.849Z","etag":null,"topics":["fitbit","fitbit-api","fitbit-sdk","go","golang"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/galeone.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-11-05T10:39:42.000Z","updated_at":"2024-09-14T10:50:26.000Z","dependencies_parsed_at":"2023-12-25T19:56:03.492Z","dependency_job_id":"b06c0c5c-c2d2-4a07-b16d-702b114d53fa","html_url":"https://github.com/galeone/fitbit","commit_stats":null,"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/galeone%2Ffitbit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/galeone%2Ffitbit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/galeone%2Ffitbit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/galeone%2Ffitbit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/galeone","download_url":"https://codeload.github.com/galeone/fitbit/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":222670770,"owners_count":17020515,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["fitbit","fitbit-api","fitbit-sdk","go","golang"],"created_at":"2024-10-03T17:35:43.326Z","updated_at":"2024-11-02T04:03:05.069Z","avatar_url":"https://github.com/galeone.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Fitbit Web API - Go client\n\nThis package allows you to create a \"server\" application that interacts with the [Fitbit API](https://dev.fitbit.com/reference/web-api/) in Go.\n\n## Usage\n\nThe prerequisite is to follow the [Getting Started](https://dev.fitbit.com/build/reference/web-api/developer-guide/getting-started/) official guide.\n\nOnce you have created a Fitbit Developer account you have to register a new application, of **server** type. Then, there are 2 required steps:\n\n1. Server application Authorization flow.\n\n   `galeone/fitbit` gives you the basic functionalities for implementing the [Authorization Code Grant Flow with PKCE](https://dev.fitbit.com/build/reference/web-api/developer-guide/authorization/#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](#server-application-authorization-flow).)\n2. Client usage.\n\n   Once the user granted the permissions to your application, you can use the authorized client for querying the Fitbit API.\n   **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.\n\n### Server application Authorization flow\n\nYou also need to be familiar with some Web Framework (not shown).\n\n1. Create a type that implements the `fitbit.Storage` interface. You can see an implementation based on PostgreSQL, through the package [galeone/igor](https://github.com/galeone/igor) here: [galeone/fitbit-pgdb](https://github.com/galeone/fitbit-pgdb).\n1. Create a `fitbit.Authorizer` object\n1. Create the endpoint for the authorization flow. The content should look like\n   ```go\n    fitbitAuthorizer := fitbit.NewAuthorizer(_db, _clientID, _clientSecret, _redirectURL)\n\n    authorizing := types.AuthorizingUser{\n        CSRFToken: uuid.New().String(),\n        // Code verifier for PKCE\n        // https://dev.fitbit.com/build/reference/web-api/developer-guide/authorization/#Authorization-Code-Grant-Flow-with-PKCE\n        Code: fmt.Sprintf(\"%s-%s\", uuid.New().String(), uuid.New().String()),\n    }\n\n    fitbitAuthorizer.SetAuthorizing(\u0026authorizing)\n\n    // Potentially set cookie for identifying the authorizing user\n    c.SetCookie(\u0026http.Cookie{\n        Name: \"authorizing\",\n        Value: fitbitAuthorizer.CSRFToken().String(),\n        // No Expires = Session cookie\n        HttpOnly: true,\n    })\n\n    if err = _db.InsertAuthorizingUser(\u0026authorizing); err != nil {\n        return err\n    }\n\n    var auth_url *url.URL\n    if auth_url, err = fitbitAuthorizer.AuthorizationURL(); err != nil {\n        return err\n    }\n\n    c.Redirect(http.StatusTemporaryRedirect, auth_url.String())\n   ```\n1. Create the endpoint for the Redirect URI. The content should look like\n   ```go\n    state := c.QueryParam(\"state\")\n    if state != fitbitAuthorizer.CSRFToken().String() {\n        return c.Redirect(http.StatusTemporaryRedirect, \"/error?status=csrf\")\n    }\n\n    code := c.QueryParam(\"code\")\n    var token *types.AuthorizedUser\n    var err error\n    if token, err = fitbitAuthorizer.ExchangeAuthorizationCode(code); err != nil {\n        return c.Redirect(http.StatusTemporaryRedirect, \"/error?status=exchange\")\n    }\n    // Update the fitbitclient. Now it contains a valid token and HTTP can be used to query the API\n    fitbitAuthorizer.SetToken(token)\n\n    // Save token and redirect user to the application\n    if err = _db.UpsertAuthorizedUser(token); err != nil {\n        return err\n    }\n    // Cookie used to identify the user that authorized the application\n    cookie := http.Cookie{\n        Name:     \"token\",\n        Value:    token.AccessToken,\n        Domain:   _domain,\n        Expires:  time.Now().Add(time.Second * time.Duration(token.ExpiresIn)),\n        HttpOnly: true,\n    }\n    c.SetCookie(\u0026cookie)\n    // Redirect the user to your application endpoint\n    c.Redirect(http.StatusTemporaryRedirect, \"/app\")\n   ```\n\nThat's all.\n\n### Client usage\n\nAfter 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`.\n\n```go\nfitbitAuthorizer := fitbit.NewClient(_db, _clientID, _clientSecret, _redirectURL)\n\n// Auhtorization token (after exhange)\ncookie, err = c.Cookie(\"token\")\n\nvar dbToken *types.AuthorizedUser\nif dbToken, err = _db.AuthorizedUser(cookie.Value); err != nil {\n    return err\n}\n\n// Set the valid token\nfitbitAuthorizer.SetToken(dbToken)\n\n// Create the client\nvar fb *client.Client\nif fb, err = client.NewClient(fitbitAuthorizer); err != nil {\n    return err\n}\n\n// Use it!\n\nvar logs *types.ActivityLogList\nif logs, err = fb.UserActivityLogList(\u0026types.Pagination{\n    Offset:     0,\n    BeforeDate: types.FitbitDateTime{Time: time.Now()},\n    Limit:      10,\n    Sort:       \"desc\",\n}); err != nil {\n    return\n}\n\nfor _, activity := range logs.Activities {\n    if activity.TcxLink != \"\" {\n        var tcxDB *tcx.TCXDB\n        if tcxDB, err = fb.UserActivityTCX(activity.LogID); err != nil {\n            return\n        }\n        // So something with the tcxDB\n    }\n   // Do something with the activity\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgaleone%2Ffitbit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgaleone%2Ffitbit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgaleone%2Ffitbit/lists"}