Bruce Gust
asked on
If you've worked with the Fitbit API, you probably have run into this...
I'm working my way through a couple of tutorials that walk you through how to create an API that retrieves Fitbit info. The content is great and every educational, but I'm stuck and I need some help.
First of all, I'm using "fitbit-node" (https://github.com/lukasolson/fitbit-node). With that, I've been able to successfully retrieve "profile.json" which seems to be the starting point for any API.
The "app.js" that's included as part of the example, looks like this:
When you run this code after having successfully negotiated the Fitbit authorization screen, you get a screen full of JSON data that looks similar to this:
Now, head out to https://www.rdluna.info/fitbit_api.html. I realize that this is a different piece of code that's being used to access the Fitbit API, but there's enough in the way of similarities that justified believing that this was a viable resource that I could use to access what ultimately goes beyond mere profile info.
And that's the dilemma! What I have above is necessary and helpful, but there's nothing about the user's calorie intake, heartbeat or exercise regiment, and that's the info that I need.
According the rdluna tutorial, while my starting point is "profile.json" (below is the fourth block of code on the https://www.rdluna.info/fitbit_api.html tutorial, if you want to look at it))...
...this is only the user's information. If you want heartbeat, calories and exercise routine, then you have to access some of the other Fitbit endpoints which are listed here: https://dev.fitbit.com/build/reference/web-api/
Here's where I get lost...
You've got the "profile.json" data. But now you have to somehow segue into the other endpoints / fitness data, but I don't understand how.
In the luna tutorial, just a few blocks of code down, you have this:
It would seem to be that there's a "jump" that's been made based on the assumption that the student who's going through these tutorials understands the logic that ties all of this together.
If I do this:
I'm looking for heart rate and activities and I get nothing. Even the "console.log("heartrate") that I've got in bold in the above code doesn't show up.
What am I missing? There are no errors, but there's no info and no evidence to suggest that the "heart rate" and "activity" pieces are even firing. What am I doing wrong?
Thanks!
First of all, I'm using "fitbit-node" (https://github.com/lukasolson/fitbit-node). With that, I've been able to successfully retrieve "profile.json" which seems to be the starting point for any API.
The "app.js" that's included as part of the example, looks like this:
// initialize the express application
const express = require("express");
const app = express();
// initialize the Fitbit API client
const FitbitApiClient = require("fitbit-node");
const client = new FitbitApiClient({
clientId: "22BD5D", //client_id
clientSecret: "9677a6cdf63836e26d0617e9ac2c38f8", //client secret
apiVersion: '1.2' // 1.2 is the default
});
// redirect the user to the Fitbit authorization page
app.get("/authorize", (req, res) => {
// request access to the user's activity, heartrate, location, nutrion, profile, settings, sleep, social, and weight scopes
res.redirect(client.getAuthorizeUrl('activity heartrate location nutrition profile settings sleep social weight', 'http://localhost:3000/callback')); //callback url
});
// handle the callback from the Fitbit authorization flow
app.get("/callback", (req, res) => {
// exchange the authorization code we just received for an access token
client.getAccessToken(req.query.code, 'http://localhost:3000/callback').then(result => { //callback url
// use the access token to fetch the user's profile information
client.get("/profile.json", result.access_token)
.then(results => {
res.send(results[0]);
console.log(results[0].user.age);
}).catch(err => {
res.status(err.status).send(err);
});
}).catch(err => {
res.status(err.status).send(err);
});
});
// launch the server
app.listen(3000);
When you run this code after having successfully negotiated the Fitbit authorization screen, you get a screen full of JSON data that looks similar to this:
{
"user":{
"age":22,
"ambassador":false,
"autoStrideEnabled":true,
"avatar":"https://static0.fitbit.com/images/profile/defaultProfile_100.png",
"avatar150":"https://static0.fitbit.com/images/profile/defaultProfile_150.png",
"avatar640":"https://static0.fitbit.com/images/profile/defaultProfile_640.png",
"averageDailySteps":5296,
"clockTimeDisplayFormat":"12hour",
"corporate":false,
"corporateAdmin":false,
"dateOfBirth":"1983-08-26",
"displayName":"Bruce G.",
"displayNameSetting":"name",
"distanceUnit":"en_US",
"encodedId":"7V335V",
"familyGuidanceEnabled":false,
"features":{
"exerciseGoal":true
},
"firstName":"Bruce",
"foodsLocale":"en_US",
"fullName":"Bruce Gust",
"gender":"MALE",
"glucoseUnit":"en_US",
"height":175.20000000000002,
"heightUnit":"en_US",
"isChild":false,
"isCoach":false,
"lastName":"Gust",
"locale":"en_US",
"memberSince":"2019-10-22",
"mfaEnabled":false,
"offsetFromUTCMillis":-21600000,
"startDayOfWeek":"SUNDAY",
"strideLengthRunning":95.60000000000001,
"strideLengthRunningType":"default",
"strideLengthWalking":72.7,
"strideLengthWalkingType":"default",
"swimUnit":"en_US",
"timezone":"America/Chicago",
"topBadges":[
{
"badgeGradientEndColor":"00D3D6",
"badgeGradientStartColor":"007273",
"badgeType":"DAILY_STEPS",
"category":"Daily Steps",
"cheers":[
],
"dateTime":"2019-11-04",
"description":"15,000 steps in a day",
"earnedMessage":"Congrats on earning your first Urban Boot badge!",
"encodedId":"228TMK",
"image100px":"https://static0.fitbit.com/images/badges_new/100px/badge_daily_steps15k.png",
"image125px":"https://static0.fitbit.com/images/badges_new/125px/badge_daily_steps15k.png",
"image300px":"https://static0.fitbit.com/images/badges_new/300px/badge_daily_steps15k.png",
"image50px":"https://static0.fitbit.com/images/badges_new/badge_daily_steps15k.png",
"image75px":"https://static0.fitbit.com/images/badges_new/75px/badge_daily_steps15k.png",
"marketingDescription":"You've walked 15,000 steps And earned the Urban Boot badge!",
"mobileDescription":"With a number that's almost three times more than the national average, your step count is really heating up.",
"name":"Urban Boot (15,000 steps in a day)",
"shareImage640px":"https://static0.fitbit.com/images/badges_new/386px/shareLocalized/en_US/badge_daily_steps15k.png",
"shareText":"I took 15,000 steps and earned the Urban Boot badge! #Fitbit",
"shortDescription":"15,000 steps",
"shortName":"Urban Boot",
"timesAchieved":1,
"value":15000
},
{
"badgeGradientEndColor":"38D7FF",
"badgeGradientStartColor":"2DB4D7",
"badgeType":"DAILY_FLOORS",
"category":"Daily Climb",
"cheers":[
],
"dateTime":"2019-11-04",
"description":"50 floors in a day",
"earnedMessage":"Congrats on earning your first Lighthouse badge!",
"encodedId":"FITBITID",
"image100px":"https://static0.fitbit.com/images/badges_new/100px/badge_daily_floors50.png",
"image125px":"https://static0.fitbit.com/images/badges_new/125px/badge_daily_floors50.png",
"image300px":"https://static0.fitbit.com/images/badges_new/300px/badge_daily_floors50.png",
"image50px":"https://static0.fitbit.com/images/badges_new/badge_daily_floors50.png",
"image75px":"https://static0.fitbit.com/images/badges_new/75px/badge_daily_floors50.png",
"marketingDescription":"You've climbed 50 floors to earn the Lighthouse badge!",
"mobileDescription":"With a floor count this high, you're a beacon of inspiration to us all!",
"name":"Lighthouse (50 floors in a day)",
"shareImage640px":"https://static0.fitbit.com/images/badges_new/386px/shareLocalized/en_US/badge_daily_floors50.png",
"shareText":"I climbed 50 flights of stairs and earned the Lighthouse badge! #Fitbit",
"shortDescription":"50 floors",
"shortName":"Lighthouse",
"timesAchieved":1,
"value":50
}
],
"waterUnit":"en_US",
"waterUnitName":"fl oz",
"weight":81.6,
"weightUnit":"en_US"
}
}
Now, head out to https://www.rdluna.info/fitbit_api.html. I realize that this is a different piece of code that's being used to access the Fitbit API, but there's enough in the way of similarities that justified believing that this was a viable resource that I could use to access what ultimately goes beyond mere profile info.
And that's the dilemma! What I have above is necessary and helpful, but there's nothing about the user's calorie intake, heartbeat or exercise regiment, and that's the info that I need.
According the rdluna tutorial, while my starting point is "profile.json" (below is the fourth block of code on the https://www.rdluna.info/fitbit_api.html tutorial, if you want to look at it))...
...this is only the user's information. If you want heartbeat, calories and exercise routine, then you have to access some of the other Fitbit endpoints which are listed here: https://dev.fitbit.com/build/reference/web-api/
Here's where I get lost...
You've got the "profile.json" data. But now you have to somehow segue into the other endpoints / fitness data, but I don't understand how.
In the luna tutorial, just a few blocks of code down, you have this:
It would seem to be that there's a "jump" that's been made based on the assumption that the student who's going through these tutorials understands the logic that ties all of this together.
If I do this:
// initialize the express application
const express = require("express");
const app = express();
// initialize the Fitbit API client
const FitbitApiClient = require("fitbit-node");
const client = new FitbitApiClient({
clientId: "22BD5D", //client_id
clientSecret: "9677a6cdf63836e26d0617e9ac2c38f8", //client secret
apiVersion: '1.2' // 1.2 is the default
});
// redirect the user to the Fitbit authorization page
app.get("/authorize", (req, res) => {
// request access to the user's activity, heartrate, location, nutrion, profile, settings, sleep, social, and weight scopes
res.redirect(client.getAuthorizeUrl('activity heartrate location nutrition profile settings sleep social weight', 'http://localhost:3000/callback')); //callback url
});
// handle the callback from the Fitbit authorization flow
app.get("/callback", (req, res) => {
// exchange the authorization code we just received for an access token
client.getAccessToken(req.query.code, 'http://localhost:3000/callback').then(result => { //callback url
// use the access token to fetch the user's profile information
client.get("/profile.json", result.access_token)
.then(results => {
res.send(results[0]);
console.log(results[0].user.age);
}).catch(err => {
res.status(err.status).send(err);
});
}).catch(err => {
res.status(err.status).send(err);
});
});
app.get("/heartrate/:date", function(req, res) {
[b]console.log("heart rate");[/b]
client.get("/activities/heart/date/" + req.params.date + "/1d.json", token)
.then(async function(results) {
var date = results[0]['activities-heart'][0]['dateTime'];
var data = JSON.stringify(results[0]['activities-heart-intraday']['dataset']);
data = data.replaceAll('"time":"', '"dateTime":"' + date + "T");
result = await insert_query_json('fitbit.heartrate', data);
res.send(result);
console.log("hello");
}).catch(err => {
res.status(err.status).send(err);
});
});
app.get("/activity/:activity/:date", (req, res) => {
client.get("/activities/" + req.params.activity + "/date/" + req.params.date + "/1d.json", token)
.then(async function(results) {
var date = results[0]['activities-' + req.params.activity][0]['dateTime'];
var data = JSON.stringify(results[0]['activities-' + req.params.activity + '-intraday']['dataset']);
data = data.replaceAll('"time":"', '"dateTime":"' + date + "T");
result = await insert_query_json('fitbit.' + req.params.activity, data);
res.send(result);
}).catch(err => {
res.status(err.status).send(err);
});
});
// launch the server
app.listen(3000);
I'm looking for heart rate and activities and I get nothing. Even the "console.log("heartrate") that I've got in bold in the above code doesn't show up.
What am I missing? There are no errors, but there's no info and no evidence to suggest that the "heart rate" and "activity" pieces are even firing. What am I doing wrong?
Thanks!
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
BOOM!
Haha ... I like BOOM ! BOOM is good :)
ASKER
I'll apply what you're stated above and see if I can't make some progress.
BTW: I'm going to have a bunch of questions before I'm through. If you're willing, I would appreciate whatever insight you can give me.
Here's another question: https://www.experts-exchange.com/questions/29163184/Why-does-this-app-js-file-not-see-my-route.html#questionAdd