From a117c5b566eee7a6a811d56a9372d377b116002a Mon Sep 17 00:00:00 2001 From: "Daniel (dB.) Doubrovkine" Date: Thu, 16 Oct 2025 10:01:09 -0400 Subject: [PATCH 1/3] Respect Faraday::Response::RaiseError::DEFAULT_OPTIONS when raising errors. --- .rubocop_todo.yml | 13 +- CHANGELOG.md | 3 +- Gemfile | 1 + lib/strava/errors/ratelimit_error.rb | 26 +-- lib/strava/web/raise_response_error.rb | 25 ++- .../activity_with_ratelimit_exceeded.yml | 175 +----------------- .../endpoints/activities/activity_spec.rb | 15 -- spec/strava/api/client_spec.rb | 48 +++++ 8 files changed, 82 insertions(+), 224 deletions(-) diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index d349f1d..52fe0c4 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -1,17 +1,15 @@ # This configuration was generated by # `rubocop --auto-gen-config` -# on 2025-02-02 03:09:26 UTC using RuboCop version 1.68.0. +# on 2025-10-16 14:00:36 UTC using RuboCop version 1.68.0. # The point is for the user to remove these configuration records # one by one as the offenses are removed from the code base. # Note that changes in the inspected code, or installation of new # versions of RuboCop, may require this file to be generated again. # Offense count: 1 -# Configuration parameters: AllowedPatterns. -# AllowedPatterns: (?-mix:(exactly|at_least|at_most)\(\d+\)\.times) -Lint/UnreachableLoop: +RSpec/AnyInstance: Exclude: - - 'bin/strava-activities.rb' + - 'spec/strava/api/client_spec.rb' # Offense count: 13 # This cop supports unsafe autocorrection (--autocorrect-all). @@ -23,11 +21,6 @@ RSpec/DescribedClass: - 'spec/strava/oauth/client_spec.rb' - 'spec/strava/webhooks/client_spec.rb' -# Offense count: 1 -RSpec/MultipleDescribes: - Exclude: - - 'spec/strava/api/client/endpoints/activities/activity_spec.rb' - # Offense count: 5 # Configuration parameters: AllowedGroups. RSpec/NestedGroups: diff --git a/CHANGELOG.md b/CHANGELOG.md index 9791cac..911969a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,8 @@ ### 2.3.0 (Next) +* [#91](https://github.com/dblock/strava-ruby-client/pull/91): Respects `Faraday::Response::RaiseError::DEFAULT_OPTIONS` when raising errors - [@dblock](https://github.com/dblock). * [#87](https://github.com/dblock/strava-ruby-client/pull/87): Prepares v2.3.0 by improving the event specs - [@simonneutert](https://github.com/simonneutert). -* [#86](https://github.com/dblock/strava-ruby-client/pull/86): Add description to club event model - [@tobiaszwaszak](https://github.com/tobiaszwaszak). +* [#86](https://github.com/dblock/strava-ruby-client/pull/86): Adds description to club event model - [@tobiaszwaszak](https://github.com/tobiaszwaszak). * Your contribution here. ### 2.2.0 (2024/9/17) diff --git a/Gemfile b/Gemfile index 1ba87dc..ce9c024 100755 --- a/Gemfile +++ b/Gemfile @@ -5,6 +5,7 @@ source 'http://rubygems.org' gemspec group :development, :test do + gem 'csv' gem 'dotenv' gem 'faraday-retry' gem 'gpx' diff --git a/lib/strava/errors/ratelimit_error.rb b/lib/strava/errors/ratelimit_error.rb index e7434f6..a178332 100644 --- a/lib/strava/errors/ratelimit_error.rb +++ b/lib/strava/errors/ratelimit_error.rb @@ -3,29 +3,11 @@ module Strava module Errors class RatelimitError < ::Faraday::ClientError - attr_reader :http_response, :ratelimit, :error_message + attr_reader :ratelimit - def initialize(http_response, error_message = nil) - @response = http_response.response - @ratelimit = Strava::Api::Ratelimit.new(@response) - @error_message = error_message || message - super({ - status: http_response.status, - headers: http_response.response_headers, - body: http_response.body - }) - end - - def message - response[:body]['message'] || super - end - - def headers - response[:headers] - end - - def errors - response[:body]['errors'] + def initialize(env, response) + @ratelimit = Strava::Api::Ratelimit.new(env.response) + super(response) end end end diff --git a/lib/strava/web/raise_response_error.rb b/lib/strava/web/raise_response_error.rb index 45f309c..5ad56a4 100644 --- a/lib/strava/web/raise_response_error.rb +++ b/lib/strava/web/raise_response_error.rb @@ -3,6 +3,7 @@ module Strava module Web class RaiseResponseError < ::Faraday::Middleware + DEFAULT_OPTIONS = Faraday::Response::RaiseError::DEFAULT_OPTIONS CLIENT_ERROR_STATUSES = (400...600) def on_complete(env) @@ -13,18 +14,38 @@ def on_complete(env) # mimic the behavior that we get with proxy requests with HTTPS raise Faraday::ConnectionFailed, %(407 "Proxy Authentication Required ") when 429 - raise Strava::Errors::RatelimitError.new(env, 'Too Many Requests') + raise Strava::Errors::RatelimitError.new(env, response_values(env)) when CLIENT_ERROR_STATUSES raise Strava::Errors::Fault, response_values(env) end end def response_values(env) - { + response = { status: env.status, headers: env.response_headers, body: env.body } + + # Include the request data by default. If the middleware was explicitly + # configured to _not_ include request data, then omit it. + return response unless options[:include_request] + + response.merge( + request: { + method: env.method, + url: env.url, + url_path: env.url.path, + params: query_params(env), + headers: env.request_headers, + body: env.request_body + } + ) + end + + def query_params(env) + env.request.params_encoder ||= Faraday::Utils.default_params_encoder + env.params_encoder.decode(env.url.query) end end end diff --git a/spec/fixtures/strava/client/activity_with_ratelimit_exceeded.yml b/spec/fixtures/strava/client/activity_with_ratelimit_exceeded.yml index 6d67a3e..485b372 100644 --- a/spec/fixtures/strava/client/activity_with_ratelimit_exceeded.yml +++ b/spec/fixtures/strava/client/activity_with_ratelimit_exceeded.yml @@ -52,180 +52,7 @@ http_interactions: - 1; mode=block body: encoding: UTF-8 - string: '{"resource_state":3,"athlete":{"id":26462176,"resource_state":1},"name":"TCS - NYC Marathon 2018","distance":42268.1,"moving_time":13085,"elapsed_time":13333,"total_elevation_gain":270.9,"type":"Run","sport_type":"Run","workout_type":1,"id":1946417534,"external_id":"17900304917.tcx","upload_id":2082412856,"start_date":"2018-11-04T14:53:46Z","start_date_local":"2018-11-04T09:53:46Z","timezone":"(GMT-05:00) - America/New_York","utc_offset":-18000.0,"start_latlng":[40.6,-74.06],"end_latlng":[40.77,-73.98],"location_city":null,"location_state":null,"location_country":"","start_latitude":40.6,"start_longitude":-74.06,"achievement_count":7,"kudos_count":33,"comment_count":8,"athlete_count":301,"photo_count":0,"map":{"id":"a1946417534","polyline":"aayvFjz_cMCcBIqA{@_EY}@q@sCYeBYoAg@iBW_Be@gBo@oDm@mCMu@GU[s@e@wCq@oCQaAqCqLU}@WoASs@cAeF[qAc@{Ac@mBe@gCa@aBiAsFc@eBk@iBUyA{@qDo@wC_@{AWwAW_Ay@{DgAuESeAy@yDkAgFWy@e@uBe@aBYw@c@cAg@aAYc@iAgA_CeB{AqA}@gAiA_Ba@_@gAsAi@_@sAg@m@c@wBsBi@_@q@[q@Si@YQCKDQVc@~@GT@TLXx@hAdCbCHNBNu@hBo@nB_A|BKLOHU@YCe@Ky@[mA[w@[_Do@}@]s@Os@Wo@Qu@[uAY}CiAy@_@WG{@MyCgAe@Mu@[iA]g@I}@c@aCc@_Bu@eA_@s@Mc@Ow@Qw@[aASw@YeAYo@GSGo@W_@Kk@UyCy@gAi@}@]uAYi@Q{@M_@IUKk@[o@ImCaAgAW}FqBeAW}Ag@sCo@}@_@uAc@mAk@wAuAiAwAcAaAOK]KUM]IYW]c@c@{@_@i@}@{@_AmAkAeAm@u@m@k@qAeB{@y@w@aAsBsB_A{@[m@s@cAe@o@[Y_@k@g@c@i@_@q@{@_Aw@mAuAYS[[g@Yu@w@m@q@_@m@w@m@UU]y@w@m@QSWe@uAgAa@k@m@i@o@u@a@m@uA_Bk@c@}@aAo@c@}@}@}CuD}@w@gDmDkAwAiA_AqBeCiBgBg@s@oAuAg@a@cAcAkB{AaAqAa@a@a@[k@_A{@u@aCeCkAwAgAiAs@q@_@m@g@a@a@o@oAmAgAmAwAiA}@oAs@u@_@_@g@_@y@}@m@]s@e@e@{@k@g@k@}@u@y@e@[Wg@uAkAi@y@u@o@s@}@i@Wa@o@w@y@q@k@wAwB]O_Co@OKk@o@WSYM}@WgAs@IYI}@IKcAm@KK]i@c@[e@e@i@]i@Uu@a@c@o@QOoAs@_@u@UMKMO]UWy@k@eAg@_@Wa@OUM]i@UUk@Yu@g@e@s@m@SKSMa@KMw@_@u@u@[UkBoAo@[k@_@KK_@g@_CqB}@m@g@c@qCcBc@[q@_@_AYGIYq@kAy@]QaA[c@S{@q@kB}@o@a@QGk@Ig@g@SOo@S[Oa@q@g@Sq@MIGOUSSuAs@c@k@cBk@u@k@a@a@i@S_@_@q@c@kEkB_B_@c@E[FuDdBm@Nw@b@K@ECEQ@m@GaBUoCHmAA]c@kDOyBEsAOuAYaDHkBGgBOaBCy@WqBCwAW_Ck@sKa@eD@gBMqAOoDQwB}@gQGm@GsAEiDQyAUoCIe@Y{@BDIsABwBGoBYqDSkEI]KOWGwAKs@JwALqAVQ?{@I_AHi@HaCj@y@@{Ab@{@@{@Dw@Ru@F_@F{@VcBXK?m@GK@{Bv@O@c@Gk@Jw@Tg@@cAJcA?cAX[PIBo@Cy@Pi@BaAL]?{@Em@JwAf@c@`@m@`@i@`A}A`BsAfB_@\\a@b@y@n@oAfB]f@cAdAgArBQVo@p@kAv@_A`Ag@r@k@bAkBdCeBzAk@`@a@R_@Ds@?o@Ek@AuB[y@YYEi@CgASW?UDS@s@GKCk@]c@KUKgBaAc@Ow@Qa@Q[U]]]OW]c@Sm@[o@Q{@_@wAgAk@Uc@[e@Uy@u@[g@g@][Yg@eAS[gBsAc@m@wA{A}AsAu@cA_Ay@_@o@sAsAa@o@iA_AWe@s@{@iBeBo@_@_@c@YSa@e@g@c@cAgBoBcCk@o@u@m@eAaAkBmBcB_Cy@}BMOMIK@cAXe@Xe@L{@Zi@PeAl@eA^gAf@mA`@qAt@uB`Aq@^u@h@aAl@aBl@s@\\mAVyAf@ICGKKk@WsGGm@CuAI]GGKCqA^sBX{@Rs@Bw@Aq@JgA?o@NiCTo@Js@F}@Lw@Re@FmE^wDVmBRs@?m@Cu@Sq@Iu@QmA_@iBe@_AOcBg@sDq@iCm@_Cw@w@Ma@?WBKDMLIPI^SlBO|@]~CMTGDG@a@EkAGUEcCm@gBo@uEy@wBk@s@MUKQMi@k@cAo@IOAUHu@Z}BD_BTgA@OE}@FaAf@eCZ{@PyA@}@EmA@eAIm@@SJ]l@gAHUBc@AMCEAGFs@DU^s@Z_C?i@KaAAiAQyA?gAIWm@oAOI_@Ik@o@GSEs@_@Lg@D{BCo@GWK]YIMe@aAKMMCQJ]f@mAfAu@x@c@r@q@zAW~@[tAy@tBUbAOz@m@pAQp@Yt@YdAe@bAw@pBa@tBg@`BCb@]tBSp@Ox@]jA]r@sAtBY`A[|@G^At@Oj@Kv@GVw@rAa@|AcDhIg@bBgBdEi@~AWz@a@pBWbAmAvD_AbCQn@e@xBa@hBc@vCQ|@w@dCiA|CMb@ARL[Ns@\\uAFg@BGB@c@iBMEc@_@[u@SW_@McA?[Gq@WaBu@_@Ye@k@QIk@Ka@W_@e@cAk@[[cAw@[o@IGIAE@m@VO@SKg@e@o@GOEMOi@}@m@i@a@g@QM_@}@KEo@EIEGQKe@GGIAK@q@VQAMKYc@OMWCm@BSAc@S[]a@YOEc@AUGGKIcAO_AGOKImAm@aASSI{A{Ag@[k@e@q@]gAa@c@WiAgA]e@WUOGeAGQE_@W_@]}@[Qq@Qc@e@Kc@[qAk@cBwAaCsCKISKg@Kk@Io@Y[SoAkAwAk@s@[k@_@aAw@k@[c@McCa@eC}@wAgAUYOKMSECa@eAEIGGsAa@OC[Bs@L_A^c@JU@[A[M[YCEQm@]y@[_AAYFkAAc@OeAISQUw@c@gAc@iBm@s@[eBuAm@YW[]o@Y[s@a@eAS_Ae@]WuAmAi@}@W[w@c@w@kAWKk@OqAS_@OSQ]c@c@_@}@iASO]O_DsA_Ak@m@g@s@u@aAm@e@q@Y[q@Yk@a@aAk@YI_AI[Q_@Us@q@iAq@_BwAq@c@y@q@qA[e@S]Ia@Q]Yi@QWM[[a@u@o@m@m@[aAo@a@Mc@SqAiAwBwA_Bi@c@WgCuB}@}@{@o@qBmAqAm@i@[g@i@sAeByB_Ec@iAmA_E_@eA{AaD]y@{AqC_@e@k@i@eAu@q@i@kAu@iB_AWCI@KFS\\[|@gBrFOPOFWCu@QsAU]Qq@m@a@QQGm@Iw@QG@KHKNkAnCi@vAKNKDG?QGs@g@a@Sg@O_AQmBeAYG[EM@MFMNGNSt@Cj@Jf@Vf@`@b@pA|@xA|APXDP?LM\\Wb@qBlCIRSn@Uh@wApBi@jAm@`Bm@jCK`ACd@@hABj@Fp@Bf@GlASzAUxAmAxDAN@THVLJl@Zf@b@x@l@r@`@v@t@zAr@~@j@r@`@~@fAr@h@lCxAn@d@fA|@f@RfAt@z@h@`@\\\\TxAt@j@j@bAf@hAnATNr@V^Vf@Rd@\\`@f@b@Xr@Zd@b@h@`@LT@RELc@fAI~@k@bBAXFTLLj@`@^`@hBzAn@\\r@h@r@RdAr@PDJCfAiA\\m@f@oAHKHAj@R|@BRFl@d@t@^VXrAfA~@f@XVr@d@x@\\v@dALJt@^~@l@`A`@nAz@|@^JHZd@`@Nr@j@f@Xd@\\r@NJDn@r@VPn@Z^V^Hb@TxAdAh@h@`@Vt@Zf@b@lBlAhCzAr@n@rBnAj@`@b@Pz@n@`@`@^Nb@ZZN^\\^f@\\Zr@Z\\V^Nh@f@`Bt@pAbAdAb@z@x@hBlAZ\\r@f@p@^t@RXT`@P\\b@p@f@d@f@d@Lt@j@d@Xh@P`@Jd@Rf@r@b@X`Az@FPPdAT\\dAh@`Ar@\\Zn@Tr@h@dAp@dAt@t@~@Zz@HlA?l@I~@CrA@vABXLt@Pf@Rv@Rb@HJvAjA`Ap@XL\\DLDzCrBj@b@PR`AfBp@n@z@h@t@h@PHp@H^Hz@Bp@JTH~@j@r@Z\\Bl@IVHHHj@`An@`B^n@nArA\\Pr@Nz@AlAIj@Wf@Eb@?z@Bv@Rf@RJJZh@h@n@r@hBX^p@lARVb@Xj@Hj@NPJLJh@z@LZ\\pAF^HT^f@XRdC|@zA\\^F~AEnAMXMd@_@lBe@X?f@JzAf@TNtAbBVTFVIlA[x@YxA]n@Wp@a@r@c@tAy@lBM`@Wn@Kj@Y`A[n@oA`EWl@QXKf@uD~Js@@MEEO?a@","resource_state":3,"summary_polyline":"aayvFjz_cMyu@_lDwS}VyNgI{@bCzEfGeDvIkATe{Bwq@uoDcxDqKiFmQ{Qka@g[so@i`@oIqCiI~CmPgsCucAhK{g@rj@cSaAm[yP_x@a~@se@dS_B}Nim@jG_a@wIeDrLgWqFkCoCzCgWIsGhCyL_@wIaDsFsFF_CgCiGdIiVfz@wLd[aOrj@jAsEeC}EsGcBoKqIiEe@{G}HwKeCu@iDwYmPqL_LwYeMaE}EeJHsCaM{wByuA}Qm_@oGeFwCy@wDhJsK_DeDvGmLoCEtCvFtG{J|QgDr\\zu@fh@{@`JdLtHbDwEfC\\tlB`nA|D~FjM`JhBzRdTvP~LbCvFdIlMNbP|TrGbBdJgBfG|Dw@xFoQhf@qAc@"},"trainer":false,"commute":false,"manual":false,"private":false,"visibility":"everyone","flagged":false,"gear_id":"g3423618","from_accepted_tag":false,"average_speed":3.17,"max_speed":5.6,"has_heartrate":true,"average_heartrate":170.1,"max_heartrate":187.0,"heartrate_opt_out":false,"display_hide_heartrate_option":false,"elev_high":54.7,"elev_low":-8.1,"pr_count":0,"total_photo_count":9,"has_kudoed":false,"suffer_score":656,"description":"Official - time 3:42:02. Race got impossibly hard at mile 21 but I never stopped except - to pee on mile 9. \r\n\r\nI am so fucking happy that I did this!","calories":3760.0,"segment_efforts":[{"id":49065850796,"resource_state":2,"name":"NYC - Marathon Mile 1","activity":{"id":1946417534,"resource_state":1},"athlete":{"id":26462176,"resource_state":1},"elapsed_time":461,"moving_time":461,"start_date":"2018-11-04T14:53:46Z","start_date_local":"2018-11-04T09:53:46Z","distance":1499.5,"start_index":0,"end_index":462,"average_heartrate":161.1,"max_heartrate":169.0,"segment":{"id":8457023,"resource_state":2,"name":"NYC - Marathon Mile 1","activity_type":"Run","distance":1558.7,"average_grade":-2.1,"maximum_grade":8.2,"elevation_high":34.9,"elevation_low":-0.4,"start_latlng":[40.601918,-74.06061],"end_latlng":[40.607072,-74.043591],"start_latitude":40.601918,"start_longitude":-74.06061,"end_latitude":40.607072,"end_longitude":-74.043591,"climb_category":0,"city":"Staten - Island","state":"New York","country":"United States","private":false,"hazardous":false,"starred":false},"kom_rank":null,"pr_rank":null,"achievements":[],"hidden":false},{"id":49065850820,"resource_state":2,"name":"Verrazano-Narrows - Bridge","activity":{"id":1946417534,"resource_state":1},"athlete":{"id":26462176,"resource_state":1},"elapsed_time":821,"moving_time":821,"start_date":"2018-11-04T14:53:46Z","start_date_local":"2018-11-04T09:53:46Z","distance":2766.4,"start_index":0,"end_index":823,"average_heartrate":159.7,"max_heartrate":169.0,"segment":{"id":6261626,"resource_state":2,"name":"Verrazano-Narrows - Bridge","activity_type":"Run","distance":2825.1,"average_grade":-0.8,"maximum_grade":11.3,"elevation_high":34.5,"elevation_low":-0.1,"start_latlng":[40.601931,-74.060544],"end_latlng":[40.612209,-74.030438],"start_latitude":40.601931,"start_longitude":-74.060544,"end_latitude":40.612209,"end_longitude":-74.030438,"climb_category":0,"city":"Richmond, - NY, USA","state":"NY","country":"United States","private":false,"hazardous":false,"starred":false},"kom_rank":null,"pr_rank":null,"achievements":[],"hidden":false},{"id":49065850842,"resource_state":2,"name":"NYC - Marathon Mile 2 Orange \u0026 Green","activity":{"id":1946417534,"resource_state":1},"athlete":{"id":26462176,"resource_state":1},"elapsed_time":491,"moving_time":491,"start_date":"2018-11-04T15:01:39Z","start_date_local":"2018-11-04T10:01:39Z","distance":1721.1,"start_index":474,"end_index":967,"average_heartrate":156.2,"max_heartrate":168.0,"segment":{"id":8457018,"resource_state":2,"name":"NYC - Marathon Mile 2 Orange \u0026 Green","activity_type":"Run","distance":1714.9,"average_grade":0.9,"maximum_grade":9.8,"elevation_high":15.6,"elevation_low":0.0,"start_latlng":[40.607216,-74.043134],"end_latlng":[40.61584,-74.027201],"start_latitude":40.607216,"start_longitude":-74.043134,"end_latitude":40.61584,"end_longitude":-74.027201,"climb_category":0,"city":"New - York","state":"New York","country":"United States","private":false,"hazardous":false,"starred":false},"kom_rank":null,"pr_rank":null,"achievements":[],"hidden":false},{"id":49065850867,"resource_state":2,"name":"NYC - Marathon Mile 3 Orange","activity":{"id":1946417534,"resource_state":1},"athlete":{"id":26462176,"resource_state":1},"elapsed_time":432,"moving_time":432,"start_date":"2018-11-04T15:09:46Z","start_date_local":"2018-11-04T10:09:46Z","distance":1533.3,"start_index":963,"end_index":1396,"average_heartrate":169.6,"max_heartrate":176.0,"segment":{"id":8457010,"resource_state":2,"name":"NYC - Marathon Mile 3 Orange","activity_type":"Run","distance":1529.2,"average_grade":0.5,"maximum_grade":4.4,"elevation_high":22.8,"elevation_low":15.3,"start_latlng":[40.615717,-74.027267],"end_latlng":[40.625286,-74.027256],"start_latitude":40.615717,"start_longitude":-74.027267,"end_latitude":40.625286,"end_longitude":-74.027256,"climb_category":0,"city":"Brooklyn","state":"New - York","country":"United States","private":false,"hazardous":false,"starred":false},"kom_rank":null,"pr_rank":null,"achievements":[],"hidden":false},{"id":49065850890,"resource_state":2,"name":"NYC - Marathon Mile 4 Orange \u0026 Blue","activity":{"id":1946417534,"resource_state":1},"athlete":{"id":26462176,"resource_state":1},"elapsed_time":462,"moving_time":462,"start_date":"2018-11-04T15:16:58Z","start_date_local":"2018-11-04T10:16:58Z","distance":1653.2,"start_index":1396,"end_index":1860,"average_heartrate":170.3,"max_heartrate":174.0,"segment":{"id":8456833,"resource_state":2,"name":"NYC - Marathon Mile 4 Orange \u0026 Blue","activity_type":"Run","distance":1651.7,"average_grade":0.1,"maximum_grade":7.4,"elevation_high":24.9,"elevation_low":14.1,"start_latlng":[40.625286,-74.027256],"end_latlng":[40.639056,-74.020409],"start_latitude":40.625286,"start_longitude":-74.027256,"end_latitude":40.639056,"end_longitude":-74.020409,"climb_category":0,"city":"Brooklyn","state":"New - York","country":"United States","private":false,"hazardous":false,"starred":false},"kom_rank":null,"pr_rank":null,"achievements":[],"hidden":false},{"id":49065850915,"resource_state":2,"name":"NYC - Marathon Mile 5","activity":{"id":1946417534,"resource_state":1},"athlete":{"id":26462176,"resource_state":1},"elapsed_time":443,"moving_time":443,"start_date":"2018-11-04T15:24:40Z","start_date_local":"2018-11-04T10:24:40Z","distance":1583.2,"start_index":1860,"end_index":2305,"average_heartrate":171.2,"max_heartrate":176.0,"segment":{"id":8456852,"resource_state":2,"name":"NYC - Marathon Mile 5","activity_type":"Run","distance":1564.9,"average_grade":-0.2,"maximum_grade":2.3,"elevation_high":28.3,"elevation_low":20.3,"start_latlng":[40.639056,-74.020409],"end_latlng":[40.650112,-74.008914],"start_latitude":40.639056,"start_longitude":-74.020409,"end_latitude":40.650112,"end_longitude":-74.008914,"climb_category":0,"city":"Brooklyn","state":"New - York","country":"United States","private":false,"hazardous":false,"starred":false},"kom_rank":null,"pr_rank":null,"achievements":[],"hidden":false},{"id":49065850937,"resource_state":2,"name":"NYC - Marathon Mile 6","activity":{"id":1946417534,"resource_state":1},"athlete":{"id":26462176,"resource_state":1},"elapsed_time":508,"moving_time":508,"start_date":"2018-11-04T15:32:04Z","start_date_local":"2018-11-04T10:32:04Z","distance":1806.8,"start_index":2306,"end_index":2815,"average_heartrate":169.6,"max_heartrate":174.0,"segment":{"id":8456862,"resource_state":2,"name":"NYC - Marathon Mile 6","activity_type":"Run","distance":1802.0,"average_grade":-0.6,"maximum_grade":9.8,"elevation_high":27.2,"elevation_low":9.6,"start_latlng":[40.650058,-74.008757],"end_latlng":[40.662686,-73.995609],"start_latitude":40.650058,"start_longitude":-74.008757,"end_latitude":40.662686,"end_longitude":-73.995609,"climb_category":0,"city":"Brooklyn","state":"New - York","country":"United States","private":false,"hazardous":false,"starred":false},"kom_rank":null,"pr_rank":null,"achievements":[],"hidden":false},{"id":49065850965,"resource_state":2,"name":"NYC - Marathon Mile 7","activity":{"id":1946417534,"resource_state":1},"athlete":{"id":26462176,"resource_state":1},"elapsed_time":429,"moving_time":429,"start_date":"2018-11-04T15:40:06Z","start_date_local":"2018-11-04T10:40:06Z","distance":1534.4,"start_index":2789,"end_index":3219,"average_heartrate":171.6,"max_heartrate":176.0,"segment":{"id":8456872,"resource_state":2,"name":"NYC - Marathon Mile 7","activity_type":"Run","distance":1527.4,"average_grade":-0.3,"maximum_grade":8.2,"elevation_high":20.4,"elevation_low":9.8,"start_latlng":[40.662093,-73.996175],"end_latlng":[40.673262,-73.986283],"start_latitude":40.662093,"start_longitude":-73.996175,"end_latitude":40.673262,"end_longitude":-73.986283,"climb_category":0,"city":"Brooklyn","state":"New - York","country":"United States","private":false,"hazardous":false,"starred":false},"kom_rank":null,"pr_rank":null,"achievements":[],"hidden":false},{"id":49065851076,"resource_state":2,"name":"NYC - Marathon Mile 8","activity":{"id":1946417534,"resource_state":1},"athlete":{"id":26462176,"resource_state":1},"elapsed_time":487,"moving_time":487,"start_date":"2018-11-04T15:47:16Z","start_date_local":"2018-11-04T10:47:16Z","distance":1728.1,"start_index":3220,"end_index":3709,"average_heartrate":172.3,"max_heartrate":176.0,"segment":{"id":8456875,"resource_state":2,"name":"NYC - Marathon Mile 8","activity_type":"Run","distance":1717.6,"average_grade":0.3,"maximum_grade":7.9,"elevation_high":17.4,"elevation_low":8.4,"start_latlng":[40.673288,-73.986255],"end_latlng":[40.686646,-73.979081],"start_latitude":40.673288,"start_longitude":-73.986255,"end_latitude":40.686646,"end_longitude":-73.979081,"climb_category":0,"city":"Brooklyn","state":"New - York","country":"United States","private":false,"hazardous":false,"starred":false},"kom_rank":null,"pr_rank":null,"achievements":[],"hidden":false},{"id":49065851028,"resource_state":2,"name":"4th - Avenue: Union to Bergen","activity":{"id":1946417534,"resource_state":1},"athlete":{"id":26462176,"resource_state":1},"elapsed_time":178,"moving_time":178,"start_date":"2018-11-04T15:49:52Z","start_date_local":"2018-11-04T10:49:52Z","distance":636.5,"start_index":3376,"end_index":3555,"average_heartrate":172.0,"max_heartrate":175.0,"segment":{"id":6929299,"resource_state":2,"name":"4th - Avenue: Union to Bergen","activity_type":"Run","distance":634.1,"average_grade":0.2,"maximum_grade":2.3,"elevation_high":9.3,"elevation_low":7.9,"start_latlng":[40.677481,-73.983164],"end_latlng":[40.682445,-73.979752],"start_latitude":40.677481,"start_longitude":-73.983164,"end_latitude":40.682445,"end_longitude":-73.979752,"climb_category":0,"city":"New - York","state":"NY","country":"United States","private":false,"hazardous":false,"starred":false},"kom_rank":null,"pr_rank":null,"achievements":[],"hidden":false},{"id":49065851137,"resource_state":2,"name":"NYC - Marathon Mile 9","activity":{"id":1946417534,"resource_state":1},"athlete":{"id":26462176,"resource_state":1},"elapsed_time":474,"moving_time":474,"start_date":"2018-11-04T15:55:24Z","start_date_local":"2018-11-04T10:55:24Z","distance":1608.9,"start_index":3710,"end_index":4185,"average_heartrate":174.7,"max_heartrate":181.0,"segment":{"id":8456882,"resource_state":2,"name":"NYC - Marathon Mile 9","activity_type":"Run","distance":1659.4,"average_grade":0.5,"maximum_grade":6.7,"elevation_high":32.0,"elevation_low":14.0,"start_latlng":[40.686679,-73.979054],"end_latlng":[40.688982,-73.960037],"start_latitude":40.686679,"start_longitude":-73.979054,"end_latitude":40.688982,"end_longitude":-73.960037,"climb_category":0,"city":"Brooklyn","state":"New - York","country":"United States","private":false,"hazardous":false,"starred":false},"kom_rank":null,"pr_rank":null,"achievements":[],"hidden":false},{"id":49065851106,"resource_state":2,"name":"Lafayette - Hill Crusher","activity":{"id":1946417534,"resource_state":1},"athlete":{"id":26462176,"resource_state":1},"elapsed_time":117,"moving_time":117,"start_date":"2018-11-04T15:57:47Z","start_date_local":"2018-11-04T10:57:47Z","distance":382.7,"start_index":3853,"end_index":3970,"average_heartrate":178.2,"max_heartrate":180.0,"segment":{"id":14891840,"resource_state":2,"name":"Lafayette - Hill Crusher","activity_type":"Run","distance":398.7,"average_grade":2.0,"maximum_grade":7.1,"elevation_high":28.1,"elevation_low":19.9,"start_latlng":[40.687173,-73.973574],"end_latlng":[40.688019,-73.968925],"start_latitude":40.687173,"start_longitude":-73.973574,"end_latitude":40.688019,"end_longitude":-73.968925,"climb_category":0,"city":"Brooklyn","state":"New - York","country":"United States","private":false,"hazardous":false,"starred":false},"kom_rank":null,"pr_rank":null,"achievements":[],"hidden":false},{"id":49065851220,"resource_state":2,"name":"Cumberland - to Franklin","activity":{"id":1946417534,"resource_state":1},"athlete":{"id":26462176,"resource_state":1},"elapsed_time":376,"moving_time":347,"start_date":"2018-11-04T15:58:17Z","start_date_local":"2018-11-04T10:58:17Z","distance":1203.8,"start_index":3883,"end_index":4260,"average_heartrate":173.4,"max_heartrate":181.0,"segment":{"id":16082469,"resource_state":2,"name":"Cumberland - to Franklin","activity_type":"Run","distance":1333.0,"average_grade":-0.3,"maximum_grade":3.5,"elevation_high":28.4,"elevation_low":19.0,"start_latlng":[40.687459,-73.97239],"end_latlng":[40.68915,-73.958204],"start_latitude":40.687459,"start_longitude":-73.97239,"end_latitude":40.68915,"end_longitude":-73.958204,"climb_category":0,"city":"Brooklyn","state":"New - York","country":"United States","private":false,"hazardous":false,"starred":false},"kom_rank":null,"pr_rank":null,"achievements":[],"hidden":false},{"id":49065851247,"resource_state":2,"name":"NYC - Marathon Mile 10","activity":{"id":1946417534,"resource_state":1},"athlete":{"id":26462176,"resource_state":1},"elapsed_time":509,"moving_time":480,"start_date":"2018-11-04T16:03:18Z","start_date_local":"2018-11-04T11:03:18Z","distance":1684.5,"start_index":4185,"end_index":4696,"average_heartrate":170.0,"max_heartrate":177.0,"segment":{"id":8456893,"resource_state":2,"name":"NYC - Marathon Mile 10","activity_type":"Run","distance":1728.3,"average_grade":-1.0,"maximum_grade":5.4,"elevation_high":23.8,"elevation_low":3.6,"start_latlng":[40.688982,-73.960037],"end_latlng":[40.700824,-73.957403],"start_latitude":40.688982,"start_longitude":-73.960037,"end_latitude":40.700824,"end_longitude":-73.957403,"climb_category":0,"city":"Brooklyn","state":"New - York","country":"United States","private":false,"hazardous":false,"starred":false},"kom_rank":null,"pr_rank":null,"achievements":[],"hidden":false},{"id":49065851278,"resource_state":2,"name":"NYC - Marathon Mile 11","activity":{"id":1946417534,"resource_state":1},"athlete":{"id":26462176,"resource_state":1},"elapsed_time":436,"moving_time":436,"start_date":"2018-11-04T16:11:47Z","start_date_local":"2018-11-04T11:11:47Z","distance":1436.4,"start_index":4696,"end_index":5133,"average_heartrate":173.9,"max_heartrate":179.0,"segment":{"id":8456911,"resource_state":2,"name":"NYC - Marathon Mile 11","activity_type":"Run","distance":1473.7,"average_grade":0.7,"maximum_grade":6.5,"elevation_high":17.0,"elevation_low":5.0,"start_latlng":[40.700824,-73.957403],"end_latlng":[40.711861,-73.962873],"start_latitude":40.700824,"start_longitude":-73.957403,"end_latitude":40.711861,"end_longitude":-73.962873,"climb_category":0,"city":"Brooklyn","state":"New - York","country":"United States","private":false,"hazardous":false,"starred":false},"kom_rank":null,"pr_rank":2,"achievements":[{"type_id":3,"type":"pr","rank":2}],"hidden":false},{"id":49065851305,"resource_state":2,"name":"Foot - of Williamsburg Br to McCarren Park on Bedford Ave","activity":{"id":1946417534,"resource_state":1},"athlete":{"id":26462176,"resource_state":1},"elapsed_time":359,"moving_time":359,"start_date":"2018-11-04T16:18:45Z","start_date_local":"2018-11-04T11:18:45Z","distance":1287.6,"start_index":5115,"end_index":5475,"average_heartrate":173.8,"max_heartrate":178.0,"segment":{"id":8011296,"resource_state":2,"name":"Foot - of Williamsburg Br to McCarren Park on Bedford Ave","activity_type":"Run","distance":1268.2,"average_grade":-0.9,"maximum_grade":0.9,"elevation_high":16.3,"elevation_low":4.9,"start_latlng":[40.711263,-73.963103],"end_latlng":[40.720454,-73.954804],"start_latitude":40.711263,"start_longitude":-73.963103,"end_latitude":40.720454,"end_longitude":-73.954804,"climb_category":0,"city":"Brooklyn","state":"New - York","country":"United States","private":false,"hazardous":false,"starred":false},"kom_rank":null,"pr_rank":null,"achievements":[],"hidden":false},{"id":49065851349,"resource_state":2,"name":"NYC - Marathon Mile 13","activity":{"id":1946417534,"resource_state":1},"athlete":{"id":26462176,"resource_state":1},"elapsed_time":454,"moving_time":454,"start_date":"2018-11-04T16:26:52Z","start_date_local":"2018-11-04T11:26:52Z","distance":1530.7,"start_index":5604,"end_index":6059,"average_heartrate":170.3,"max_heartrate":178.0,"segment":{"id":8456924,"resource_state":2,"name":"NYC - Marathon Mile 13","activity_type":"Run","distance":1551.8,"average_grade":-0.1,"maximum_grade":8.8,"elevation_high":10.6,"elevation_low":0.4,"start_latlng":[40.723428,-73.951598],"end_latlng":[40.734689,-73.952388],"start_latitude":40.723428,"start_longitude":-73.951598,"end_latitude":40.734689,"end_longitude":-73.952388,"climb_category":0,"city":"Brooklyn","state":"New - York","country":"United States","private":false,"hazardous":false,"starred":false},"kom_rank":null,"pr_rank":null,"achievements":[],"hidden":false},{"id":49065851369,"resource_state":2,"name":"McGuinness - - Greenpoint to Bridge","activity":{"id":1946417534,"resource_state":1},"athlete":{"id":26462176,"resource_state":1},"elapsed_time":169,"moving_time":169,"start_date":"2018-11-04T16:32:01Z","start_date_local":"2018-11-04T11:32:01Z","distance":571.2,"start_index":5914,"end_index":6083,"average_heartrate":172.8,"max_heartrate":178.0,"segment":{"id":8541320,"resource_state":2,"name":"McGuinness - - Greenpoint to Bridge","activity_type":"Run","distance":565.8,"average_grade":-0.3,"maximum_grade":-0.1,"elevation_high":4.6,"elevation_low":2.9,"start_latlng":[40.730425,-73.95173],"end_latlng":[40.735412,-73.952746],"start_latitude":40.730425,"start_longitude":-73.95173,"end_latitude":40.735412,"end_longitude":-73.952746,"climb_category":0,"city":"Brooklyn","state":"New - York","country":"United States","private":false,"hazardous":false,"starred":false},"kom_rank":null,"pr_rank":null,"achievements":[],"hidden":false},{"id":49065851486,"resource_state":2,"name":"NYC - Marathon Mile 14","activity":{"id":1946417534,"resource_state":1},"athlete":{"id":26462176,"resource_state":1},"elapsed_time":559,"moving_time":559,"start_date":"2018-11-04T16:34:26Z","start_date_local":"2018-11-04T11:34:26Z","distance":1847.6,"start_index":6059,"end_index":6620,"average_heartrate":170.9,"max_heartrate":181.0,"segment":{"id":8456929,"resource_state":2,"name":"NYC - Marathon Mile 14","activity_type":"Run","distance":1890.2,"average_grade":0.0,"maximum_grade":10.9,"elevation_high":15.6,"elevation_low":-0.8,"start_latlng":[40.734689,-73.952388],"end_latlng":[40.748767,-73.95048],"start_latitude":40.734689,"start_longitude":-73.952388,"end_latitude":40.748767,"end_longitude":-73.95048,"climb_category":0,"city":"Brooklyn","state":"New - York","country":"United States","private":false,"hazardous":false,"starred":false},"kom_rank":null,"pr_rank":null,"achievements":[],"hidden":false},{"id":49065851447,"resource_state":2,"name":"Pulaski - - Greenpoint to LIC","activity":{"id":1946417534,"resource_state":1},"athlete":{"id":26462176,"resource_state":1},"elapsed_time":254,"moving_time":254,"start_date":"2018-11-04T16:34:50Z","start_date_local":"2018-11-04T11:34:50Z","distance":826.4,"start_index":6083,"end_index":6338,"average_heartrate":167.7,"max_heartrate":181.0,"segment":{"id":2394714,"resource_state":2,"name":"Pulaski - - Greenpoint to LIC","activity_type":"Run","distance":846.367,"average_grade":0.1,"maximum_grade":29.0,"elevation_high":6.0,"elevation_low":-2.0,"start_latlng":[40.73542730882764,-73.9527929853648],"end_latlng":[40.74279734864831,-73.95170132629573],"start_latitude":40.73542730882764,"start_longitude":-73.9527929853648,"end_latitude":40.74279734864831,"end_longitude":-73.95170132629573,"climb_category":0,"city":"Long - Island City","state":"NY","country":"United States","private":false,"hazardous":false,"starred":false},"kom_rank":null,"pr_rank":null,"achievements":[],"hidden":false},{"id":49065851386,"resource_state":2,"name":"Pulaski - Bridge","activity":{"id":1946417534,"resource_state":1},"athlete":{"id":26462176,"resource_state":1},"elapsed_time":132,"moving_time":132,"start_date":"2018-11-04T16:35:48Z","start_date_local":"2018-11-04T11:35:48Z","distance":424.9,"start_index":6142,"end_index":6274,"average_heartrate":167.3,"max_heartrate":181.0,"segment":{"id":6401050,"resource_state":2,"name":"Pulaski - Bridge","activity_type":"Run","distance":430.4,"average_grade":0.0,"maximum_grade":1.9,"elevation_high":2.6,"elevation_low":0.0,"start_latlng":[40.737056,-73.953014],"end_latlng":[40.740829,-73.952169],"start_latitude":40.737056,"start_longitude":-73.953014,"end_latitude":40.740829,"end_longitude":-73.952169,"climb_category":0,"city":"Queens, - NY, USA","state":"NY","country":"United States","private":false,"hazardous":false,"starred":false},"kom_rank":null,"pr_rank":null,"achievements":[],"hidden":false},{"id":49065851414,"resource_state":2,"name":"Pulaski - from top of Ash Street stairs","activity":{"id":1946417534,"resource_state":1},"athlete":{"id":26462176,"resource_state":1},"elapsed_time":121,"moving_time":121,"start_date":"2018-11-04T16:36:23Z","start_date_local":"2018-11-04T11:36:23Z","distance":396.5,"start_index":6177,"end_index":6298,"average_heartrate":162.7,"max_heartrate":177.0,"segment":{"id":8921373,"resource_state":2,"name":"Pulaski - from top of Ash Street stairs","activity_type":"Run","distance":413.9,"average_grade":0.2,"maximum_grade":1.8,"elevation_high":2.8,"elevation_low":0.0,"start_latlng":[40.738041,-73.953282],"end_latlng":[40.741543,-73.952024],"start_latitude":40.738041,"start_longitude":-73.953282,"end_latitude":40.741543,"end_longitude":-73.952024,"climb_category":0,"city":"Brooklyn","state":"New - York","country":"United States","private":false,"hazardous":false,"starred":false},"kom_rank":null,"pr_rank":null,"achievements":[],"hidden":false},{"id":49065851638,"resource_state":2,"name":"NYC - Marathon Queens Borough","activity":{"id":1946417534,"resource_state":1},"athlete":{"id":26462176,"resource_state":1},"elapsed_time":1050,"moving_time":1050,"start_date":"2018-11-04T16:37:14Z","start_date_local":"2018-11-04T11:37:14Z","distance":3314.8,"start_index":6228,"end_index":7281,"average_heartrate":174.3,"max_heartrate":187.0,"segment":{"id":8386900,"resource_state":2,"name":"NYC - Marathon Queens Borough","activity_type":"Run","distance":3454.1,"average_grade":0.7,"maximum_grade":22.5,"elevation_high":40.6,"elevation_low":-0.8,"start_latlng":[40.739526,-73.952593],"end_latlng":[40.755241,-73.950832],"start_latitude":40.739526,"start_longitude":-73.952593,"end_latitude":40.755241,"end_longitude":-73.950832,"climb_category":0,"city":"Queens","state":"New - York","country":"United States","private":false,"hazardous":false,"starred":false},"kom_rank":null,"pr_rank":null,"achievements":[],"hidden":false},{"id":49065851568,"resource_state":2,"name":"NYC - Marathon Mile 15","activity":{"id":1946417534,"resource_state":1},"athlete":{"id":26462176,"resource_state":1},"elapsed_time":481,"moving_time":481,"start_date":"2018-11-04T16:43:36Z","start_date_local":"2018-11-04T11:43:36Z","distance":1492.3,"start_index":6611,"end_index":7094,"average_heartrate":175.7,"max_heartrate":181.0,"segment":{"id":8456937,"resource_state":2,"name":"NYC - Marathon Mile 15","activity_type":"Run","distance":1551.3,"average_grade":1.4,"maximum_grade":25.5,"elevation_high":21.0,"elevation_low":-0.4,"start_latlng":[40.748819,-73.950733],"end_latlng":[40.752728,-73.944854],"start_latitude":40.748819,"start_longitude":-73.950733,"end_latitude":40.752728,"end_longitude":-73.944854,"climb_category":0,"city":"Queens","state":"New - York","country":"United States","private":false,"hazardous":false,"starred":false},"kom_rank":null,"pr_rank":null,"achievements":[],"hidden":false},{"id":49065851669,"resource_state":2,"name":"Main - Street Climb","activity":{"id":1946417534,"resource_state":1},"athlete":{"id":26462176,"resource_state":1},"elapsed_time":407,"moving_time":407,"start_date":"2018-11-04T16:48:31Z","start_date_local":"2018-11-04T11:48:31Z","distance":1192.2,"start_index":6907,"end_index":7315,"average_heartrate":177.9,"max_heartrate":187.0,"segment":{"id":5940443,"resource_state":2,"name":"Main - Street Climb","activity_type":"Run","distance":1028.4,"average_grade":4.0,"maximum_grade":33.3,"elevation_high":36.8,"elevation_low":-4.2,"start_latlng":[40.74958,-73.941584],"end_latlng":[40.755582,-73.951606],"start_latitude":40.74958,"start_longitude":-73.941584,"end_latitude":40.755582,"end_longitude":-73.951606,"climb_category":0,"city":"Queens, - NY, USA","state":"NY","country":"United States","private":false,"hazardous":false,"starred":false},"kom_rank":null,"pr_rank":null,"achievements":[],"hidden":false},{"id":49065851607,"resource_state":2,"name":"Queensbridge - Climb Repeat","activity":{"id":1946417534,"resource_state":1},"athlete":{"id":26462176,"resource_state":1},"elapsed_time":243,"moving_time":243,"start_date":"2018-11-04T16:49:49Z","start_date_local":"2018-11-04T11:49:49Z","distance":684.7,"start_index":6985,"end_index":7229,"average_heartrate":179.6,"max_heartrate":187.0,"segment":{"id":11449434,"resource_state":2,"name":"Queensbridge - Climb Repeat","activity_type":"Run","distance":694.6,"average_grade":-0.3,"maximum_grade":0.0,"elevation_high":5.6,"elevation_low":3.5,"start_latlng":[40.751415,-73.941841],"end_latlng":[40.754455,-73.948919],"start_latitude":40.751415,"start_longitude":-73.941841,"end_latitude":40.754455,"end_longitude":-73.948919,"climb_category":0,"city":"Queens","state":"New - York","country":"United States","private":false,"hazardous":false,"starred":false},"kom_rank":null,"pr_rank":null,"achievements":[],"hidden":false},{"id":49065851735,"resource_state":2,"name":"NYC - Marathon Mile 16","activity":{"id":1946417534,"resource_state":1},"athlete":{"id":26462176,"resource_state":1},"elapsed_time":512,"moving_time":512,"start_date":"2018-11-04T16:51:34Z","start_date_local":"2018-11-04T11:51:34Z","distance":1456.5,"start_index":7091,"end_index":7604,"average_heartrate":171.7,"max_heartrate":187.0,"segment":{"id":8456942,"resource_state":2,"name":"NYC - Marathon Mile 16","activity_type":"Run","distance":1598.1,"average_grade":-0.1,"maximum_grade":12.9,"elevation_high":43.2,"elevation_low":19.8,"start_latlng":[40.752692,-73.944776],"end_latlng":[40.759453,-73.960807],"start_latitude":40.752692,"start_longitude":-73.944776,"end_latitude":40.759453,"end_longitude":-73.960807,"climb_category":0,"city":"Queens","state":"New - York","country":"United States","private":false,"hazardous":false,"starred":false},"kom_rank":null,"pr_rank":null,"achievements":[],"hidden":false},{"id":49065851799,"resource_state":2,"name":"NYC - Marathon Mile 17","activity":{"id":1946417534,"resource_state":1},"athlete":{"id":26462176,"resource_state":1},"elapsed_time":432,"moving_time":432,"start_date":"2018-11-04T17:01:35Z","start_date_local":"2018-11-04T12:01:35Z","distance":1613.8,"start_index":7688,"end_index":8122,"average_heartrate":161.3,"max_heartrate":175.0,"segment":{"id":8456946,"resource_state":2,"name":"NYC - Marathon Mile 17","activity_type":"Run","distance":1560.5,"average_grade":-0.7,"maximum_grade":7.7,"elevation_high":18.8,"elevation_low":6.6,"start_latlng":[40.759507,-73.960948],"end_latlng":[40.771031,-73.953673],"start_latitude":40.759507,"start_longitude":-73.960948,"end_latitude":40.771031,"end_longitude":-73.953673,"climb_category":0,"city":"New - York","state":"New York","country":"United States","private":false,"hazardous":false,"starred":false},"kom_rank":null,"pr_rank":null,"achievements":[],"hidden":false},{"id":49065851986,"resource_state":2,"name":"New - York City Marathon - 1st Avenue","activity":{"id":1946417534,"resource_state":1},"athlete":{"id":26462176,"resource_state":1},"elapsed_time":1767,"moving_time":1767,"start_date":"2018-11-04T17:01:41Z","start_date_local":"2018-11-04T12:01:41Z","distance":6099.6,"start_index":7694,"end_index":9465,"average_heartrate":163.0,"max_heartrate":179.0,"segment":{"id":813865,"resource_state":2,"name":"New - York City Marathon - 1st Avenue","activity_type":"Run","distance":5502.2,"average_grade":-0.3,"maximum_grade":1.4,"elevation_high":18.5,"elevation_low":0.2,"start_latlng":[40.76008,-73.96159],"end_latlng":[40.8033,-73.92998],"start_latitude":40.76008,"start_longitude":-73.96159,"end_latitude":40.8033,"end_longitude":-73.92998,"climb_category":0,"city":"New - York","state":"NY","country":"United States","private":false,"hazardous":false,"starred":false},"kom_rank":null,"pr_rank":null,"achievements":[],"hidden":false},{"id":49065851861,"resource_state":2,"name":"NYC - Marathon Mile 18","activity":{"id":1946417534,"resource_state":1},"athlete":{"id":26462176,"resource_state":1},"elapsed_time":521,"moving_time":521,"start_date":"2018-11-04T17:08:47Z","start_date_local":"2018-11-04T12:08:47Z","distance":1884.9,"start_index":8122,"end_index":8642,"average_heartrate":172.4,"max_heartrate":179.0,"segment":{"id":8456951,"resource_state":2,"name":"NYC - Marathon Mile 18","activity_type":"Run","distance":1673.8,"average_grade":-0.5,"maximum_grade":27.3,"elevation_high":16.6,"elevation_low":-0.4,"start_latlng":[40.771031,-73.953673],"end_latlng":[40.783917,-73.944209],"start_latitude":40.771031,"start_longitude":-73.953673,"end_latitude":40.783917,"end_longitude":-73.944209,"climb_category":0,"city":"New - York","state":"New York","country":"United States","private":false,"hazardous":false,"starred":false},"kom_rank":null,"pr_rank":null,"achievements":[],"hidden":false},{"id":49065851921,"resource_state":2,"name":"NYC - Marathon Mile 19","activity":{"id":1946417534,"resource_state":1},"athlete":{"id":26462176,"resource_state":1},"elapsed_time":537,"moving_time":537,"start_date":"2018-11-04T17:17:28Z","start_date_local":"2018-11-04T12:17:28Z","distance":1751.8,"start_index":8642,"end_index":9181,"average_heartrate":157.2,"max_heartrate":175.0,"segment":{"id":8456955,"resource_state":2,"name":"NYC - Marathon Mile 19","activity_type":"Run","distance":1633.5,"average_grade":0.1,"maximum_grade":11.1,"elevation_high":2.0,"elevation_low":-1.0,"start_latlng":[40.783917,-73.944209],"end_latlng":[40.796648,-73.934851],"start_latitude":40.783917,"start_longitude":-73.944209,"end_latitude":40.796648,"end_longitude":-73.934851,"climb_category":0,"city":"New - York","state":"New York","country":"United States","private":false,"hazardous":false,"starred":false},"kom_rank":null,"pr_rank":null,"achievements":[],"hidden":false},{"id":49065851893,"resource_state":2,"name":"st - Avenue Climb","activity":{"id":1946417534,"resource_state":1},"athlete":{"id":26462176,"resource_state":1},"elapsed_time":227,"moving_time":227,"start_date":"2018-11-04T17:19:55Z","start_date_local":"2018-11-04T12:19:55Z","distance":751.6,"start_index":8789,"end_index":9017,"average_heartrate":154.6,"max_heartrate":175.0,"segment":{"id":5823618,"resource_state":2,"name":"st - Avenue Climb","activity_type":"Run","distance":705.1,"average_grade":6.0,"maximum_grade":30.1,"elevation_high":6409.8,"elevation_low":6367.8,"start_latlng":[40.78736,-73.941745],"end_latlng":[40.792899,-73.937772],"start_latitude":40.78736,"start_longitude":-73.941745,"end_latitude":40.792899,"end_longitude":-73.937772,"climb_category":0,"city":"New - York","state":"NY","country":"United States","private":false,"hazardous":false,"starred":false},"kom_rank":null,"pr_rank":null,"achievements":[],"hidden":false},{"id":49065852054,"resource_state":2,"name":"NYC - Marathon Mile 20","activity":{"id":1946417534,"resource_state":1},"athlete":{"id":26462176,"resource_state":1},"elapsed_time":541,"moving_time":541,"start_date":"2018-11-04T17:26:25Z","start_date_local":"2018-11-04T12:26:25Z","distance":1657.2,"start_index":9181,"end_index":9722,"average_heartrate":167.1,"max_heartrate":181.0,"segment":{"id":8456959,"resource_state":2,"name":"NYC - Marathon Mile 20","activity_type":"Run","distance":1606.9,"average_grade":0.4,"maximum_grade":9.0,"elevation_high":15.4,"elevation_low":0.6,"start_latlng":[40.796648,-73.934851],"end_latlng":[40.807585,-73.925571],"start_latitude":40.796648,"start_longitude":-73.934851,"end_latitude":40.807585,"end_longitude":-73.925571,"climb_category":0,"city":"New - York","state":"New York","country":"United States","private":false,"hazardous":false,"starred":false},"kom_rank":null,"pr_rank":null,"achievements":[],"hidden":false},{"id":49065852017,"resource_state":2,"name":"NYC - Marathon Willis Avenue Bridge","activity":{"id":1946417534,"resource_state":1},"athlete":{"id":26462176,"resource_state":1},"elapsed_time":304,"moving_time":304,"start_date":"2018-11-04T17:29:38Z","start_date_local":"2018-11-04T12:29:38Z","distance":930.0,"start_index":9374,"end_index":9679,"average_heartrate":173.4,"max_heartrate":181.0,"segment":{"id":8386120,"resource_state":2,"name":"NYC - Marathon Willis Avenue Bridge","activity_type":"Run","distance":904.1,"average_grade":1.0,"maximum_grade":9.0,"elevation_high":15.4,"elevation_low":1.2,"start_latlng":[40.801206,-73.93159],"end_latlng":[40.807002,-73.924431],"start_latitude":40.801206,"start_longitude":-73.93159,"end_latitude":40.807002,"end_longitude":-73.924431,"climb_category":0,"city":"Bronx","state":"New - York","country":"United States","private":false,"hazardous":false,"starred":false},"kom_rank":null,"pr_rank":null,"achievements":[],"hidden":false},{"id":49065852172,"resource_state":2,"name":"NYC - Marathon Mile 21","activity":{"id":1946417534,"resource_state":1},"athlete":{"id":26462176,"resource_state":1},"elapsed_time":561,"moving_time":561,"start_date":"2018-11-04T17:35:26Z","start_date_local":"2018-11-04T12:35:26Z","distance":1625.4,"start_index":9722,"end_index":10285,"average_heartrate":173.1,"max_heartrate":184.0,"segment":{"id":8456966,"resource_state":2,"name":"NYC - Marathon Mile 21","activity_type":"Run","distance":1678.1,"average_grade":0.0,"maximum_grade":9.0,"elevation_high":9.8,"elevation_low":1.6,"start_latlng":[40.807585,-73.925571],"end_latlng":[40.814221,-73.934515],"start_latitude":40.807585,"start_longitude":-73.925571,"end_latitude":40.814221,"end_longitude":-73.934515,"climb_category":0,"city":"Bronx","state":"New - York","country":"United States","private":false,"hazardous":false,"starred":false},"kom_rank":null,"pr_rank":null,"achievements":[],"hidden":false},{"id":49065852200,"resource_state":2,"name":"Madison - Avenue Bridge","activity":{"id":1946417534,"resource_state":1},"athlete":{"id":26462176,"resource_state":1},"elapsed_time":111,"moving_time":111,"start_date":"2018-11-04T17:43:22Z","start_date_local":"2018-11-04T12:43:22Z","distance":320.0,"start_index":10200,"end_index":10311,"average_heartrate":176.9,"max_heartrate":183.0,"segment":{"id":6401062,"resource_state":2,"name":"Madison - Avenue Bridge","activity_type":"Run","distance":318.3,"average_grade":-1.4,"maximum_grade":3.4,"elevation_high":7.2,"elevation_low":0.0,"start_latlng":[40.813948,-73.93179],"end_latlng":[40.814526,-73.935373],"start_latitude":40.813948,"start_longitude":-73.93179,"end_latitude":40.814526,"end_longitude":-73.935373,"climb_category":0,"city":"New - York","state":"NY","country":"United States","private":false,"hazardous":false,"starred":false},"kom_rank":null,"pr_rank":null,"achievements":[],"hidden":false},{"id":49065852224,"resource_state":2,"name":"NYC - Marathon Mile 22","activity":{"id":1946417534,"resource_state":1},"athlete":{"id":26462176,"resource_state":1},"elapsed_time":536,"moving_time":536,"start_date":"2018-11-04T17:44:47Z","start_date_local":"2018-11-04T12:44:47Z","distance":1596.4,"start_index":10285,"end_index":10823,"average_heartrate":175.1,"max_heartrate":181.0,"segment":{"id":8456971,"resource_state":2,"name":"NYC - Marathon Mile 22","activity_type":"Run","distance":1593.4,"average_grade":-0.0,"maximum_grade":6.1,"elevation_high":9.0,"elevation_low":2.6,"start_latlng":[40.814221,-73.934515],"end_latlng":[40.805142,-73.945313],"start_latitude":40.814221,"start_longitude":-73.934515,"end_latitude":40.805142,"end_longitude":-73.945313,"climb_category":0,"city":"New - York","state":"New York","country":"United States","private":false,"hazardous":false,"starred":false},"kom_rank":null,"pr_rank":null,"achievements":[],"hidden":false},{"id":49065852327,"resource_state":2,"name":"New - York City Marathon - 5th Avenue","activity":{"id":1946417534,"resource_state":1},"athlete":{"id":26462176,"resource_state":1},"elapsed_time":1513,"moving_time":1513,"start_date":"2018-11-04T17:45:32Z","start_date_local":"2018-11-04T12:45:32Z","distance":4123.9,"start_index":10330,"end_index":11847,"average_heartrate":174.1,"max_heartrate":181.0,"segment":{"id":813866,"resource_state":2,"name":"New - York City Marathon - 5th Avenue","activity_type":"Run","distance":4199.42,"average_grade":0.8,"maximum_grade":3.2,"elevation_high":34.7,"elevation_low":2.8,"start_latlng":[40.81479,-73.93615999999997],"end_latlng":[40.784110000000005,-73.95859000000002],"start_latitude":40.81479,"start_longitude":-73.93615999999997,"end_latitude":40.784110000000005,"end_longitude":-73.95859000000002,"climb_category":0,"city":"New - York","state":"NY","country":"United States","private":false,"hazardous":false,"starred":false},"kom_rank":null,"pr_rank":null,"achievements":[],"hidden":false},{"id":49065852252,"resource_state":2,"name":"NYC - Marathon Mile 23","activity":{"id":1946417534,"resource_state":1},"athlete":{"id":26462176,"resource_state":1},"elapsed_time":657,"moving_time":657,"start_date":"2018-11-04T17:53:43Z","start_date_local":"2018-11-04T12:53:43Z","distance":1725.7,"start_index":10823,"end_index":11481,"average_heartrate":172.1,"max_heartrate":177.0,"segment":{"id":8456979,"resource_state":2,"name":"NYC - Marathon Mile 23","activity_type":"Run","distance":1761.6,"average_grade":0.2,"maximum_grade":10.5,"elevation_high":12.4,"elevation_low":2.4,"start_latlng":[40.805142,-73.945313],"end_latlng":[40.791778,-73.953151],"start_latitude":40.805142,"start_longitude":-73.945313,"end_latitude":40.791778,"end_longitude":-73.953151,"climb_category":0,"city":"New - York","state":"New York","country":"United States","private":false,"hazardous":false,"starred":false},"kom_rank":null,"pr_rank":null,"achievements":[],"hidden":false},{"id":49065852351,"resource_state":2,"name":"Bad - Fred Lebow, Bad!","activity":{"id":1946417534,"resource_state":1},"athlete":{"id":26462176,"resource_state":1},"elapsed_time":619,"moving_time":619,"start_date":"2018-11-04T18:00:28Z","start_date_local":"2018-11-04T13:00:28Z","distance":1592.8,"start_index":11229,"end_index":11849,"average_heartrate":174.7,"max_heartrate":181.0,"segment":{"id":8351740,"resource_state":2,"name":"Bad - Fred Lebow, Bad!","activity_type":"Run","distance":1616.6,"average_grade":1.8,"maximum_grade":10.1,"elevation_high":34.8,"elevation_low":5.3,"start_latlng":[40.796772,-73.949287],"end_latlng":[40.784294,-73.95874],"start_latitude":40.796772,"start_longitude":-73.949287,"end_latitude":40.784294,"end_longitude":-73.95874,"climb_category":0,"city":"New - York","state":"New York","country":"United States","private":false,"hazardous":false,"starred":false},"kom_rank":null,"pr_rank":null,"achievements":[],"hidden":false},{"id":49065852418,"resource_state":2,"name":"NYC - Marathon Mile 24","activity":{"id":1946417534,"resource_state":1},"athlete":{"id":26462176,"resource_state":1},"elapsed_time":575,"moving_time":575,"start_date":"2018-11-04T18:04:40Z","start_date_local":"2018-11-04T13:04:40Z","distance":1542.4,"start_index":11481,"end_index":12058,"average_heartrate":175.4,"max_heartrate":181.0,"segment":{"id":8456987,"resource_state":2,"name":"NYC - Marathon Mile 24","activity_type":"Run","distance":1550.8,"average_grade":1.2,"maximum_grade":8.5,"elevation_high":31.6,"elevation_low":12.4,"start_latlng":[40.791778,-73.953151],"end_latlng":[40.781389,-73.963608],"start_latitude":40.791778,"start_longitude":-73.953151,"end_latitude":40.781389,"end_longitude":-73.963608,"climb_category":0,"city":"New - York","state":"New York","country":"United States","private":false,"hazardous":false,"starred":false},"kom_rank":null,"pr_rank":null,"achievements":[],"hidden":false},{"id":49065852376,"resource_state":2,"name":"Middle - of the 5th East Side","activity":{"id":1946417534,"resource_state":1},"athlete":{"id":26462176,"resource_state":1},"elapsed_time":314,"moving_time":314,"start_date":"2018-11-04T18:07:49Z","start_date_local":"2018-11-04T13:07:49Z","distance":843.1,"start_index":11671,"end_index":11986,"average_heartrate":176.2,"max_heartrate":181.0,"segment":{"id":11321105,"resource_state":2,"name":"Middle - of the 5th East Side","activity_type":"Run","distance":848.4,"average_grade":1.0,"maximum_grade":5.9,"elevation_high":35.4,"elevation_low":23.7,"start_latlng":[40.787825,-73.955935],"end_latlng":[40.781575,-73.961278],"start_latitude":40.787825,"start_longitude":-73.955935,"end_latitude":40.781575,"end_longitude":-73.961278,"climb_category":0,"city":"New - York","state":"New York","country":"United States","private":false,"hazardous":false,"starred":false},"kom_rank":null,"pr_rank":null,"achievements":[],"hidden":false},{"id":49065852436,"resource_state":2,"name":"800m - repeat south - 92nd to 84th","activity":{"id":1946417534,"resource_state":1},"athlete":{"id":26462176,"resource_state":1},"elapsed_time":297,"moving_time":297,"start_date":"2018-11-04T18:09:31Z","start_date_local":"2018-11-04T13:09:31Z","distance":830.2,"start_index":11773,"end_index":12071,"average_heartrate":174.8,"max_heartrate":181.0,"segment":{"id":17091054,"resource_state":2,"name":"800m - repeat south - 92nd to 84th","activity_type":"Run","distance":812.3,"average_grade":-0.3,"maximum_grade":9.1,"elevation_high":35.0,"elevation_low":27.0,"start_latlng":[40.785883,-73.957804],"end_latlng":[40.781226,-73.963965],"start_latitude":40.785883,"start_longitude":-73.957804,"end_latitude":40.781226,"end_longitude":-73.963965,"climb_category":0,"city":"New - York","state":"New York","country":"United States","private":false,"hazardous":false,"starred":false},"kom_rank":null,"pr_rank":null,"achievements":[],"hidden":false},{"id":49065852397,"resource_state":2,"name":"400m - - Engineer''s Gate - South","activity":{"id":1946417534,"resource_state":1},"athlete":{"id":26462176,"resource_state":1},"elapsed_time":134,"moving_time":134,"start_date":"2018-11-04T18:10:55Z","start_date_local":"2018-11-04T13:10:55Z","distance":372.0,"start_index":11857,"end_index":11992,"average_heartrate":174.9,"max_heartrate":181.0,"segment":{"id":8472872,"resource_state":2,"name":"400m - - Engineer''s Gate - South","activity_type":"Run","distance":373.7,"average_grade":-0.9,"maximum_grade":1.6,"elevation_high":35.5,"elevation_low":31.0,"start_latlng":[40.784111,-73.959049],"end_latlng":[40.78151,-73.961503],"start_latitude":40.784111,"start_longitude":-73.959049,"end_latitude":40.78151,"end_longitude":-73.961503,"climb_category":0,"city":"New - York","state":"New York","country":"United States","private":false,"hazardous":false,"starred":false},"kom_rank":null,"pr_rank":null,"achievements":[],"hidden":false},{"id":49065852532,"resource_state":2,"name":"1000m - - Engineer''s Gate - South","activity":{"id":1946417534,"resource_state":1},"athlete":{"id":26462176,"resource_state":1},"elapsed_time":355,"moving_time":355,"start_date":"2018-11-04T18:10:56Z","start_date_local":"2018-11-04T13:10:56Z","distance":984.0,"start_index":11858,"end_index":12214,"average_heartrate":172.7,"max_heartrate":181.0,"segment":{"id":8473236,"resource_state":2,"name":"1000m - - Engineer''s Gate - South","activity_type":"Run","distance":980.0,"average_grade":-0.7,"maximum_grade":6.0,"elevation_high":35.5,"elevation_low":26.9,"start_latlng":[40.78409,-73.959033],"end_latlng":[40.778294,-73.96636],"start_latitude":40.78409,"start_longitude":-73.959033,"end_latitude":40.778294,"end_longitude":-73.96636,"climb_category":0,"city":"New - York","state":"New York","country":"United States","private":false,"hazardous":false,"starred":false},"kom_rank":null,"pr_rank":2,"achievements":[{"type_id":3,"type":"pr","rank":2}],"hidden":false},{"id":49065852558,"resource_state":2,"name":"Rolling - past the Met Museum","activity":{"id":1946417534,"resource_state":1},"athlete":{"id":26462176,"resource_state":1},"elapsed_time":184,"moving_time":184,"start_date":"2018-11-04T18:13:47Z","start_date_local":"2018-11-04T13:13:47Z","distance":504.1,"start_index":12030,"end_index":12214,"average_heartrate":171.4,"max_heartrate":176.0,"segment":{"id":17352622,"resource_state":2,"name":"Rolling - past the Met Museum","activity_type":"Run","distance":509.0,"average_grade":0.1,"maximum_grade":2.9,"elevation_high":89.4,"elevation_low":84.4,"start_latlng":[40.781716,-73.962757],"end_latlng":[40.778326,-73.966487],"start_latitude":40.781716,"start_longitude":-73.962757,"end_latitude":40.778326,"end_longitude":-73.966487,"climb_category":0,"city":"New - York","state":"New York","country":"United States","private":false,"hazardous":false,"starred":false},"kom_rank":null,"pr_rank":2,"achievements":[{"type_id":3,"type":"pr","rank":2}],"hidden":false},{"id":49065852611,"resource_state":2,"name":"NYC - Marathon Mile 25","activity":{"id":1946417534,"resource_state":1},"athlete":{"id":26462176,"resource_state":1},"elapsed_time":563,"moving_time":563,"start_date":"2018-11-04T18:14:15Z","start_date_local":"2018-11-04T13:14:15Z","distance":1537.9,"start_index":12058,"end_index":12622,"average_heartrate":172.2,"max_heartrate":178.0,"segment":{"id":8456995,"resource_state":2,"name":"NYC - Marathon Mile 25","activity_type":"Run","distance":1536.0,"average_grade":-0.6,"maximum_grade":8.6,"elevation_high":32.8,"elevation_low":14.8,"start_latlng":[40.781389,-73.963608],"end_latlng":[40.7698,-73.971748],"start_latitude":40.781389,"start_longitude":-73.963608,"end_latitude":40.7698,"end_longitude":-73.971748,"climb_category":0,"city":"New - York","state":"New York","country":"United States","private":false,"hazardous":false,"starred":false},"kom_rank":null,"pr_rank":2,"achievements":[{"type_id":3,"type":"pr","rank":2}],"hidden":false},{"id":49065852587,"resource_state":2,"name":"East - Drive CP half mile-ish","activity":{"id":1946417534,"resource_state":1},"athlete":{"id":26462176,"resource_state":1},"elapsed_time":302,"moving_time":302,"start_date":"2018-11-04T18:16:58Z","start_date_local":"2018-11-04T13:16:58Z","distance":819.9,"start_index":12221,"end_index":12524,"average_heartrate":172.4,"max_heartrate":178.0,"segment":{"id":11321118,"resource_state":2,"name":"East - Drive CP half mile-ish","activity_type":"Run","distance":836.2,"average_grade":-0.4,"maximum_grade":8.5,"elevation_high":31.8,"elevation_low":14.9,"start_latlng":[40.77816,-73.966493],"end_latlng":[40.771593,-73.969675],"start_latitude":40.77816,"start_longitude":-73.966493,"end_latitude":40.771593,"end_longitude":-73.969675,"climb_category":0,"city":"New - York","state":"New York","country":"United States","private":false,"hazardous":false,"starred":false},"kom_rank":null,"pr_rank":2,"achievements":[{"type_id":3,"type":"pr","rank":2}],"hidden":false},{"id":49065852683,"resource_state":2,"name":"Rolling - thru the Zoo at CP","activity":{"id":1946417534,"resource_state":1},"athlete":{"id":26462176,"resource_state":1},"elapsed_time":176,"moving_time":176,"start_date":"2018-11-04T18:24:33Z","start_date_local":"2018-11-04T13:24:33Z","distance":500.9,"start_index":12678,"end_index":12854,"average_heartrate":170.4,"max_heartrate":175.0,"segment":{"id":17352648,"resource_state":2,"name":"Rolling - thru the Zoo at CP","activity_type":"Run","distance":481.7,"average_grade":-1.9,"maximum_grade":1.3,"elevation_high":77.6,"elevation_low":67.8,"start_latlng":[40.768853,-73.973054],"end_latlng":[40.764833,-73.973706],"start_latitude":40.768853,"start_longitude":-73.973054,"end_latitude":40.764833,"end_longitude":-73.973706,"climb_category":0,"city":"New - York","state":"New York","country":"United States","private":false,"hazardous":false,"starred":false},"kom_rank":null,"pr_rank":2,"achievements":[{"type_id":3,"type":"pr","rank":2}],"hidden":false},{"id":49065852776,"resource_state":2,"name":"Central - Park South","activity":{"id":1946417534,"resource_state":1},"athlete":{"id":26462176,"resource_state":1},"elapsed_time":290,"moving_time":290,"start_date":"2018-11-04T18:27:16Z","start_date_local":"2018-11-04T13:27:16Z","distance":763.5,"start_index":12841,"end_index":13059,"average_heartrate":172.2,"max_heartrate":175.0,"segment":{"id":8351701,"resource_state":2,"name":"Central - Park South","activity_type":"Run","distance":694.5,"average_grade":1.2,"maximum_grade":24.1,"elevation_high":24.2,"elevation_low":7.2,"start_latlng":[40.764999,-73.973488],"end_latlng":[40.768085,-73.981186],"start_latitude":40.764999,"start_longitude":-73.973488,"end_latitude":40.768085,"end_longitude":-73.981186,"climb_category":0,"city":"New - York","state":"New York","country":"United States","private":false,"hazardous":false,"starred":false},"kom_rank":null,"pr_rank":null,"achievements":[],"hidden":false},{"id":49065852709,"resource_state":2,"name":"59th - short stretch","activity":{"id":1946417534,"resource_state":1},"athlete":{"id":26462176,"resource_state":1},"elapsed_time":97,"moving_time":97,"start_date":"2018-11-04T18:27:25Z","start_date_local":"2018-11-04T13:27:25Z","distance":268.5,"start_index":12850,"end_index":12947,"average_heartrate":170.6,"max_heartrate":172.0,"segment":{"id":18403816,"resource_state":2,"name":"59th - short stretch","activity_type":"Run","distance":268.6,"average_grade":0.7,"maximum_grade":2.0,"elevation_high":40.4,"elevation_low":38.6,"start_latlng":[40.764784,-73.973574],"end_latlng":[40.7657,-73.976411],"start_latitude":40.764784,"start_longitude":-73.973574,"end_latitude":40.7657,"end_longitude":-73.976411,"climb_category":0,"city":"New - York","state":"New York","country":"United States","private":false,"hazardous":false,"starred":false},"kom_rank":null,"pr_rank":null,"achievements":[],"hidden":false},{"id":49065852751,"resource_state":2,"name":"Central - Park West Climb","activity":{"id":1946417534,"resource_state":1},"athlete":{"id":26462176,"resource_state":1},"elapsed_time":112,"moving_time":112,"start_date":"2018-11-04T18:29:05Z","start_date_local":"2018-11-04T13:29:05Z","distance":283.8,"start_index":12950,"end_index":13040,"average_heartrate":173.5,"max_heartrate":175.0,"segment":{"id":6013558,"resource_state":2,"name":"Central - Park West Climb","activity_type":"Run","distance":305.9,"average_grade":13.5,"maximum_grade":6.7,"elevation_high":1.6,"elevation_low":-39.6,"start_latlng":[40.765612,-73.976645],"end_latlng":[40.767442,-73.978981],"start_latitude":40.765612,"start_longitude":-73.976645,"end_latitude":40.767442,"end_longitude":-73.978981,"climb_category":0,"city":"New - York","state":"NY","country":"United States","private":false,"hazardous":false,"starred":false},"kom_rank":null,"pr_rank":null,"achievements":[],"hidden":false},{"id":49065852797,"resource_state":2,"name":"Central - Park West Climb","activity":{"id":1946417534,"resource_state":1},"athlete":{"id":26462176,"resource_state":1},"elapsed_time":115,"moving_time":115,"start_date":"2018-11-04T18:30:20Z","start_date_local":"2018-11-04T13:30:20Z","distance":294.5,"start_index":13014,"end_index":13068,"average_heartrate":173.3,"max_heartrate":175.0,"segment":{"id":5939710,"resource_state":2,"name":"Central - Park West Climb","activity_type":"Run","distance":324.3,"average_grade":13.3,"maximum_grade":42.0,"elevation_high":65.6,"elevation_low":22.6,"start_latlng":[40.766638,-73.978325],"end_latlng":[40.768282,-73.981293],"start_latitude":40.766638,"start_longitude":-73.978325,"end_latitude":40.768282,"end_longitude":-73.981293,"climb_category":0,"city":"New - York","state":"NY","country":"United States","private":false,"hazardous":false,"starred":false},"kom_rank":null,"pr_rank":2,"achievements":[{"type_id":3,"type":"pr","rank":2}],"hidden":false},{"id":49065852817,"resource_state":2,"name":"NW - Corner Central Park","activity":{"id":1946417534,"resource_state":1},"athlete":{"id":26462176,"resource_state":1},"elapsed_time":95,"moving_time":95,"start_date":"2018-11-04T18:30:51Z","start_date_local":"2018-11-04T13:30:51Z","distance":250.6,"start_index":13034,"end_index":13078,"average_heartrate":173.0,"max_heartrate":175.0,"segment":{"id":11321081,"resource_state":2,"name":"NW - Corner Central Park","activity_type":"Run","distance":262.4,"average_grade":-0.4,"maximum_grade":2.1,"elevation_high":24.1,"elevation_low":21.9,"start_latlng":[40.767003,-73.979135],"end_latlng":[40.768603,-73.98112],"start_latitude":40.767003,"start_longitude":-73.979135,"end_latitude":40.768603,"end_longitude":-73.98112,"climb_category":0,"city":"New - York","state":"New York","country":"United States","private":false,"hazardous":false,"starred":false},"kom_rank":null,"pr_rank":null,"achievements":[],"hidden":false}],"splits_metric":[{"distance":1001.6,"elapsed_time":314,"elevation_difference":15.6,"moving_time":314,"split":1,"average_speed":3.19,"average_heartrate":157.96178343949043,"pace_zone":2},{"distance":1000.7,"elapsed_time":286,"elevation_difference":-26.1,"moving_time":286,"split":2,"average_speed":3.5,"average_heartrate":165.06993006993008,"pace_zone":3},{"distance":1000.9,"elapsed_time":287,"elevation_difference":-14.3,"moving_time":287,"split":3,"average_speed":3.49,"average_heartrate":154.28919860627178,"pace_zone":3},{"distance":997.3,"elapsed_time":285,"elevation_difference":11.4,"moving_time":285,"split":4,"average_speed":3.5,"average_heartrate":165.80701754385964,"pace_zone":3},{"distance":1002.2,"elapsed_time":280,"elevation_difference":-2.2,"moving_time":280,"split":5,"average_speed":3.58,"average_heartrate":169.37857142857143,"pace_zone":3},{"distance":1000.1,"elapsed_time":279,"elevation_difference":1.5,"moving_time":279,"split":6,"average_speed":3.58,"average_heartrate":170.6057347670251,"pace_zone":3},{"distance":999.1,"elapsed_time":281,"elevation_difference":1.3,"moving_time":281,"split":7,"average_speed":3.56,"average_heartrate":171.2526690391459,"pace_zone":3},{"distance":998.8,"elapsed_time":279,"elevation_difference":-4.3,"moving_time":279,"split":8,"average_speed":3.58,"average_heartrate":170.53405017921148,"pace_zone":3},{"distance":1000.3,"elapsed_time":276,"elevation_difference":-14.5,"moving_time":276,"split":9,"average_speed":3.62,"average_heartrate":168.1195652173913,"pace_zone":3},{"distance":999.5,"elapsed_time":288,"elevation_difference":6.5,"moving_time":288,"split":10,"average_speed":3.47,"average_heartrate":171.59027777777777,"pace_zone":3},{"distance":1002.9,"elapsed_time":278,"elevation_difference":-3.6,"moving_time":278,"split":11,"average_speed":3.61,"average_heartrate":172.19064748201438,"pace_zone":3},{"distance":999.4,"elapsed_time":283,"elevation_difference":-1.4,"moving_time":283,"split":12,"average_speed":3.53,"average_heartrate":170.97526501766785,"pace_zone":3},{"distance":999.0,"elapsed_time":294,"elevation_difference":4.5,"moving_time":294,"split":13,"average_speed":3.4,"average_heartrate":172.50680272108843,"pace_zone":2},{"distance":1000.2,"elapsed_time":292,"elevation_difference":13.8,"moving_time":292,"split":14,"average_speed":3.43,"average_heartrate":177.22602739726028,"pace_zone":2},{"distance":1001.2,"elapsed_time":307,"elevation_difference":-11.1,"moving_time":278,"split":15,"average_speed":3.26,"average_heartrate":170.18705035971223,"pace_zone":2},{"distance":997.8,"elapsed_time":283,"elevation_difference":-9.7,"moving_time":283,"split":16,"average_speed":3.53,"average_heartrate":170.19081272084804,"pace_zone":3},{"distance":999.3,"elapsed_time":296,"elevation_difference":9.8,"moving_time":296,"split":17,"average_speed":3.38,"average_heartrate":172.18243243243242,"pace_zone":2},{"distance":1002.6,"elapsed_time":291,"elevation_difference":-0.3,"moving_time":291,"split":18,"average_speed":3.45,"average_heartrate":174.68384879725085,"pace_zone":3},{"distance":997.3,"elapsed_time":285,"elevation_difference":-10.6,"moving_time":285,"split":19,"average_speed":3.5,"average_heartrate":173.49824561403508,"pace_zone":3},{"distance":1003.2,"elapsed_time":301,"elevation_difference":3.4,"moving_time":301,"split":20,"average_speed":3.33,"average_heartrate":168.41528239202657,"pace_zone":2},{"distance":996.8,"elapsed_time":295,"elevation_difference":-5.2,"moving_time":295,"split":21,"average_speed":3.38,"average_heartrate":171.0135593220339,"pace_zone":2},{"distance":1001.6,"elapsed_time":303,"elevation_difference":1.3,"moving_time":303,"split":22,"average_speed":3.31,"average_heartrate":168.04950495049505,"pace_zone":2},{"distance":998.4,"elapsed_time":303,"elevation_difference":-0.1,"moving_time":303,"split":23,"average_speed":3.3,"average_heartrate":174.5742574257426,"pace_zone":2},{"distance":1004.5,"elapsed_time":283,"elevation_difference":2.3,"moving_time":278,"split":24,"average_speed":3.55,"average_heartrate":175.4496402877698,"pace_zone":3},{"distance":996.0,"elapsed_time":335,"elevation_difference":9.7,"moving_time":335,"split":25,"average_speed":2.97,"average_heartrate":178.28059701492538,"pace_zone":2},{"distance":1002.6,"elapsed_time":311,"elevation_difference":1.3,"moving_time":311,"split":26,"average_speed":3.22,"average_heartrate":166.13826366559485,"pace_zone":2},{"distance":997.9,"elapsed_time":288,"elevation_difference":-2.1,"moving_time":278,"split":27,"average_speed":3.46,"average_heartrate":158.25179856115108,"pace_zone":3},{"distance":999.9,"elapsed_time":292,"elevation_difference":-2.3,"moving_time":292,"split":28,"average_speed":3.42,"average_heartrate":169.10616438356163,"pace_zone":2},{"distance":1000.0,"elapsed_time":309,"elevation_difference":-6.9,"moving_time":309,"split":29,"average_speed":3.24,"average_heartrate":174.0873786407767,"pace_zone":2},{"distance":999.6,"elapsed_time":294,"elevation_difference":-2.7,"moving_time":294,"split":30,"average_speed":3.4,"average_heartrate":162.05460750853243,"pace_zone":2},{"distance":1001.7,"elapsed_time":324,"elevation_difference":-0.7,"moving_time":324,"split":31,"average_speed":3.09,"average_heartrate":159.07407407407408,"pace_zone":2},{"distance":1000.5,"elapsed_time":333,"elevation_difference":-0.6,"moving_time":333,"split":32,"average_speed":3.0,"average_heartrate":156.35735735735736,"pace_zone":2},{"distance":998.4,"elapsed_time":334,"elevation_difference":6.0,"moving_time":334,"split":33,"average_speed":2.99,"average_heartrate":175.25149700598803,"pace_zone":2},{"distance":999.1,"elapsed_time":355,"elevation_difference":-1.7,"moving_time":355,"split":34,"average_speed":2.81,"average_heartrate":171.15211267605633,"pace_zone":1},{"distance":1001.8,"elapsed_time":348,"elevation_difference":-1.4,"moving_time":348,"split":35,"average_speed":2.88,"average_heartrate":175.17528735632183,"pace_zone":1},{"distance":1000.3,"elapsed_time":333,"elevation_difference":1.7,"moving_time":333,"split":36,"average_speed":3.0,"average_heartrate":176.26126126126127,"pace_zone":2},{"distance":997.8,"elapsed_time":373,"elevation_difference":-1.0,"moving_time":373,"split":37,"average_speed":2.68,"average_heartrate":172.04289544235925,"pace_zone":1},{"distance":1001.4,"elapsed_time":390,"elevation_difference":14.1,"moving_time":390,"split":38,"average_speed":2.57,"average_heartrate":173.1153846153846,"pace_zone":1},{"distance":998.8,"elapsed_time":364,"elevation_difference":15.0,"moving_time":364,"split":39,"average_speed":2.74,"average_heartrate":176.3653846153846,"pace_zone":1},{"distance":1000.1,"elapsed_time":357,"elevation_difference":-14.1,"moving_time":357,"split":40,"average_speed":2.8,"average_heartrate":171.4593837535014,"pace_zone":1},{"distance":1002.4,"elapsed_time":367,"elevation_difference":-0.8,"moving_time":367,"split":41,"average_speed":2.73,"average_heartrate":173.14713896457766,"pace_zone":1},{"distance":998.3,"elapsed_time":372,"elevation_difference":3.1,"moving_time":372,"split":42,"average_speed":2.68,"average_heartrate":171.2587601078167,"pace_zone":1},{"distance":266.8,"elapsed_time":305,"elevation_difference":0.1,"moving_time":101,"split":43,"average_speed":0.87,"average_heartrate":172.92929292929293,"pace_zone":1}],"splits_standard":[{"distance":1609.9,"elapsed_time":489,"elevation_difference":5.9,"moving_time":489,"split":1,"average_speed":3.29,"average_heartrate":161.37832310838445,"pace_zone":2},{"distance":1611.4,"elapsed_time":460,"elevation_difference":-31.0,"moving_time":460,"split":2,"average_speed":3.5,"average_heartrate":155.80434782608697,"pace_zone":3},{"distance":1608.3,"elapsed_time":455,"elevation_difference":10.0,"moving_time":455,"split":3,"average_speed":3.53,"average_heartrate":169.3208791208791,"pace_zone":3},{"distance":1610.0,"elapsed_time":448,"elevation_difference":0.4,"moving_time":448,"split":4,"average_speed":3.59,"average_heartrate":170.26785714285714,"pace_zone":3},{"distance":1607.6,"elapsed_time":451,"elevation_difference":-3.4,"moving_time":451,"split":5,"average_speed":3.56,"average_heartrate":171.1818181818182,"pace_zone":3},{"distance":1612.5,"elapsed_time":454,"elevation_difference":-9.6,"moving_time":454,"split":6,"average_speed":3.55,"average_heartrate":169.43832599118943,"pace_zone":3},{"distance":1606.8,"elapsed_time":449,"elevation_difference":-2.9,"moving_time":449,"split":7,"average_speed":3.58,"average_heartrate":171.55902004454342,"pace_zone":3},{"distance":1608.8,"elapsed_time":462,"elevation_difference":5.1,"moving_time":462,"split":8,"average_speed":3.48,"average_heartrate":172.14502164502164,"pace_zone":3},{"distance":1611.6,"elapsed_time":471,"elevation_difference":8.2,"moving_time":471,"split":9,"average_speed":3.42,"average_heartrate":174.98726114649682,"pace_zone":2},{"distance":1608.4,"elapsed_time":479,"elevation_difference":-17.0,"moving_time":450,"split":10,"average_speed":3.36,"average_heartrate":169.96444444444444,"pace_zone":2},{"distance":1611.6,"elapsed_time":479,"elevation_difference":10.8,"moving_time":479,"split":11,"average_speed":3.36,"average_heartrate":173.32985386221296,"pace_zone":2},{"distance":1605.8,"elapsed_time":462,"elevation_difference":-10.9,"moving_time":462,"split":12,"average_speed":3.48,"average_heartrate":172.61688311688312,"pace_zone":3},{"distance":1609.0,"elapsed_time":479,"elevation_difference":-0.5,"moving_time":479,"split":13,"average_speed":3.36,"average_heartrate":169.8100208768267,"pace_zone":2},{"distance":1610.3,"elapsed_time":485,"elevation_difference":-1.6,"moving_time":485,"split":14,"average_speed":3.32,"average_heartrate":170.44329896907217,"pace_zone":2},{"distance":1610.1,"elapsed_time":466,"elevation_difference":5.5,"moving_time":461,"split":15,"average_speed":3.46,"average_heartrate":175.41865509761388,"pace_zone":3},{"distance":1607.8,"elapsed_time":533,"elevation_difference":12.5,"moving_time":533,"split":16,"average_speed":3.02,"average_heartrate":172.46341463414635,"pace_zone":2},{"distance":1610.3,"elapsed_time":464,"elevation_difference":-7.6,"moving_time":454,"split":17,"average_speed":3.47,"average_heartrate":161.59251101321587,"pace_zone":3},{"distance":1609.3,"elapsed_time":490,"elevation_difference":-5.4,"moving_time":490,"split":18,"average_speed":3.28,"average_heartrate":173.13673469387754,"pace_zone":2},{"distance":1608.6,"elapsed_time":488,"elevation_difference":-4.2,"moving_time":488,"split":19,"average_speed":3.3,"average_heartrate":158.0841889117043,"pace_zone":2},{"distance":1610.0,"elapsed_time":535,"elevation_difference":-2.0,"moving_time":535,"split":20,"average_speed":3.01,"average_heartrate":162.29532710280372,"pace_zone":2},{"distance":1609.2,"elapsed_time":551,"elevation_difference":4.6,"moving_time":551,"split":21,"average_speed":2.92,"average_heartrate":172.4464609800363,"pace_zone":1},{"distance":1611.1,"elapsed_time":563,"elevation_difference":1.5,"moving_time":563,"split":22,"average_speed":2.86,"average_heartrate":174.9449378330373,"pace_zone":1},{"distance":1608.1,"elapsed_time":572,"elevation_difference":-1.1,"moving_time":572,"split":23,"average_speed":2.81,"average_heartrate":173.83041958041957,"pace_zone":1},{"distance":1608.0,"elapsed_time":613,"elevation_difference":27.8,"moving_time":613,"split":24,"average_speed":2.62,"average_heartrate":174.35073409461663,"pace_zone":1},{"distance":1610.5,"elapsed_time":573,"elevation_difference":-17.7,"moving_time":573,"split":25,"average_speed":2.81,"average_heartrate":172.6544502617801,"pace_zone":1},{"distance":1609.9,"elapsed_time":594,"elevation_difference":4.2,"moving_time":594,"split":26,"average_speed":2.71,"average_heartrate":172.0841750841751,"pace_zone":1},{"distance":423.2,"elapsed_time":368,"elevation_difference":3.1,"moving_time":164,"split":27,"average_speed":1.15,"average_heartrate":173.36024844720498,"pace_zone":1}],"laps":[{"id":6270116916,"resource_state":2,"name":"Lap - 1","activity":{"id":1946417534,"resource_state":1},"athlete":{"id":26462176,"resource_state":1},"elapsed_time":13306,"moving_time":13299,"start_date":"2018-11-04T14:53:46Z","start_date_local":"2018-11-04T09:53:46Z","distance":42882.9,"start_index":0,"end_index":13128,"total_elevation_gain":270.9,"average_speed":3.22,"max_speed":5.6,"average_heartrate":170.1,"max_heartrate":187.0,"lap_index":1,"split":1,"pace_zone":2}],"best_efforts":[{"id":4155301967,"resource_state":2,"name":"400m","activity":{"id":1946417534,"resource_state":1},"athlete":{"id":26462176,"resource_state":1},"elapsed_time":100,"moving_time":91,"start_date":"2018-11-04T16:59:54Z","start_date_local":"2018-11-04T11:59:54Z","distance":400,"start_index":7592,"end_index":7688,"pr_rank":null,"achievements":[]},{"id":4155301991,"resource_state":2,"name":"1/2 - mile","activity":{"id":1946417534,"resource_state":1},"athlete":{"id":26462176,"resource_state":1},"elapsed_time":212,"moving_time":213,"start_date":"2018-11-04T16:46:14Z","start_date_local":"2018-11-04T11:46:14Z","distance":805,"start_index":6770,"end_index":6983,"pr_rank":null,"achievements":[]},{"id":4155302038,"resource_state":2,"name":"1k","activity":{"id":1946417534,"resource_state":1},"athlete":{"id":26462176,"resource_state":1},"elapsed_time":268,"moving_time":269,"start_date":"2018-11-04T15:42:21Z","start_date_local":"2018-11-04T10:42:21Z","distance":1000,"start_index":2925,"end_index":3194,"pr_rank":null,"achievements":[]},{"id":4155302058,"resource_state":2,"name":"1 - mile","activity":{"id":1946417534,"resource_state":1},"athlete":{"id":26462176,"resource_state":1},"elapsed_time":442,"moving_time":443,"start_date":"2018-11-04T15:28:33Z","start_date_local":"2018-11-04T10:28:33Z","distance":1609,"start_index":2094,"end_index":2538,"pr_rank":null,"achievements":[]},{"id":4155302098,"resource_state":2,"name":"2 - mile","activity":{"id":1946417534,"resource_state":1},"athlete":{"id":26462176,"resource_state":1},"elapsed_time":896,"moving_time":896,"start_date":"2018-11-04T15:21:04Z","start_date_local":"2018-11-04T10:21:04Z","distance":3219,"start_index":1643,"end_index":2542,"pr_rank":null,"achievements":[]},{"id":4155302108,"resource_state":2,"name":"5k","activity":{"id":1946417534,"resource_state":1},"athlete":{"id":26462176,"resource_state":1},"elapsed_time":1391,"moving_time":1392,"start_date":"2018-11-04T15:12:50Z","start_date_local":"2018-11-04T10:12:50Z","distance":5000,"start_index":1147,"end_index":2544,"pr_rank":null,"achievements":[]},{"id":4155302113,"resource_state":2,"name":"10k","activity":{"id":1946417534,"resource_state":1},"athlete":{"id":26462176,"resource_state":1},"elapsed_time":2811,"moving_time":2812,"start_date":"2018-11-04T15:00:38Z","start_date_local":"2018-11-04T10:00:38Z","distance":10000,"start_index":413,"end_index":3234,"pr_rank":null,"achievements":[]},{"id":4155302114,"resource_state":2,"name":"15k","activity":{"id":1946417534,"resource_state":1},"athlete":{"id":26462176,"resource_state":1},"elapsed_time":4273,"moving_time":4245,"start_date":"2018-11-04T14:59:11Z","start_date_local":"2018-11-04T09:59:11Z","distance":15000,"start_index":326,"end_index":4614,"pr_rank":null,"achievements":[]},{"id":4155302135,"resource_state":2,"name":"10 - mile","activity":{"id":1946417534,"resource_state":1},"athlete":{"id":26462176,"resource_state":1},"elapsed_time":4598,"moving_time":4570,"start_date":"2018-11-04T14:59:59Z","start_date_local":"2018-11-04T09:59:59Z","distance":16090,"start_index":374,"end_index":4988,"pr_rank":null,"achievements":[]},{"id":4155302151,"resource_state":2,"name":"20k","activity":{"id":1946417534,"resource_state":1},"athlete":{"id":26462176,"resource_state":1},"elapsed_time":5745,"moving_time":5717,"start_date":"2018-11-04T14:57:49Z","start_date_local":"2018-11-04T09:57:49Z","distance":20000,"start_index":243,"end_index":6008,"pr_rank":null,"achievements":[]},{"id":4155302155,"resource_state":2,"name":"Half-Marathon","activity":{"id":1946417534,"resource_state":1},"athlete":{"id":26462176,"resource_state":1},"elapsed_time":6076,"moving_time":6048,"start_date":"2018-11-04T14:58:52Z","start_date_local":"2018-11-04T09:58:52Z","distance":21097,"start_index":306,"end_index":6404,"pr_rank":null,"achievements":[]},{"id":4155302162,"resource_state":2,"name":"30k","activity":{"id":1946417534,"resource_state":1},"athlete":{"id":26462176,"resource_state":1},"elapsed_time":8773,"moving_time":8729,"start_date":"2018-11-04T14:54:19Z","start_date_local":"2018-11-04T09:54:19Z","distance":30000,"start_index":33,"end_index":8827,"pr_rank":null,"achievements":[]},{"id":4155302168,"resource_state":2,"name":"Marathon","activity":{"id":1946417534,"resource_state":1},"athlete":{"id":26462176,"resource_state":1},"elapsed_time":13094,"moving_time":13050,"start_date":"2018-11-04T14:53:49Z","start_date_local":"2018-11-04T09:53:49Z","distance":42195,"start_index":3,"end_index":13058,"pr_rank":null,"achievements":[]}],"gear":{"id":"g3423618","primary":true,"name":"adidas - Supernova ST","resource_state":2,"distance":366945.0},"photos":{"primary":{"id":null,"unique_id":"5e8006d0-8349-40ad-a4ef-72b5e6e82dfe","urls":{"600":"https://dgtzuqphqg23d.cloudfront.net/mo8thQ4Z5qAylUaRZHOWAR1sp16Bo-pp0ggYQKSWiZE-540x768.jpg","100":"https://dgtzuqphqg23d.cloudfront.net/mo8thQ4Z5qAylUaRZHOWAR1sp16Bo-pp0ggYQKSWiZE-90x128.jpg"},"source":1},"use_primary_photo":true,"count":9},"device_name":"Fitbit - Ionic","embed_token":"6f5179ffed45a82d3e12d324fdc2814bd422d1da","similar_activities":{"effort_count":1,"average_speed":3.2302713030187236,"min_average_speed":3.2302713030187236,"mid_average_speed":3.2302713030187236,"max_average_speed":3.2302713030187236,"pr_rank":null,"frequency_milestone":null,"trend":{"speeds":[3.2302713030187236],"current_activity_index":0,"min_speed":3.2302713030187236,"mid_speed":3.2302713030187236,"max_speed":3.2302713030187236,"direction":0},"resource_state":2},"available_zones":["heartrate","pace"]}' + string: '{"error":"Rate Limit Exceeded","status":429,"message":"Too Many Requests"}' http_version: recorded_at: Sun, 25 Nov 2018 13:45:45 GMT recorded_with: VCR 4.0.0 diff --git a/spec/strava/api/client/endpoints/activities/activity_spec.rb b/spec/strava/api/client/endpoints/activities/activity_spec.rb index 77240bf..8586630 100644 --- a/spec/strava/api/client/endpoints/activities/activity_spec.rb +++ b/spec/strava/api/client/endpoints/activities/activity_spec.rb @@ -372,18 +372,3 @@ end end end - -# uses the cassette: 'client/activity' but with status changed to 429 and ratelimit exceeded -RSpec.describe 'Strava::Api::Client#activity', vcr: { cassette_name: 'client/activity_with_ratelimit_exceeded' } do - include_context 'with API client' - it 'raises Strava::Errors::RatelimitError' do - expect do - client.activity(1_946_417_534) - end.to raise_error(Strava::Errors::RatelimitError) do |error| - expect(error.error_message).to eql('Too Many Requests') - expect(error.ratelimit).to be_a Strava::Api::Ratelimit - expect(error.ratelimit.exceeded?).to be(true) - expect(error.ratelimit.exceeded).to eql({ fifteen_minutes_remaining: 0 }) - end - end -end diff --git a/spec/strava/api/client_spec.rb b/spec/strava/api/client_spec.rb index f460d43..9741e88 100644 --- a/spec/strava/api/client_spec.rb +++ b/spec/strava/api/client_spec.rb @@ -10,6 +10,7 @@ end it_behaves_like 'web client' + context 'with errors' do it 'handles authorization errors', vcr: { cassette_name: 'client/authorization_error' } do expect { client.activity(id: 1_946_417_534) }.to raise_error Strava::Errors::Fault, /Authorization Error/ @@ -18,6 +19,53 @@ it 'handles not found errors', vcr: { cassette_name: 'client/not_found_error' } do expect { client.activity(id: 1_946_417_534) }.to raise_error Faraday::ResourceNotFound end + + it 'includes method url and url_path', vcr: { cassette_name: 'client/not_found_error' } do + expect { client.activity(id: 1_946_417_534) }.to raise_error Faraday::ResourceNotFound do |error| + request = error.response[:request] + expect(request[:method]).to eq :get + expect(request[:url]).to eq URI('https://www.strava.com/api/v3/activities/1946417534') + expect(request[:url_path]).to eq '/api/v3/activities/1946417534' + end + end + + context 'with DEFAULT_OPTIONS[:include_request] set to false' do + before do + allow_any_instance_of(Strava::Web::RaiseResponseError).to receive(:options) + .and_return({ include_request: false, allowed_statuses: [] }) + end + + it 'does not include method url and url_path in Faraday::ResourceNotFound', vcr: { cassette_name: 'client/not_found_error' } do + expect { client.activity(id: 1_946_417_534) }.to raise_error Faraday::ResourceNotFound do |error| + expect(error.response[:request]).to be_nil + end + end + + it 'does not include method url and url_path in Strava::Errors::RatelimitError', vcr: { cassette_name: 'client/activity_with_ratelimit_exceeded' } do + expect do + client.activity(1_946_417_534) + end.to raise_error(Strava::Errors::RatelimitError) do |error| + expect(error.ratelimit).to be_a Strava::Api::Ratelimit + expect(error.ratelimit.exceeded?).to be(true) + expect(error.ratelimit.exceeded).to eql({ fifteen_minutes_remaining: 0 }) + expect(error.response[:request]).to be_nil + end + end + end + + it 'raises Strava::Errors::RatelimitError', vcr: { cassette_name: 'client/activity_with_ratelimit_exceeded' } do + expect do + client.activity(1_946_417_534) + end.to raise_error(Strava::Errors::RatelimitError) do |error| + expect(error.ratelimit).to be_a Strava::Api::Ratelimit + expect(error.ratelimit.exceeded?).to be(true) + expect(error.ratelimit.exceeded).to eql({ fifteen_minutes_remaining: 0 }) + request = error.response[:request] + expect(request[:method]).to eq :get + expect(request[:url]).to eq URI('https://www.strava.com/api/v3/activities/1946417534') + expect(request[:url_path]).to eq '/api/v3/activities/1946417534' + end + end end context 'with SSL certificates' do From ff9b96894a4bf427ed76635a994d697722d0b18d Mon Sep 17 00:00:00 2001 From: "Daniel (dB.) Doubrovkine" Date: Thu, 16 Oct 2025 10:15:54 -0400 Subject: [PATCH 2/3] Fixed RSpec/DescribedClass. --- .rubocop_todo.yml | 12 +----------- spec/strava/models/athlete_spec.rb | 2 +- spec/strava/oauth/client_spec.rb | 15 ++++++++------- spec/strava/webhooks/client_spec.rb | 14 +++++++------- 4 files changed, 17 insertions(+), 26 deletions(-) diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 52fe0c4..902b9a6 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -1,6 +1,6 @@ # This configuration was generated by # `rubocop --auto-gen-config` -# on 2025-10-16 14:00:36 UTC using RuboCop version 1.68.0. +# on 2025-10-16 14:15:33 UTC using RuboCop version 1.68.0. # The point is for the user to remove these configuration records # one by one as the offenses are removed from the code base. # Note that changes in the inspected code, or installation of new @@ -11,16 +11,6 @@ RSpec/AnyInstance: Exclude: - 'spec/strava/api/client_spec.rb' -# Offense count: 13 -# This cop supports unsafe autocorrection (--autocorrect-all). -# Configuration parameters: SkipBlocks, EnforcedStyle, OnlyStaticConstants. -# SupportedStyles: described_class, explicit -RSpec/DescribedClass: - Exclude: - - 'spec/strava/models/athlete_spec.rb' - - 'spec/strava/oauth/client_spec.rb' - - 'spec/strava/webhooks/client_spec.rb' - # Offense count: 5 # Configuration parameters: AllowedGroups. RSpec/NestedGroups: diff --git a/spec/strava/models/athlete_spec.rb b/spec/strava/models/athlete_spec.rb index fda90fd..4051702 100644 --- a/spec/strava/models/athlete_spec.rb +++ b/spec/strava/models/athlete_spec.rb @@ -5,7 +5,7 @@ RSpec.describe Strava::Models::Athlete do let(:fixtures) { 'spec/fixtures/strava/models' } let(:json) { JSON.parse(File.read("#{fixtures}/athlete.json")) } - let(:activity) { Strava::Models::Athlete.new(json) } + let(:activity) { described_class.new(json) } describe 'ride' do it 'exposes custom properties' do diff --git a/spec/strava/oauth/client_spec.rb b/spec/strava/oauth/client_spec.rb index 297acb5..732f0bd 100644 --- a/spec/strava/oauth/client_spec.rb +++ b/spec/strava/oauth/client_spec.rb @@ -8,8 +8,9 @@ end it_behaves_like 'web client' + context 'with defaults' do - let(:client) { Strava::OAuth::Client.new } + let(:client) { described_class.new } describe '#initialize' do it 'sets endpoint' do @@ -32,8 +33,8 @@ context 'with custom settings' do describe '#initialize' do Strava::OAuth::Config::ATTRIBUTES.each do |key| - context key do - let(:client) { Strava::OAuth::Client.new(key => 'custom') } + context key.to_s do + let(:client) { described_class.new(key => 'custom') } it "sets #{key}" do expect(client.send(key)).not_to eq Strava::OAuth::Config.send(key) @@ -46,14 +47,14 @@ context 'with global config' do after do - Strava::OAuth::Client.config.reset + described_class.config.reset end - let(:client) { Strava::OAuth::Client.new } + let(:client) { described_class.new } context 'with client id and secret' do before do - Strava::OAuth::Client.configure do |config| + described_class.configure do |config| config.client_id = 'custom client id' config.client_secret = 'custom client secret' end @@ -69,7 +70,7 @@ end context 'with a client id and secret' do - let(:client) { Strava::OAuth::Client.new(client_id: '12345', client_secret: 'client-secret') } + let(:client) { described_class.new(client_id: '12345', client_secret: 'client-secret') } describe '#authorize_url' do it 'returns url' do diff --git a/spec/strava/webhooks/client_spec.rb b/spec/strava/webhooks/client_spec.rb index b1c720a..ddd97cc 100644 --- a/spec/strava/webhooks/client_spec.rb +++ b/spec/strava/webhooks/client_spec.rb @@ -9,7 +9,7 @@ it_behaves_like 'web client' context 'with defaults' do - let(:client) { Strava::Webhooks::Client.new } + let(:client) { described_class.new } describe '#initialize' do it 'sets endpoint' do @@ -27,8 +27,8 @@ context 'with custom settings' do describe '#initialize' do Strava::Webhooks::Config::ATTRIBUTES.each do |key| - context key do - let(:client) { Strava::Webhooks::Client.new(key => 'custom') } + context key.to_s do + let(:client) { described_class.new(key => 'custom') } it "sets #{key}" do expect(client.send(key)).not_to eq Strava::Webhooks::Config.send(key) @@ -41,14 +41,14 @@ context 'with global config' do after do - Strava::Webhooks::Client.config.reset + described_class.config.reset end - let(:client) { Strava::Webhooks::Client.new } + let(:client) { described_class.new } context 'with client id and secret' do before do - Strava::Webhooks::Client.configure do |config| + described_class.configure do |config| config.client_id = 'custom client id' config.client_secret = 'custom client secret' end @@ -64,7 +64,7 @@ end context 'with a client id and secret' do - let(:client) { Strava::Webhooks::Client.new(client_id: ENV.fetch('STRAVA_CLIENT_ID', '24523'), client_secret: ENV.fetch('STRAVA_CLIENT_SECRET', 'client-secret')) } + let(:client) { described_class.new(client_id: ENV.fetch('STRAVA_CLIENT_ID', '24523'), client_secret: ENV.fetch('STRAVA_CLIENT_SECRET', 'client-secret')) } describe '#push_subscriptions' do it 'gets an empty set of push subscriptions', vcr: { cassette_name: 'webhooks/no_push_subscriptions' } do From 7eb759b4411ec9d9cc001e4ec6f881ae5b065385 Mon Sep 17 00:00:00 2001 From: "Daniel (dB.) Doubrovkine" Date: Thu, 16 Oct 2025 10:24:36 -0400 Subject: [PATCH 3/3] Added UPGRADING note. --- README.md | 6 ++++++ UPGRADING.md | 12 +++++++++++- lib/strava/errors/ratelimit_error.rb | 12 ++++++++++++ .../client/activity_with_ratelimit_exceeded.yml | 2 +- spec/strava/api/client_spec.rb | 3 +++ 5 files changed, 33 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 104dba6..2f3b279 100644 --- a/README.md +++ b/README.md @@ -1122,6 +1122,12 @@ rescue Strava::Errors::Fault => e end ``` +Faraday can optionally exclude HTTP method, path and query params from the errors raised. The client implementation options will now default to `Faraday::Response::RaiseError::DEFAULT_OPTIONS` with `include_request` set to `true`. You can change this behavior by setting `Strava::Web::RaiseResponseError::DEFAULT_OPTIONS`. + +```ruby +Strava::Web::RaiseResponseError::DEFAULT_OPTIONS = { include_request: false } +``` + ## Tools For a complete set of command-line tools, check out [strava-ruby-cli](https://github.com/dblock/strava-ruby-cli) built on top of this gem. diff --git a/UPGRADING.md b/UPGRADING.md index 6337c47..6425481 100644 --- a/UPGRADING.md +++ b/UPGRADING.md @@ -1,5 +1,15 @@ # Upgrading Strava-Ruby-Client +### Upgrading to >= 2.3.0 + +Faraday can optionally exclude HTTP method, path and query params from the errors raised. The client implementation options will now default to `Faraday::Response::RaiseError::DEFAULT_OPTIONS` with `include_request` set to `true`. You can change this behavior by setting `Strava::Web::RaiseResponseError::DEFAULT_OPTIONS`. + +```ruby +Strava::Web::RaiseResponseError::DEFAULT_OPTIONS = { include_request: false } +``` + +See [#91](https://github.com/dblock/strava-ruby-client/pull/91) for details. + ### Upgrading to >= 2.2.0 Support for Ruby 2.x has been dropped. The minimum required Ruby version is now 3.0.0. @@ -45,4 +55,4 @@ client = Strava::Api::Client.new(ca_file: OpenSSL::X509::DEFAULT_CERT_FILE, ca_p The library was upgraded to require Faraday 1.0 or newer. Change all references to `Faraday::Error::ResourceNotFound` or `Faraday::Error::ConnectionFailed` to `Faraday::ConnectionFailed` and `Faraday::ResourceNotFound` respectively. -See [#30](https://github.com/dblock/strava-ruby-client/pull/30) for more details. +See [#30](https://github.com/dblock/strava-ruby-client/pull/30) for details. diff --git a/lib/strava/errors/ratelimit_error.rb b/lib/strava/errors/ratelimit_error.rb index a178332..df7188b 100644 --- a/lib/strava/errors/ratelimit_error.rb +++ b/lib/strava/errors/ratelimit_error.rb @@ -9,6 +9,18 @@ def initialize(env, response) @ratelimit = Strava::Api::Ratelimit.new(env.response) super(response) end + + def message + response[:body]['message'] || super + end + + def headers + response[:headers] + end + + def errors + response[:body]['errors'] + end end end end diff --git a/spec/fixtures/strava/client/activity_with_ratelimit_exceeded.yml b/spec/fixtures/strava/client/activity_with_ratelimit_exceeded.yml index 485b372..d67583e 100644 --- a/spec/fixtures/strava/client/activity_with_ratelimit_exceeded.yml +++ b/spec/fixtures/strava/client/activity_with_ratelimit_exceeded.yml @@ -52,7 +52,7 @@ http_interactions: - 1; mode=block body: encoding: UTF-8 - string: '{"error":"Rate Limit Exceeded","status":429,"message":"Too Many Requests"}' + string: '{"errors":"Rate Limit Exceeded","status":429,"message":"Too Many Requests"}' http_version: recorded_at: Sun, 25 Nov 2018 13:45:45 GMT recorded_with: VCR 4.0.0 diff --git a/spec/strava/api/client_spec.rb b/spec/strava/api/client_spec.rb index 9741e88..e0c14c0 100644 --- a/spec/strava/api/client_spec.rb +++ b/spec/strava/api/client_spec.rb @@ -49,6 +49,9 @@ expect(error.ratelimit.exceeded?).to be(true) expect(error.ratelimit.exceeded).to eql({ fifteen_minutes_remaining: 0 }) expect(error.response[:request]).to be_nil + expect(error.message).to eq 'Too Many Requests' + expect(error.headers).to be_a Hash + expect(error.errors).to eq 'Rate Limit Exceeded' end end end