{"_id":"57a21a58cd51b22d00f62389","project":"55773a5ba042551900b002cb","initVersion":{"_id":"55773a5ba042551900b002ce","version":"1"},"user":{"_id":"546d17e2eb9cfd1400dd4529","username":"","name":"World Triathlon"},"__v":0,"createdAt":"2016-08-03T16:22:48.096Z","changelog":[],"body":"For the upcoming [Olympic Games in Rio](https://www.rio2016.com/en/triathlon) we decided to use the Triathlon API to build an application so users could quickly compare the performances of any two athletes in the start lists. \n\nIn this article we will introduce the [application that was developed](https://data.triathlon.org/matchups/female?athlete1=5454&athlete2=15744) (in under a day) in order to demonstrate the various capabilities of the API and to provide an example of the API calls that it uses.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/41d8401-matchup.png\",\n        \"matchup.png\",\n        1061,\n        983,\n        \"#e2e1e7\"\n      ],\n      \"border\": true,\n      \"caption\": \"Olympic Head-to-Head Matchup Simulator\"\n    }\n  ]\n}\n[/block]\n**Extracting Start Lists**\n\nTo begin we need to know the start lists of the different programs in order to populate the corresponding dropdowns so users may choose which athletes to compare.\n\nTo get to the program information we first need to extract the `event_id` of the Rio Olympic Games. The simplest method is to use the **[Search API](https://developers.triathlon.org/docs/search-results)** and we can use the query of `Rio 2016` which returns the 2016 Rio de Janerio Olympic Games as the first result with the `event_id` of 100636.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"curl --header \\\"apikey: YOUR_APP_KEY\\\" \\\"https://api.triathlon.org/v1/search/events?query=2016%20rio\\\"\",\n      \"language\": \"curl\"\n    }\n  ]\n}\n[/block]\nWe now use the `event_id` to find a listing of the programs at the Rio Games.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"curl --header \\\"apikey: YOUR_APP_KEY\\\" \\\"https://api.triathlon.org/v1/events/100636/programs\\\"\",\n      \"language\": \"curl\"\n    }\n  ]\n}\n[/block]\nThis yields the following result:\n\n```\n{\n    \"code\": 200,\n    \"status\": \"success\",\n    \"data\": [\n        {\n            \"prog_id\": 305290,\n            \"event_id\": 100636,\n            \"prog_name\": \"Elite Men\",\n            \"prog_date\": \"2016-08-18\",\n            \"prog_time\": \"11:00:00\",\n            \"prog_notes\": null,\n            \"results\": false,\n            \"team\": false\n        },\n        {\n            \"prog_id\": 305291,\n            \"event_id\": 100636,\n            \"prog_name\": \"Elite Women\",\n            \"prog_date\": \"2016-08-20\",\n            \"prog_time\": \"11:00:00\",\n            \"prog_notes\": null,\n            \"results\": false,\n            \"team\": false\n        }\n    ]\n}\n```\n\nSo our application will use the start lists from the `prog_id` of 305290 for the Elite Men and `305291` for the Elite Women. To extract the start list we simply substitute the `prog_id` into the **[Program Entries](https://developers.triathlon.org/docs/program-entries)** API call:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"curl --header \\\"apikey: YOUR_APP_KEY\\\" \\\"https://api.triathlon.org/v1/events/100636/programs/305290/entries\\\"\",\n      \"language\": \"curl\"\n    }\n  ]\n}\n[/block]\nThe result of this will yield an array of athlete objects which contains the necessary information required to populate our dropdowns to choose the athletes competing in the race. *Note that we only need to execute this once so any results from this response may be cached and only needs to be rerun in the case that the start list is changed prior to the event.*\n\n**Extracting Profile Data**\n\nIn extracting the start lists we have the `athlete_id` for all athletes in the corresponding program which is the unique value we will use to obtain all the remaining info included in the simulator.\n\nThe **[Retrieve Athlete Information](https://developers.triathlon.org/docs/retrieve-athlete-information)** method contains the full profile of the athlete that we will use to extract the primary profile information such as the profile image, representing country, ranking information and summary fields. Using athlete Helen Jenkins (5573) as an example the following query is made to extract her profile:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"curl --header \\\"apikey: YOUR_APP_KEY\\\" \\\"https://api.triathlon.org/v1/athletes/5573\\\"\",\n      \"language\": \"curl\"\n    }\n  ]\n}\n[/block]\nAs well as the basic profile information the result also contains a `stats` object that details the information required for the 'Career Stats' section of the simulator.\n\n```\n\"stats\": {\n      \"race_starts\": 69,\n      \"race_finishes\": 66,\n      \"finish_percentage\": 96,\n      \"race_wins\": 8,\n      \"race_podiums\": 29,\n      \"race_podium_percentage\": 42\n}\n```\n\n**Olympic Head-to-Head Stats**\n\nThe above stats block includes all ITU races that Helen Jenkins has competed in and so to retrieve the specific Olympic stats we use the **[Athlete Statistics](https://developers.triathlon.org/docs/athlete-statistics)** method using the `event_id` parameter to limit only to Olympic Games. As there are only 4 prior Games we simply use the **[Search API](https://developers.triathlon.org/docs/search-results)** to extract the `event_id` of each and pass this pipe delimited list of `event_ids` to the athlete statistics method\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"curl --header \\\"apikey: YOUR_APP_KEY\\\" \\\"https://api.triathlon.org/v1/athletes/5573/stats?event_id=4740|4529|4998|60952\\\"\",\n      \"language\": \"curl\"\n    }\n  ]\n}\n[/block]\nThis will return a similar stats data object which contains only those starts, finishes, wins and podiums related to the prior Olympic Games.\n\nTo obtain all the Olympic results for an athlete we will use the **[Athlete Results](https://developers.triathlon.org/docs/athlete-results)** method again limiting the `event_ids` to only Olympic Games results which will return an array of result objects.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"curl --header \\\"apikey: YOUR_APP_KEY\\\" \\\"https://api.triathlon.org/v1/athletes/5573/results?event_id=4740|4529|4998|60952\\\"\",\n      \"language\": \"curl\"\n    }\n  ]\n}\n[/block]\n**WTS Head-to-Head Stats**\n[block:callout]\n{\n  \"type\": \"warning\",\n  \"title\": \"Make use of a cache to improve the performance of your application\",\n  \"body\": \"Most of the API calls made can benefit from caching as the information changes infrequently. In particular the matchups endpoint is resource intensive (and correspondingly slow) and will benefit the most from caching any requests to it.\"\n}\n[/block]\nTo extract the WTS head-to-head matchups we turn to the dedicated **[Matchups Endpoint](https://developers.triathlon.org/docs/matchups)** of the Statistics API passing in the relevant `athlete_ids` (in the following example Helen Jenkins and Gwen Jorgenson). The result of this API call will return the number of times the athletes have met in WTS races, basic WTS race stats for both athletes and a list of all times the athletes have competed together (and corresponding results), from which we may derive the latest head-to_head result.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"curl --header \\\"apikey: YOUR_APP_KEY\\\" \\\"https://api.triathlon.org/v1/statistics/matchups?athletes=athlete.id,in,40887,5573\\\"\",\n      \"language\": \"curl\"\n    }\n  ]\n}\n[/block]\nThe only missing pieces of information are the WTS best finish and the WTS best 10km run time which are not currently included in the matchup response. To obtain both we use the **[Results](https://developers.triathlon.org/docs/search-results)** method of the Statistics API. For the best finish we simply find the minimum `position` for an athlete from all WTS results:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"curl --header \\\"apikey: YOUR_APP_KEY\\\" \\\"https://api.triathlon.org/v1/statistics/results?analysis=minimum&target_property=position&filters=athlete.id,eq,5573\\\"\",\n      \"language\": \"curl\"\n    }\n  ]\n}\n[/block]\nFinally, to extract the best 10km run time we find the minimum of the `splits.run` property specifying filters for a `Standard` distance format and apply a sanity check that the run time must be greater than 1600 seconds (or about 26 minutes). This check removes events such as 2013 [Kitzbuehel ](http://wts.triathlon.org/results/result/2013_itu_world_triathlon_kitzbuehel/259526) which used a different format despite being classified as a `Standard` distance.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"curl --header \\\"apikey: YOUR_APP_KEY\\\" \\\"https://api.triathlon.org/v1/statistics/results?collection=results&analysis=minimum&target_property=splits.run&filters=athlete.id,eq,5573|format,eq,Standard|splits.run,gt,1600\\\"\",\n      \"language\": \"curl\"\n    }\n  ]\n}\n[/block]\nThis will yield the following result for Helen Jenkins with the result being returned in seconds. This may be easily converted to a time such as in PHP using a simple function such as `gmdate(\"i:s\", $run_time)` \n\n```\n{\n   \"code\":200,\n   \"status\":\"success\",\n   \"data\":{\n      \"result\":1981\n   }\n}\n```\n\nWhilst there are many approaches to extracting the information on the [Head-to-Head simulator](https://data.triathlon.org/matchups/female?athlete1=11133&athlete2=5573) this post details the methodology we used to develop the dynamic tool. To test any of the queries or to build your own application simply [sign up for a free API key](https://apps.api.triathlon.org/register) to access the entrire Triathlon API.","slug":"scaffolding-the-olympic-head-to-head-simulator","title":"Scaffolding the Olympic Head-to-Head Simulator"}

