Access your Nike+ run data using C# and .NET

Here’s a really simple way to use your Nike+ run data on your own website using C#.

Firstly, get your Nike+ ID and test out your feed by pointing your browser to the Nike+ run list API URL as demonstrated below. You can find your unique ID using the instructions listed in this post.  It’s worth noting that older accounts have a numeric ID, while newer subscribers have a GUID-like string like mine.

http://nikerunning.nike.com/nikeplus/v1/services/widget/get_public_run_list.jsp?userID=14fa3afc-8687-47ef-9899-75e8d090284d

If, after requesting this URL, you can see your run data in XML format, the ‘share more’ setting is already enabled in Nike+.  If not, you either have the wrong ID or you need to make your profile data public. You can do this within the privacy options within the Nike+ web application.

Here’s a C# class I wrote to read the XML data into a strongly typed object called RunViewModel, consisting of ‘summary’ and ‘run list’ objects:

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Xml;using System.Xml.Linq;using System.Net;namespace com.kewney.examples.nikeplus{        public class RunViewModel    {        public List Runs { get; set; }        public Summary Summary { get; set; }    }    public class Run    {        public DateTime startTime { get; set; }        public float distance { get; set; }        public int duration { get; set; }        public DateTime syncTime { get; set; }        public float calories { get; set; }        public string name { get; set; }        public string description { get; set; }        public string howFelt { get; set; }        public string weather { get; set; }        public string terrain { get; set; }        public string intensity { get; set; }        public string gpxId { get; set; }        public string equipmentType { get; set; }        public string durationDesc        {            get            {                return TimeSpan.FromSeconds(duration / 1000).ToReadableString();            }            set { }        }             }    public class Summary    {        public int runs { get; set; }        public float distance { get; set; }        public int runDuration { get; set; }        public float calories { get; set; }        public int duration { get; set; }    }    public static class RunMethods    {        private static string url = "http://nikerunning.nike.com/nikeplus/v1/services/widget/get_public_run_list.jsp";        ///         /// Public method to obtain run data        ///         /// Nike+ ID        /// Run view model, containing run list and summary        public static RunViewModel GetRuns(string id)        {            return new RunViewModel            {                Runs = GetRunList(id),                Summary = GetSummaryInfo(id)            };        }        private static List GetRunList(string id)        {            XmlReaderSettings xrs = new XmlReaderSettings();            xrs.XmlResolver = new XmlUrlResolver();            xrs.ValidationType = ValidationType.DTD;            try            {                using (XmlReader xtr = XmlTextReader.Create(string.Format("{0}?userID={1}", url, id), xrs))                {                    XDocument xd = XDocument.Load(xtr);                    return (from entry in xd.Descendants().Where(x => x.Name == "run")                            select new Run                            {                                startTime = (DateTime)entry.Element("startTime"),                                distance = (float)entry.Element("distance"),                                duration = (int)entry.Element("duration"),                                syncTime = (DateTime)entry.Element("syncTime"),                                calories = (float)entry.Element("calories"),                                name = (string)entry.Element("name"),                                description = (string)entry.Element("description"),                                howFelt = (string)entry.Element("howFelt"),                                weather = (string)entry.Element("weather"),                                terrain = (string)entry.Element("terrain"),                                intensity = (string)entry.Element("intensity"),                                gpxId = (string)entry.Element("gpxId"),                                equipmentType = (string)entry.Element("equipmentType")                            }).OrderByDescending(x => x.startTime).ToList();                    xtr.Close();                }            }            catch (WebException ex)            {                return new List();            }        }        private static Summary GetSummaryInfo(string id)        {            XmlReaderSettings xrs = new XmlReaderSettings();            xrs.XmlResolver = new XmlUrlResolver();            xrs.ValidationType = ValidationType.DTD;            try            {                using (XmlReader xtr = XmlTextReader.Create(string.Format("{0}?userID={1}", url, id), xrs))                {                    XDocument xd = XDocument.Load(xtr);                    return (from entry in xd.Descendants().Descendants("runListSummary")                            select new Summary                            {                                runs = (int)entry.Element("runs"),                                distance = (float)entry.Element("distance"),                                runDuration = (int)entry.Element("runDuration"),                                calories = (float)entry.Element("calories"),                                duration = (int)entry.Element("duration")                            }).FirstOrDefault();                    xtr.Close();                }            }            catch (WebException ex)            {                return new Summary();            }        }    }}

Here’s how to use the data:

RunListViewModel objMyRuns = BlogMVC.Models.RunMethods.GetRuns("14fa3afc-8687-47ef-9899-75e8d090284d")

From here, you can look through your run list and use the objMyRuns.Summary.Item to access the summary data

If you’re wondering what the string extension ToReadableString() looks like, here it is:

 public static string ToReadableString(this TimeSpan span)    {        string formatted = string.Format("{0}{1}{2}{3}",            span.Days > 0 ? string.Format("{0:0}d ", span.Days) : string.Empty,            span.Hours > 0 ? string.Format("{0:0}h ", span.Hours) : string.Empty,            span.Minutes > 0 ? string.Format("{0:0}m ", span.Minutes) : string.Empty,            span.Seconds > 0 ? string.Format("{0:0}s", span.Seconds) : string.Empty);        if (formatted.EndsWith(", ")) formatted = formatted.Substring(0, formatted.Length - 2);        return formatted;    } 

Have fun and here is an example of it in use.

Additional Information: More URLs from the Nike+ API

I haven’t included any tutorial information on the other functionality of the other API URLs, but have listed them below for you to test.

URL Description
https://secure-nikeplus.nike.com/nikeplus/v1/services/widget/generate_pin.jhtml?login=&password= Authenticates the user and places a cookie on their system for later use.
http://secure-nikeplus.nike.com/nikeplus/v1/services/app/get_user_data.jhtml Obtains data about the user (e.g. name, gender, country)
https://secure-nikeplus.nike.com/nikeplus/v1/services/app/goal_list.jhtml List the goals of the selected user
https://secure-nikeplus.nike.com/nikeplus/v1/services/app/run_list.jhtml Lists the users runs and statistics, as used in this post
https://secure-nikeplus.nike.com/nikeplus/v1/services/app/get_run.jhtml?id= A detailed view of the run, including numbers from the run list
https://secure-nikeplus.nike.com/nikeplus/v1/services/widget/get_challenges_for_user.jhtml Lists the user’s challenges
https://secure-nikeplus.nike.com/nikeplus/v1/services/app/personal_records.jhtml Lists the user’s personal records

Leave a Reply