I have been working with the Fitbit API on and off for a number of years and recently have been working with the subscription end point. After reading Scott Hanselmans blog post about Refit it got me thinking how easy would it be to knock something up. This isn’t in replacement for the Fitbit.NET Client library I’m a contributor to as it handles logins, retries etc.
Getting Started
To start with you need to add the Refit library into your application. To do this you add in the nuget package.
Install-Package refit
I would highly recommend reading the documentation for the library and also Scott Hanselman’s blog post for some other basics/getting started information.
Define the Api Interface
Next step is you need to define the API interface which you are going to work with. These methods relate to the end points you want to access in the API. One of the most basic requests in the Fitbit API is the GET request for user profile data so I went with that and defined a POCO class for the data to serilalise into.
public interface IFitbitApi
{
[Get("/1/user/{encodedUserId}/profile.json")]
Task<User> GetUserProfileAsync(string encodedUserId);
}
public class User
{
[JsonProperty("fullName")]
public string FullName { get; set; }
// other items omitted for brevity
}
Now that this is defined we need to specify the Authorization
header which is needed for the request. The way headers work in Refit
are interesting but the usage I was interested in was adding in the OAuth token to each request.
Authorization Header addition
To get the Authorization
header setup as required I had to add in the headers attribute to the API interface definition so that it knew about the required header.
public interface IFitbitApi
{
[Get("/1/user/{encodedUserId}/profile.json")]
[Headers("Authorization: Bearer")]
Task<User> GetUserProfileAsync(string encodedUserId);
}
The second part of this was to make sure the generated service the Refit
library generates knew where the value comes from. As part of the setup for the API call you can specify a RefitSettings
object which can drive a number of properties. One of the properties is AuthorizationHeaderValueGetter
which requires a Func<Task<string>>
to return the auth token.
The
Func<Task<string>>
is a function which the library will call if theAuthorization
header is specified on the interface to get the token required. It then can add it into the request before executing. More information can be found by looking at theAuthenticatedHttpClientHandler
in the source.
I made this really simple in this example as I am dealing with the data request not the OAuth flow to get the token.
var api = RestService.For<IFitbitApi>("https://api.fitbit.com", new RefitSettings()
{
AuthorizationHeaderValueGetter = () => Task.FromResult("insert oauth token here")
});
To generate an oauth token you can use the OAuth Interactive Tutorial obviously this is not for production usage!
Making the request
On submitting a request I found that I was receiving a successful response but the User
instance being returned was empty. On checking the documentation it’s returned as a property of an outer json object.
{
"user": {
"aboutMe":<value>,
"avatar":<value>,
"avatar150":<value>,
"avatar640":<value>,
"city":<value>,
"clockTimeDisplayFormat":<12hour|24hour>,
"country":<value>,
"dateOfBirth":<value>,
"displayName":<value>,
"distanceUnit":<value>,
"encodedId":<value>,
"foodsLocale":<value>,
"fullName":<value>,
"gender":<FEMALE|MALE|NA>,
"glucoseUnit":<value>,
"height":<value>,
"heightUnit":<value>,
"locale":<value>,
"memberSince":<value>,
"offsetFromUTCMillis":<value>,
"startDayOfWeek":<value>,
"state":<value>,
"strideLengthRunning":<value>,
"strideLengthWalking":<value>,
"timezone":<value>,
"waterUnit":<value>,
"weight":<value>,
"weightUnit":<value>
}
}
Due to this structure initial serilization did not work. As part of Fitbit.Net we solved this with our deserialization processing and specified a root property to look for. However this is at deserilization time and not setup so there is no hook, as far as I can tell, to intercept this using Refit
. To get around this I added a “response” POCO wrapper to match the returned structure.
Full code
class Program
{
static async Task Main(string[] args)
{
var api = RestService.For<IFitbitApi>("https://api.fitbit.com", new RefitSettings()
{
AuthorizationHeaderValueGetter = () => Task.FromResult("insert oauth token here")
});
var response = await api.GetUserProfileAsync("-");
Console.WriteLine($"Name: {response.User.FullName}");
Console.ReadLine();
}
}
public interface IFitbitApi
{
[Get("/1/user/{encodedUserId}/profile.json")]
[Headers("Authorization: Bearer")]
Task<UserResponse> GetUserProfileAsync(string encodedUserId);
}
public class UserResponse
{
[JsonProperty("user")]
public User User { get; set; }
}
public class User
{
[JsonProperty("fullName")]
public string FullName { get; set; }
// other items omitted for brevity
}
Conclusion
We’ve taken the Refit
library and using a generated OAuth token with the Fitbit API managed to request the specified user profile data.
Any comments, queries or suggestions then please contact me on Twitter @WestDiscGolf