Scaffolding the Olympic Head-to-Head Simulator


For the upcoming [Olympic Games in Rio](https://www.rio2016.com/en/triathlon) we decided to use the Triathlon API to build an application so users could quickly compare the performances of any two athletes in the start lists. In this article we will introduce the [application that was developed](https://data.triathlon.org/matchups/female?athlete1=5454&athlete2=15744) (in under a day) in order to demonstrate the various capabilities of the API and to provide an example of the API calls that it uses. [block:image] { "images": [ { "image": [ "https://files.readme.io/41d8401-matchup.png", "matchup.png", 1061, 983, "#e2e1e7" ], "border": true, "caption": "Olympic Head-to-Head Matchup Simulator" } ] } [/block] **Extracting Start Lists** To begin we need to know the start lists of the different programs in order to populate the corresponding dropdowns so users may choose which athletes to compare. To get to the program information we first need to extract the `event_id` of the Rio Olympic Games. The simplest method is to use the **[Search API](https://developers.triathlon.org/docs/search-results)** and we can use the query of `Rio 2016` which returns the 2016 Rio de Janerio Olympic Games as the first result with the `event_id` of 100636. [block:code] { "codes": [ { "code": "curl --header \"apikey: YOUR_APP_KEY\" \"https://api.triathlon.org/v1/search/events?query=2016%20rio\"", "language": "curl" } ] } [/block] We now use the `event_id` to find a listing of the programs at the Rio Games. [block:code] { "codes": [ { "code": "curl --header \"apikey: YOUR_APP_KEY\" \"https://api.triathlon.org/v1/events/100636/programs\"", "language": "curl" } ] } [/block] This yields the following result: ``` { "code": 200, "status": "success", "data": [ { "prog_id": 305290, "event_id": 100636, "prog_name": "Elite Men", "prog_date": "2016-08-18", "prog_time": "11:00:00", "prog_notes": null, "results": false, "team": false }, { "prog_id": 305291, "event_id": 100636, "prog_name": "Elite Women", "prog_date": "2016-08-20", "prog_time": "11:00:00", "prog_notes": null, "results": false, "team": false } ] } ``` So our application will use the start lists from the `prog_id` of 305290 for the Elite Men and `305291` for the Elite Women. To extract the start list we simply substitute the `prog_id` into the **[Program Entries](https://developers.triathlon.org/docs/program-entries)** API call: [block:code] { "codes": [ { "code": "curl --header \"apikey: YOUR_APP_KEY\" \"https://api.triathlon.org/v1/events/100636/programs/305290/entries\"", "language": "curl" } ] } [/block] The result of this will yield an array of athlete objects which contains the necessary information required to populate our dropdowns to choose the athletes competing in the race. *Note that we only need to execute this once so any results from this response may be cached and only needs to be rerun in the case that the start list is changed prior to the event.* **Extracting Profile Data** In extracting the start lists we have the `athlete_id` for all athletes in the corresponding program which is the unique value we will use to obtain all the remaining info included in the simulator. The **[Retrieve Athlete Information](https://developers.triathlon.org/docs/retrieve-athlete-information)** method contains the full profile of the athlete that we will use to extract the primary profile information such as the profile image, representing country, ranking information and summary fields. Using athlete Helen Jenkins (5573) as an example the following query is made to extract her profile: [block:code] { "codes": [ { "code": "curl --header \"apikey: YOUR_APP_KEY\" \"https://api.triathlon.org/v1/athletes/5573\"", "language": "curl" } ] } [/block] As well as the basic profile information the result also contains a `stats` object that details the information required for the 'Career Stats' section of the simulator. ``` "stats": { "race_starts": 69, "race_finishes": 66, "finish_percentage": 96, "race_wins": 8, "race_podiums": 29, "race_podium_percentage": 42 } ``` **Olympic Head-to-Head Stats** The above stats block includes all ITU races that Helen Jenkins has competed in and so to retrieve the specific Olympic stats we use the **[Athlete Statistics](https://developers.triathlon.org/docs/athlete-statistics)** method using the `event_id` parameter to limit only to Olympic Games. As there are only 4 prior Games we simply use the **[Search API](https://developers.triathlon.org/docs/search-results)** to extract the `event_id` of each and pass this pipe delimited list of `event_ids` to the athlete statistics method [block:code] { "codes": [ { "code": "curl --header \"apikey: YOUR_APP_KEY\" \"https://api.triathlon.org/v1/athletes/5573/stats?event_id=4740|4529|4998|60952\"", "language": "curl" } ] } [/block] This will return a similar stats data object which contains only those starts, finishes, wins and podiums related to the prior Olympic Games. To obtain all the Olympic results for an athlete we will use the **[Athlete Results](https://developers.triathlon.org/docs/athlete-results)** method again limiting the `event_ids` to only Olympic Games results which will return an array of result objects. [block:code] { "codes": [ { "code": "curl --header \"apikey: YOUR_APP_KEY\" \"https://api.triathlon.org/v1/athletes/5573/results?event_id=4740|4529|4998|60952\"", "language": "curl" } ] } [/block] **WTS Head-to-Head Stats** [block:callout] { "type": "warning", "title": "Make use of a cache to improve the performance of your application", "body": "Most of the API calls made can benefit from caching as the information changes infrequently. In particular the matchups endpoint is resource intensive (and correspondingly slow) and will benefit the most from caching any requests to it." } [/block] To extract the WTS head-to-head matchups we turn to the dedicated **[Matchups Endpoint](https://developers.triathlon.org/docs/matchups)** of the Statistics API passing in the relevant `athlete_ids` (in the following example Helen Jenkins and Gwen Jorgenson). The result of this API call will return the number of times the athletes have met in WTS races, basic WTS race stats for both athletes and a list of all times the athletes have competed together (and corresponding results), from which we may derive the latest head-to_head result. [block:code] { "codes": [ { "code": "curl --header \"apikey: YOUR_APP_KEY\" \"https://api.triathlon.org/v1/statistics/matchups?athletes=athlete.id,in,40887,5573\"", "language": "curl" } ] } [/block] The only missing pieces of information are the WTS best finish and the WTS best 10km run time which are not currently included in the matchup response. To obtain both we use the **[Results](https://developers.triathlon.org/docs/search-results)** method of the Statistics API. For the best finish we simply find the minimum `position` for an athlete from all WTS results: [block:code] { "codes": [ { "code": "curl --header \"apikey: YOUR_APP_KEY\" \"https://api.triathlon.org/v1/statistics/results?analysis=minimum&target_property=position&filters=athlete.id,eq,5573\"", "language": "curl" } ] } [/block] Finally, to extract the best 10km run time we find the minimum of the `splits.run` property specifying filters for a `Standard` distance format and apply a sanity check that the run time must be greater than 1600 seconds (or about 26 minutes). This check removes events such as 2013 [Kitzbuehel ](http://wts.triathlon.org/results/result/2013_itu_world_triathlon_kitzbuehel/259526) which used a different format despite being classified as a `Standard` distance. [block:code] { "codes": [ { "code": "curl --header \"apikey: YOUR_APP_KEY\" \"https://api.triathlon.org/v1/statistics/results?collection=results&analysis=minimum&target_property=splits.run&filters=athlete.id,eq,5573|format,eq,Standard|splits.run,gt,1600\"", "language": "curl" } ] } [/block] This will yield the following result for Helen Jenkins with the result being returned in seconds. This may be easily converted to a time such as in PHP using a simple function such as `gmdate("i:s", $run_time)` ``` { "code":200, "status":"success", "data":{ "result":1981 } } ``` Whilst there are many approaches to extracting the information on the [Head-to-Head simulator](https://data.triathlon.org/matchups/female?athlete1=11133&athlete2=5573) this post details the methodology we used to develop the dynamic tool. To test any of the queries or to build your own application simply [sign up for a free API key](https://apps.api.triathlon.org/register) to access the entrire Triathlon API.