diff --git a/README.md b/README.md index 9a27b01..eb0c8ca 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,4 @@ # go-tflapi + Interface for querying TFL Unified API via golang + diff --git a/client.go b/client.go index 6ad12d6..d464c5a 100644 --- a/client.go +++ b/client.go @@ -17,6 +17,7 @@ const ( toPath string = "to" stopPointPath string = "StopPoint" searchPath string = "Search" + fareToPath string = "FareTo" ) // Option is a functional option for configuring the API client @@ -61,7 +62,8 @@ type Api interface { SearchStopPoints(string) (*[]EntityMatchedStop, error) SearchStopPointsWithModes(string, []string) (*[]EntityMatchedStop, error) GetStopPointForID(string) (*StopPointAPIResponse, error) - GetJourneyPlannerItinerary(JourneyPlannerQuery) (*JourneyPlannerItineraryResult, error) + GetJourneyPlannerItinerary(JourneyPlannerQuery) (*JourneyPlannerItineraryResult, error) + SingleFareFinder(SingleFareFinderInput) (*FaresSection, error) } // Client holds information necessary to make a request to your API @@ -217,3 +219,19 @@ func (c *TflClient) GetJourneyPlannerItinerary(query JourneyPlannerQuery) (*Jour return &resp, nil } + +// SingleFareFinder retrieves a single fare cost between two stations +// It queries the endpoint /StopPoint/{from}/FareTo/{to} +func (c *TflClient) SingleFareFinder(input SingleFareFinderInput) (*[]FaresSection, error) { + + pathParams := []string{stopPointPath, input.From, fareToPath, input.To} + queryParams := &map[string]string{} + url := c.buildURLWithQueryParams(pathParams, queryParams) + + resp := []FaresSection{} + if err := c.getJSON(url, &resp); err != nil { + return nil, err + } + + return &resp, nil +} diff --git a/client_test.go b/client_test.go index cb1b64f..63c790a 100644 --- a/client_test.go +++ b/client_test.go @@ -11,6 +11,8 @@ import ( "path/filepath" "reflect" "testing" + + "github.com/stretchr/testify/assert" ) const ( @@ -50,6 +52,8 @@ func TflAPIClientStub() func() { resp = getTestDataFileContents("Should_retrieve_no_matches_for_invalid_searchTerm.json") case fmt.Sprintf("/Journey/JourneyResults/1001089/to/1000173?app_id=%s&app_key=%s&date=20190401&mode=%s&time=0715", appID, appKey, "national-rail%2Ctube"): resp = getTestDataFileContents("Should_retrieve_journey_planner_itinerary_for_valid_search.json") + case fmt.Sprintf("/StopPoint/940GZZLUCYF/FareTo/910GPURLEYO?app_id=%s&app_key=%s", appID, appKey): + resp = getTestDataFileContents("single_fare_finder.json") } w.Write(resp) @@ -253,7 +257,7 @@ func TestTflAPIClient_SearchStopPointsWithModes(t *testing.T) { api: client, args: args{ searchTerm: "London Bridge", - modes: []string{"national-rail", "tube"}, + modes: []string{"national-rail", "tube"}, }, want: &expected, }, @@ -272,7 +276,6 @@ func TestTflAPIClient_SearchStopPointsWithModes(t *testing.T) { } } - func TestTflAPIClient_GetJourneyPlannerItinerary(t *testing.T) { expected := JourneyPlannerItineraryResult{} @@ -316,3 +319,49 @@ func TestTflAPIClient_GetJourneyPlannerItinerary(t *testing.T) { }) } } + +func TestTflClient_SingleFareFinder(t *testing.T) { + + expected := []FaresSection{} + json.Unmarshal(getTestDataFileContents("single_fare_finder.json"), &expected) + + type args struct { + input SingleFareFinderInput + } + tests := []struct { + name string + api *TflClient + args args + want *[]FaresSection + wantErr error + }{ + { + name: "should retrieve single fare finder", + api: client, + args: args{ + input: SingleFareFinderInput{ + From: "940GZZLUCYF", + To: "910GPURLEYO", + }, + }, + want: &expected, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := tt.api.SingleFareFinder(tt.args.input) + if err != nil && tt.wantErr == nil { + assert.Fail(t, fmt.Sprintf( + "Error not expected but got one:\n"+ + "error: %q", err), + ) + return + } + if tt.wantErr != nil { + assert.EqualError(t, err, tt.wantErr.Error()) + return + } + assert.Equal(t, tt.want, got) + }) + } +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..7f7350c --- /dev/null +++ b/go.mod @@ -0,0 +1,5 @@ +module go-tflapi + +go 1.14 + +require github.com/stretchr/testify v1.6.1 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..56d62e7 --- /dev/null +++ b/go.sum @@ -0,0 +1,10 @@ +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/testdata/journey_no_fare.json b/testdata/journey_no_fare.json new file mode 100644 index 0000000..9256ea8 --- /dev/null +++ b/testdata/journey_no_fare.json @@ -0,0 +1,814 @@ +{ + "$type": "Tfl.Api.Presentation.Entities.JourneyPlanner.ItineraryResult, Tfl.Api.Presentation.Entities", + "journeys": [ + { + "$type": "Tfl.Api.Presentation.Entities.JourneyPlanner.Journey, Tfl.Api.Presentation.Entities", + "startDateTime": "2020-08-22T16:16:00", + "duration": 35, + "arrivalDateTime": "2020-08-22T16:51:00", + "legs": [ + { + "$type": "Tfl.Api.Presentation.Entities.JourneyPlanner.Leg, Tfl.Api.Presentation.Entities", + "duration": 17, + "instruction": { + "$type": "Tfl.Api.Presentation.Entities.Instruction, Tfl.Api.Presentation.Entities", + "summary": "Southern to Purley", + "detailed": "Southern towards Reigate", + "steps": [] + }, + "obstacles": [ + { + "$type": "Tfl.Api.Presentation.Entities.JourneyPlanner.Obstacle, Tfl.Api.Presentation.Entities", + "type": "STAIRS", + "incline": "DOWN", + "stopId": 1001229, + "position": "AFTER" + }, + { + "$type": "Tfl.Api.Presentation.Entities.JourneyPlanner.Obstacle, Tfl.Api.Presentation.Entities", + "type": "STAIRS", + "incline": "UP", + "stopId": 1001229, + "position": "AFTER" + } + ], + "departureTime": "2020-08-22T16:16:00", + "arrivalTime": "2020-08-22T16:33:00", + "departurePoint": { + "$type": "Tfl.Api.Presentation.Entities.StopPoint, Tfl.Api.Presentation.Entities", + "naptanId": "910GCLPHMJ1", + "platformName": "", + "icsCode": "1001069", + "commonName": "Clapham Junction Rail Station", + "placeType": "StopPoint", + "additionalProperties": [], + "lat": 51.464213513690005, + "lon": -0.17030672354 + }, + "arrivalPoint": { + "$type": "Tfl.Api.Presentation.Entities.StopPoint, Tfl.Api.Presentation.Entities", + "naptanId": "910GPURLEY", + "platformName": "", + "icsCode": "1001229", + "commonName": "Purley Rail Station", + "placeType": "StopPoint", + "additionalProperties": [], + "lat": 51.337705571730005, + "lon": -0.11364253998 + }, + "path": { + "$type": "Tfl.Api.Presentation.Entities.JourneyPlanner.Path, Tfl.Api.Presentation.Entities", + "lineString": "[[51.46422312424, -0.16951944213],[51.46411376332, -0.16967726788],[51.46347995298, -0.17055200838],[51.46312698529, -0.17098361318],[51.46265785887, -0.17146304237],[51.46219524963, -0.17178384645],[51.4612581257, -0.17223876773],[51.4604266007, -0.17254549894],[51.45993411241, -0.17268033187],[51.45934142215, -0.17273279358],[51.45841599036, -0.17278414734],[51.45775859754, -0.17272403341],[51.45709963504, -0.17256322372],[51.45644853799, -0.1723301339],[51.45527912786, -0.17172912523],[51.45450648694, -0.17119864988],[51.45153655, -0.16874106988],[51.44842007248, -0.16611697559],[51.4469517943, -0.16480864885],[51.44650377862, -0.16433731872],[51.44619191657, -0.16394688128],[51.44607803152, -0.1637696892],[51.44607803152, -0.1637696892],[51.44577714135, -0.16330154479],[51.44504147541, -0.1616905458],[51.44465744628, -0.16071303162],[51.44436327822, -0.15973192116],[51.44415066185, -0.15879071364],[51.4435801381, -0.15567662974],[51.44336364082, -0.1544909833],[51.44284487369, -0.15185419759],[51.44284487369, -0.15185419759],[51.44187762412, -0.14693882928],[51.44155319714, -0.14575763821],[51.44123444826, -0.14493596688],[51.44091774271, -0.14424372715],[51.44061206957, -0.14368055178],[51.44024371376, -0.14313431517],[51.44005043418, -0.14285437483],[51.43952838699, -0.1422568322],[51.43903648869, -0.14185952038],[51.43857360141, -0.14159053586],[51.43665311686, -0.14070449306],[51.43420614155, -0.13950900527],[51.43271167509, -0.13883600034],[51.43192525555, -0.13858023196],[51.43109595644, -0.13845569046],[51.43044822029, -0.13843886047],[51.42935114292, -0.1384402942],[51.42585084625, -0.13887023787],[51.42497912355, -0.13890565508],[51.42399818914, -0.13885920377],[51.42308709479, -0.13868046373],[51.4210596592, -0.13785670461],[51.42052486819, -0.1375907842],[51.41989769534, -0.13717041657],[51.41890971333, -0.13630237395],[51.41890971333, -0.13630237395],[51.41808280425, -0.13557588296],[51.41747153973, -0.13502547996],[51.41661998006, -0.13406780756],[51.41554608915, -0.13270217102],[51.41506709403, -0.13198825188],[51.41452060338, -0.13098948064],[51.41411051168, -0.1300858328],[51.41323317345, -0.12807959152],[51.41274404509, -0.12673343163],[51.41238370477, -0.12556897601],[51.4116173754, -0.12263802554],[51.41140927795, -0.12197549673],[51.41140927795, -0.12197549673],[51.41123833033, -0.12143125677],[51.41089107355, -0.12052518062],[51.40993706587, -0.11823481587],[51.40870624947, -0.1155101696],[51.40810177022, -0.11426967235],[51.40752794012, -0.1132580065],[51.40694719795, -0.11237605791],[51.39871584159, -0.10036515648],[51.39871584159, -0.10036515648],[51.39722145241, -0.09818524642],[51.39660138723, -0.09710405814],[51.39591046823, -0.09553708433],[51.39504538185, -0.09321552573],[51.39456812242, -0.09207101411],[51.39405794792, -0.09111476628],[51.39323660065, -0.08982651384],[51.39281595553, -0.08939843361],[51.39179792032, -0.08845759891],[51.39179792032, -0.08845759891],[51.39132770483, -0.08802305744],[51.38998080471, -0.08704432592],[51.38934400185, -0.08659657186],[51.38870907419, -0.0862637353],[51.38821129115, -0.08606891253],[51.38782322428, -0.08598449664],[51.38732896036, -0.08600512126],[51.38690752782, -0.08608019584],[51.38623822326, -0.08639556551],[51.38508168848, -0.08716240169],[51.38403908093, -0.08829810822],[51.38263699598, -0.08944873295],[51.38108118942, -0.09054820136],[51.37907744183, -0.09175244385],[51.37835466746, -0.09209863631],[51.37760376282, -0.09237413971],[51.37622355678, -0.09266142225],[51.37551431117, -0.09273400821],[51.37528195435, -0.09273864687],[51.37528195435, -0.09273864687],[51.37152282546, -0.09281368148],[51.36772286184, -0.09305777053],[51.36351160993, -0.09344817794],[51.36275051071, -0.09351500208],[51.36275051071, -0.09351500208],[51.3613384651, -0.0936389722],[51.35697828007, -0.09371945213],[51.3561063361, -0.09374128617],[51.35520031368, -0.09387943302],[51.35425052503, -0.09409120106],[51.35323946321, -0.0944060351],[51.35059876679, -0.09570756019],[51.35011791631, -0.0960003524],[51.34940714168, -0.09653243776],[51.34860836215, -0.09718303515],[51.34700222738, -0.09874728356],[51.34700222738, -0.09874728356],[51.34677583601, -0.09896776024],[51.34603445448, -0.0998312954],[51.34537371433, -0.10067710882],[51.34474109096, -0.10159353137],[51.34365555724, -0.10341888068],[51.3419242316, -0.10646251093],[51.33764835022, -0.11362544425]]", + "stopPoints": [ + { + "$type": "Tfl.Api.Presentation.Entities.Identifier, Tfl.Api.Presentation.Entities", + "id": "910GECROYDN", + "name": "East Croydon Rail Station", + "uri": "/StopPoint/910GECROYDN", + "type": "StopPoint", + "routeType": "Unknown", + "status": "Unknown" + }, + { + "$type": "Tfl.Api.Presentation.Entities.Identifier, Tfl.Api.Presentation.Entities", + "id": "910GPURLEY", + "name": "Purley Rail Station", + "uri": "/StopPoint/910GPURLEY", + "type": "StopPoint", + "routeType": "Unknown", + "status": "Unknown" + } + ], + "elevation": [] + }, + "routeOptions": [ + { + "$type": "Tfl.Api.Presentation.Entities.JourneyPlanner.RouteOption, Tfl.Api.Presentation.Entities", + "name": "Southern", + "directions": ["Reigate Rail Station"], + "lineIdentifier": { + "$type": "Tfl.Api.Presentation.Entities.Identifier, Tfl.Api.Presentation.Entities", + "id": "southern", + "name": "Southern", + "uri": "/Line/southern", + "type": "Line", + "crowding": { + "$type": "Tfl.Api.Presentation.Entities.Crowding, Tfl.Api.Presentation.Entities" + }, + "routeType": "Unknown", + "status": "Unknown" + } + } + ], + "mode": { + "$type": "Tfl.Api.Presentation.Entities.Identifier, Tfl.Api.Presentation.Entities", + "id": "national-rail", + "name": "national-rail", + "type": "Mode", + "routeType": "Unknown", + "status": "Unknown" + }, + "disruptions": [ + { + "$type": "Tfl.Api.Presentation.Entities.Disruption, Tfl.Api.Presentation.Entities", + "category": "PlannedWork", + "type": "routeBlocking", + "categoryDescription": "PlannedWork", + "description": "LONDON OVERGROUND: Saturday 22 and Sunday 23 August, no service between Clapham Junction and Willesden Junction. Please use local London Buses or London Underground connections.", + "summary": "", + "additionalInfo": "", + "created": "2020-07-20T13:05:00", + "lastUpdate": "2020-07-20T13:08:00" + }, + { + "$type": "Tfl.Api.Presentation.Entities.Disruption, Tfl.Api.Presentation.Entities", + "category": "PlannedWork", + "type": "routeBlocking", + "categoryDescription": "PlannedWork", + "description": "LONDON OVERGROUND: Saturday 22 and Sunday 23 August, no service between Highbury & Islington and New Cross / Clapham Junction / Crystal Palace / West Croydon. Use alternative London Overground services between Highbury & Islington and Dalston Kingsland, and Southern services between New Cross Gate and West Croydon / Crystal Palace. Replacement buses operate between Dalston Kingsland and New Cross Gate, and between Canada Water and Clapham Junction.", + "summary": "", + "additionalInfo": "Replacement buses operate:

Service M: Canada Water - Surrey Quays - Queens Road Peckham - Peckham Rye - Denmark Hill - Clapham High Street - Wandsworth Road - Clapham Junction.

Service X: Dalston Kingsland - Dalston Junction - Haggerston - Hoxton - Shoreditch High Street - Whitechapel (for local London Buses Route D3 to Shadwell and Wapping) - Tower Gateway DLR - Bermondsey (Jubilee line and for local London Buses 381 and C10 to Rotherhithe) - Canada Water - Surrey Quays - Deptford Bridge DLR - New Cross - New Cross Gate.", + "created": "2020-07-20T12:59:00", + "lastUpdate": "2020-07-20T12:59:00" + } + ], + "plannedWorks": [], + "isDisrupted": true, + "hasFixedLocations": true + }, + { + "$type": "Tfl.Api.Presentation.Entities.JourneyPlanner.Leg, Tfl.Api.Presentation.Entities", + "duration": 6, + "instruction": { + "$type": "Tfl.Api.Presentation.Entities.Instruction, Tfl.Api.Presentation.Entities", + "summary": "Southern to Whyteleafe", + "detailed": "Southern towards Caterham", + "steps": [] + }, + "obstacles": [], + "departureTime": "2020-08-22T16:45:00", + "arrivalTime": "2020-08-22T16:51:00", + "departurePoint": { + "$type": "Tfl.Api.Presentation.Entities.StopPoint, Tfl.Api.Presentation.Entities", + "naptanId": "910GPURLEY", + "platformName": "", + "icsCode": "1001229", + "commonName": "Purley Rail Station", + "placeType": "StopPoint", + "additionalProperties": [], + "lat": 51.337705571730005, + "lon": -0.11364253998 + }, + "arrivalPoint": { + "$type": "Tfl.Api.Presentation.Entities.StopPoint, Tfl.Api.Presentation.Entities", + "naptanId": "910GWHYTELF", + "platformName": "", + "icsCode": "1001536", + "commonName": "Whyteleafe Rail Station", + "placeType": "StopPoint", + "additionalProperties": [], + "lat": 51.31011721212, + "lon": -0.081084275970000008 + }, + "path": { + "$type": "Tfl.Api.Presentation.Entities.JourneyPlanner.Path, Tfl.Api.Presentation.Entities", + "lineString": "[[51.33765275882, -0.11361806006],[51.33685440701, -0.11495522308],[51.33640300448, -0.11540443545],[51.33586080835, -0.11579993602],[51.3353057007, -0.1159519014],[51.33476718183, -0.11601704687],[51.33432405649, -0.11586294219],[51.33390650658, -0.11562165735],[51.33348572406, -0.11517953088],[51.3330170034, -0.11455275785],[51.33181431142, -0.11302303643],[51.33131171304, -0.11252689328],[51.32909024347, -0.11083818875],[51.3282862097, -0.11005305598],[51.32774464156, -0.10937198519],[51.32726435575, -0.10858793314],[51.32684674084, -0.10778696406],[51.32640558178, -0.1066424971],[51.3260277835, -0.10552414726],[51.32476063955, -0.10096477688],[51.32476063955, -0.10096477688],[51.32432796476, -0.09940815207],[51.32379885573, -0.09783688626],[51.32325781404, -0.0966393138],[51.32252477244, -0.09524879176],[51.32162855229, -0.09377896698],[51.3162455421, -0.08573635823],[51.31572087174, -0.08499764247],[51.3148490705, -0.08392900764],[51.31422647412, -0.08325181443],[51.31366014223, -0.08271578822],[51.31287742232, -0.08214575055],[51.31236001252, -0.08185164673],[51.31185323316, -0.08165754833],[51.31074034975, -0.08124481017],[51.31021653589, -0.08110882907],[51.30996246403, -0.08106288566]]", + "stopPoints": [ + { + "$type": "Tfl.Api.Presentation.Entities.Identifier, Tfl.Api.Presentation.Entities", + "id": "910GKNLY", + "name": "Kenley Rail Station", + "uri": "/StopPoint/910GKNLY", + "type": "StopPoint", + "routeType": "Unknown", + "status": "Unknown" + }, + { + "$type": "Tfl.Api.Presentation.Entities.Identifier, Tfl.Api.Presentation.Entities", + "id": "910GWHYTELF", + "name": "Whyteleafe Rail Station", + "uri": "/StopPoint/910GWHYTELF", + "type": "StopPoint", + "routeType": "Unknown", + "status": "Unknown" + } + ], + "elevation": [] + }, + "routeOptions": [ + { + "$type": "Tfl.Api.Presentation.Entities.JourneyPlanner.RouteOption, Tfl.Api.Presentation.Entities", + "name": "Southern", + "directions": ["Caterham Rail Station"], + "lineIdentifier": { + "$type": "Tfl.Api.Presentation.Entities.Identifier, Tfl.Api.Presentation.Entities", + "id": "southern", + "name": "Southern", + "uri": "/Line/southern", + "type": "Line", + "crowding": { + "$type": "Tfl.Api.Presentation.Entities.Crowding, Tfl.Api.Presentation.Entities" + }, + "routeType": "Unknown", + "status": "Unknown" + } + } + ], + "mode": { + "$type": "Tfl.Api.Presentation.Entities.Identifier, Tfl.Api.Presentation.Entities", + "id": "national-rail", + "name": "national-rail", + "type": "Mode", + "routeType": "Unknown", + "status": "Unknown" + }, + "disruptions": [], + "plannedWorks": [], + "isDisrupted": false, + "hasFixedLocations": true + } + ] + }, + { + "$type": "Tfl.Api.Presentation.Entities.JourneyPlanner.Journey, Tfl.Api.Presentation.Entities", + "startDateTime": "2020-08-22T16:27:00", + "duration": 33, + "arrivalDateTime": "2020-08-22T17:00:00", + "legs": [ + { + "$type": "Tfl.Api.Presentation.Entities.JourneyPlanner.Leg, Tfl.Api.Presentation.Entities", + "duration": 25, + "instruction": { + "$type": "Tfl.Api.Presentation.Entities.Instruction, Tfl.Api.Presentation.Entities", + "summary": "Southern to Upper Warlingham", + "detailed": "Southern towards East Grinstead", + "steps": [] + }, + "obstacles": [], + "departureTime": "2020-08-22T16:27:00", + "arrivalTime": "2020-08-22T16:52:00", + "departurePoint": { + "$type": "Tfl.Api.Presentation.Entities.StopPoint, Tfl.Api.Presentation.Entities", + "naptanId": "910GCLPHMJ1", + "platformName": "", + "icsCode": "1001069", + "commonName": "Clapham Junction Rail Station", + "placeType": "StopPoint", + "additionalProperties": [], + "lat": 51.464213513690005, + "lon": -0.17030672354 + }, + "arrivalPoint": { + "$type": "Tfl.Api.Presentation.Entities.StopPoint, Tfl.Api.Presentation.Entities", + "naptanId": "910GUWRLNGH", + "platformName": "", + "icsCode": "1001538", + "commonName": "Upper Warlingham Rail Station", + "placeType": "StopPoint", + "additionalProperties": [], + "lat": 51.308345955760004, + "lon": -0.07781512552 + }, + "path": { + "$type": "Tfl.Api.Presentation.Entities.JourneyPlanner.Path, Tfl.Api.Presentation.Entities", + "lineString": "[[51.46422312424, -0.16951944213],[51.46411376332, -0.16967726788],[51.46347995298, -0.17055200838],[51.46312698529, -0.17098361318],[51.46265785887, -0.17146304237],[51.46219524963, -0.17178384645],[51.4612581257, -0.17223876773],[51.4604266007, -0.17254549894],[51.45993411241, -0.17268033187],[51.45934142215, -0.17273279358],[51.45841599036, -0.17278414734],[51.45775859754, -0.17272403341],[51.45709963504, -0.17256322372],[51.45644853799, -0.1723301339],[51.45527912786, -0.17172912523],[51.45450648694, -0.17119864988],[51.45153655, -0.16874106988],[51.44842007248, -0.16611697559],[51.4469517943, -0.16480864885],[51.44650377862, -0.16433731872],[51.44619191657, -0.16394688128],[51.44607803152, -0.1637696892],[51.44607803152, -0.1637696892],[51.44577714135, -0.16330154479],[51.44504147541, -0.1616905458],[51.44465744628, -0.16071303162],[51.44436327822, -0.15973192116],[51.44415066185, -0.15879071364],[51.4435801381, -0.15567662974],[51.44336364082, -0.1544909833],[51.44284487369, -0.15185419759],[51.44284487369, -0.15185419759],[51.44187762412, -0.14693882928],[51.44119256978, -0.14342678502],[51.44008101918, -0.13741409999],[51.43999259681, -0.13694286166],[51.43849627975, -0.12881669518],[51.43816802357, -0.12684451109],[51.43740495879, -0.12242978474],[51.43720287495, -0.12104242493],[51.43705491545, -0.11910610792],[51.43690135653, -0.1162635878],[51.43682617, -0.11494298493],[51.43683967845, -0.11354679209],[51.43691654015, -0.11217676218],[51.43680901717, -0.11052657495],[51.43674791119, -0.11008306896],[51.4366033727, -0.10948474125],[51.43639615655, -0.10890339378],[51.43613501762, -0.1083242792],[51.43583932192, -0.10783292544],[51.43547265963, -0.10740206158],[51.434253819, -0.10654604269],[51.43362630697, -0.10611160469],[51.43300615346, -0.10557616625],[51.43251274039, -0.1050930443],[51.43212693265, -0.10459109251],[51.43184779974, -0.10401280055],[51.43163273366, -0.10350379432],[51.43147065449, -0.10293505262],[51.43135397128, -0.10239320648],[51.43112455632, -0.10155392452],[51.43078450023, -0.10054660571],[51.43027065931, -0.09935949544],[51.429723426, -0.09833204191],[51.42837567345, -0.09618703768],[51.42794209255, -0.09551456812],[51.4275778302, -0.09468099141],[51.42728428581, -0.09377255961],[51.42704137908, -0.09266064136],[51.42676049874, -0.09087422746],[51.42638636355, -0.08943695991],[51.42631900492, -0.08916645932],[51.42621405856, -0.08879683476],[51.42433770865, -0.08348107196],[51.42393506435, -0.08250542097],[51.42351749764, -0.08171740231],[51.42271401713, -0.08042775364],[51.42180103537, -0.07904205752],[51.42158892621, -0.07872013602],[51.42099752618, -0.0777525041],[51.41854884369, -0.07375627481],[51.41794865357, -0.07280352145],[51.417459107, -0.07231921004],[51.417459107, -0.07231921004],[51.41712592153, -0.07198959459],[51.41646423223, -0.07167227634],[51.41580774499, -0.07167114055],[51.41494740574, -0.0718511575],[51.4142951741, -0.07210869756],[51.41264590671, -0.0729833881],[51.41229803203, -0.07315620008],[51.41156420952, -0.07337399513],[51.41058727808, -0.07357324191],[51.41020109411, -0.07360385418],[51.40974136441, -0.07353690009],[51.40911798743, -0.07336179094],[51.40873700986, -0.07316211677],[51.40827302661, -0.07283652371],[51.40745951823, -0.07203675436],[51.40648613819, -0.07081238358],[51.40556312185, -0.06991664318],[51.40509227361, -0.06972079668],[51.4047574061, -0.06959111755],[51.40436980294, -0.06953555061],[51.4039122013, -0.06959795434],[51.40342125694, -0.06981991421],[51.4030845025, -0.07012164279],[51.40210852463, -0.07147105132],[51.40169348745, -0.07193419883],[51.40086719515, -0.07254402005],[51.39737697546, -0.07470366097],[51.39737697546, -0.07470366097],[51.3940124714, -0.07678516942],[51.39307073968, -0.07748588248],[51.39296431502, -0.07757658977],[51.39215905905, -0.07782595577],[51.39104916642, -0.07869177392],[51.39008776019, -0.07983879968],[51.38877129801, -0.0818198914],[51.3882005695, -0.08266300862],[51.38620047111, -0.08573602106],[51.3857695115, -0.08632888644],[51.38508168848, -0.08716240169],[51.38403908093, -0.08829810822],[51.38263699598, -0.08944873295],[51.38108118942, -0.09054820136],[51.37907744183, -0.09175244385],[51.37835466746, -0.09209863631],[51.37760376282, -0.09237413971],[51.37622355678, -0.09266142225],[51.37551431117, -0.09273400821],[51.37528195435, -0.09273864687],[51.37528195435, -0.09273864687],[51.37152282546, -0.09281368148],[51.36772286184, -0.09305777053],[51.36351160993, -0.09344817794],[51.36275051071, -0.09351500208],[51.36275051071, -0.09351500208],[51.3613384651, -0.0936389722],[51.3608948463, -0.09345629285],[51.36021360085, -0.09303929707],[51.35968011419, -0.09286036049],[51.35897681488, -0.09274593631],[51.35677086713, -0.09257902831],[51.35443105293, -0.09247514291],[51.35314408463, -0.09241370347],[51.35261363537, -0.09242137451],[51.34997785306, -0.09291858652],[51.34932462683, -0.09311803565],[51.34827083341, -0.0935570914],[51.34827083341, -0.0935570914],[51.34825276191, -0.09356462058],[51.34549874515, -0.09508613567],[51.34451148471, -0.095758873],[51.34334891576, -0.0967116603],[51.34108852311, -0.09872927216],[51.33996853356, -0.09953657292],[51.33946117682, -0.09985906527],[51.33882730614, -0.10014370928],[51.33821899869, -0.10034114573],[51.33702655073, -0.10056272258],[51.33577692408, -0.10058566132],[51.33387233782, -0.10014757145],[51.33283234212, -0.0997886109],[51.33261671754, -0.09967856896],[51.33261671754, -0.09967856896],[51.33223386117, -0.09948318447],[51.33165149027, -0.09906225902],[51.33073125039, -0.09832516104],[51.32837980498, -0.09639852412],[51.32764990362, -0.09575412141],[51.32713941388, -0.09533030515],[51.32669252998, -0.09494692268],[51.32587205313, -0.09426326085],[51.32443206633, -0.09308861178],[51.32353641395, -0.09220719922],[51.32295879755, -0.09152790255],[51.32237883902, -0.09070519817],[51.3200716172, -0.08653862148],[51.31980373678, -0.0861048764],[51.31803989178, -0.08327942257],[51.31674717006, -0.08176910767],[51.31585971686, -0.08084466516],[51.31479111181, -0.07984172213],[51.31376338545, -0.07913845702],[51.31299434103, -0.07885489284],[51.31059446874, -0.07838119193],[51.30908757202, -0.07807109568],[51.30849984915, -0.07788088224]]", + "stopPoints": [ + { + "$type": "Tfl.Api.Presentation.Entities.Identifier, Tfl.Api.Presentation.Entities", + "id": "910GECROYDN", + "name": "East Croydon Rail Station", + "uri": "/StopPoint/910GECROYDN", + "type": "StopPoint", + "routeType": "Unknown", + "status": "Unknown" + }, + { + "$type": "Tfl.Api.Presentation.Entities.Identifier, Tfl.Api.Presentation.Entities", + "id": "910GSDSD", + "name": "Sanderstead Rail Station", + "uri": "/StopPoint/910GSDSD", + "type": "StopPoint", + "routeType": "Unknown", + "status": "Unknown" + }, + { + "$type": "Tfl.Api.Presentation.Entities.Identifier, Tfl.Api.Presentation.Entities", + "id": "910GRDLSDWN", + "name": "Riddlesdown Rail Station", + "uri": "/StopPoint/910GRDLSDWN", + "type": "StopPoint", + "routeType": "Unknown", + "status": "Unknown" + }, + { + "$type": "Tfl.Api.Presentation.Entities.Identifier, Tfl.Api.Presentation.Entities", + "id": "910GUWRLNGH", + "name": "Upper Warlingham Rail Station", + "uri": "/StopPoint/910GUWRLNGH", + "type": "StopPoint", + "routeType": "Unknown", + "status": "Unknown" + } + ], + "elevation": [] + }, + "routeOptions": [ + { + "$type": "Tfl.Api.Presentation.Entities.JourneyPlanner.RouteOption, Tfl.Api.Presentation.Entities", + "name": "Southern", + "directions": ["East Grinstead Rail Station"], + "lineIdentifier": { + "$type": "Tfl.Api.Presentation.Entities.Identifier, Tfl.Api.Presentation.Entities", + "id": "southern", + "name": "Southern", + "uri": "/Line/southern", + "type": "Line", + "crowding": { + "$type": "Tfl.Api.Presentation.Entities.Crowding, Tfl.Api.Presentation.Entities" + }, + "routeType": "Unknown", + "status": "Unknown" + } + } + ], + "mode": { + "$type": "Tfl.Api.Presentation.Entities.Identifier, Tfl.Api.Presentation.Entities", + "id": "national-rail", + "name": "national-rail", + "type": "Mode", + "routeType": "Unknown", + "status": "Unknown" + }, + "disruptions": [ + { + "$type": "Tfl.Api.Presentation.Entities.Disruption, Tfl.Api.Presentation.Entities", + "category": "PlannedWork", + "type": "routeBlocking", + "categoryDescription": "PlannedWork", + "description": "LONDON OVERGROUND: Saturday 22 and Sunday 23 August, no service between Clapham Junction and Willesden Junction. Please use local London Buses or London Underground connections.", + "summary": "", + "additionalInfo": "", + "created": "2020-07-20T13:05:00", + "lastUpdate": "2020-07-20T13:08:00" + }, + { + "$type": "Tfl.Api.Presentation.Entities.Disruption, Tfl.Api.Presentation.Entities", + "category": "PlannedWork", + "type": "routeBlocking", + "categoryDescription": "PlannedWork", + "description": "LONDON OVERGROUND: Saturday 22 and Sunday 23 August, no service between Highbury & Islington and New Cross / Clapham Junction / Crystal Palace / West Croydon. Use alternative London Overground services between Highbury & Islington and Dalston Kingsland, and Southern services between New Cross Gate and West Croydon / Crystal Palace. Replacement buses operate between Dalston Kingsland and New Cross Gate, and between Canada Water and Clapham Junction.", + "summary": "", + "additionalInfo": "Replacement buses operate:

Service M: Canada Water - Surrey Quays - Queens Road Peckham - Peckham Rye - Denmark Hill - Clapham High Street - Wandsworth Road - Clapham Junction.

Service X: Dalston Kingsland - Dalston Junction - Haggerston - Hoxton - Shoreditch High Street - Whitechapel (for local London Buses Route D3 to Shadwell and Wapping) - Tower Gateway DLR - Bermondsey (Jubilee line and for local London Buses 381 and C10 to Rotherhithe) - Canada Water - Surrey Quays - Deptford Bridge DLR - New Cross - New Cross Gate.", + "created": "2020-07-20T12:59:00", + "lastUpdate": "2020-07-20T12:59:00" + }, + { + "$type": "Tfl.Api.Presentation.Entities.Disruption, Tfl.Api.Presentation.Entities", + "category": "RealTime", + "type": "routeBlocking", + "categoryDescription": "RealTime", + "description": "CHANGES TO SOUTHDOWN PSV ROUTES 357 and 409: Until further notice, Route 357 will no longer operate between Selsdon and Redhill, and operates between Redhill and Reigate only. Route 409 continues to operate between Selsdon and Godstone / East Grinstead on Monday to Saturday to a revised timetable.", + "summary": "", + "additionalInfo": "", + "created": "2020-04-01T10:01:00", + "lastUpdate": "2020-06-03T14:54:00" + } + ], + "plannedWorks": [], + "isDisrupted": true, + "hasFixedLocations": true + }, + { + "$type": "Tfl.Api.Presentation.Entities.JourneyPlanner.Leg, Tfl.Api.Presentation.Entities", + "duration": 8, + "instruction": { + "$type": "Tfl.Api.Presentation.Entities.Instruction, Tfl.Api.Presentation.Entities", + "summary": "Walk to Whyteleafe Station", + "detailed": "Walk to Whyteleafe Station", + "steps": [ + { + "$type": "Tfl.Api.Presentation.Entities.InstructionStep, Tfl.Api.Presentation.Entities", + "description": "Station Approach for 173 metres", + "turnDirection": "STRAIGHT", + "streetName": "Station Approach", + "distance": 173, + "cumulativeDistance": 173, + "skyDirection": 348, + "skyDirectionDescription": "North", + "cumulativeTravelTime": 157, + "latitude": 51.308637531159995, + "longitude": -0.07804685574, + "pathAttribute": { + "$type": "Tfl.Api.Presentation.Entities.PathAttribute, Tfl.Api.Presentation.Entities" + }, + "descriptionHeading": "Continue along ", + "trackType": "None" + }, + { + "$type": "Tfl.Api.Presentation.Entities.InstructionStep, Tfl.Api.Presentation.Entities", + "description": "on to Hillbury Road, continue for 57 metres", + "turnDirection": "LEFT", + "streetName": "Hillbury Road", + "distance": 57, + "cumulativeDistance": 230, + "skyDirection": 271, + "skyDirectionDescription": "North", + "cumulativeTravelTime": 208, + "latitude": 51.31014913393, + "longitude": -0.0786437196, + "pathAttribute": { + "$type": "Tfl.Api.Presentation.Entities.PathAttribute, Tfl.Api.Presentation.Entities" + }, + "descriptionHeading": "Turn left", + "trackType": "None" + }, + { + "$type": "Tfl.Api.Presentation.Entities.InstructionStep, Tfl.Api.Presentation.Entities", + "description": "for 21 metres", + "turnDirection": "SLIGHT_RIGHT", + "streetName": "", + "distance": 21, + "cumulativeDistance": 251, + "skyDirection": 307, + "skyDirectionDescription": "North", + "cumulativeTravelTime": 230, + "latitude": 51.310171528619996, + "longitude": -0.07946064228, + "pathAttribute": { + "$type": "Tfl.Api.Presentation.Entities.PathAttribute, Tfl.Api.Presentation.Entities" + }, + "descriptionHeading": "Take a slight right", + "trackType": "None" + }, + { + "$type": "Tfl.Api.Presentation.Entities.InstructionStep, Tfl.Api.Presentation.Entities", + "description": "on to Whyteleafe Hill, continue for 34 metres", + "turnDirection": "STRAIGHT", + "streetName": "Whyteleafe Hill", + "distance": 34, + "cumulativeDistance": 285, + "skyDirection": 220, + "skyDirectionDescription": "North", + "cumulativeTravelTime": 261, + "latitude": 51.31015708268, + "longitude": -0.0796764712, + "pathAttribute": { + "$type": "Tfl.Api.Presentation.Entities.PathAttribute, Tfl.Api.Presentation.Entities" + }, + "descriptionHeading": "Continue along ", + "trackType": "None" + } + ] + }, + "obstacles": [ + { + "$type": "Tfl.Api.Presentation.Entities.JourneyPlanner.Obstacle, Tfl.Api.Presentation.Entities", + "type": "STAIRS", + "incline": "DOWN", + "stopId": 1001538, + "position": "IDEST" + }, + { + "$type": "Tfl.Api.Presentation.Entities.JourneyPlanner.Obstacle, Tfl.Api.Presentation.Entities", + "type": "WALKWAY", + "incline": "LEVEL", + "stopId": 1001538, + "position": "IDEST" + } + ], + "departureTime": "2020-08-22T16:52:00", + "arrivalTime": "2020-08-22T17:00:00", + "departurePoint": { + "$type": "Tfl.Api.Presentation.Entities.StopPoint, Tfl.Api.Presentation.Entities", + "naptanId": "910GUWRLNGH", + "platformName": "", + "icsCode": "1001538", + "commonName": "Upper Warlingham Rail Station", + "placeType": "StopPoint", + "additionalProperties": [], + "lat": 51.308345955760004, + "lon": -0.07781512552 + }, + "arrivalPoint": { + "$type": "Tfl.Api.Presentation.Entities.StopPoint, Tfl.Api.Presentation.Entities", + "platformName": "", + "icsCode": "1001536", + "commonName": "Whyteleafe Station", + "placeType": "StopPoint", + "additionalProperties": [], + "lat": 51.31011721212, + "lon": -0.081084275970000008 + }, + "path": { + "$type": "Tfl.Api.Presentation.Entities.JourneyPlanner.Path, Tfl.Api.Presentation.Entities", + "lineString": "[[51.30849990644, -0.07788043164],[51.30863753116, -0.07804685574],[51.30862116544, -0.07816854357],[51.30986889932, -0.07855498742],[51.31014913393, -0.0786437196],[51.31017152862, -0.07946064228],[51.3102273302, -0.07957309956],[51.31015708268, -0.0796764712],[51.30998134591, -0.07992772968],[51.30992585421, -0.08000289139],[51.30984037994, -0.08010579353]]", + "stopPoints": [ + { + "$type": "Tfl.Api.Presentation.Entities.Identifier, Tfl.Api.Presentation.Entities", + "name": "Whyteleafe Station", + "uri": "/StopPoint/", + "type": "StopPoint", + "routeType": "Unknown", + "status": "Unknown" + } + ], + "elevation": [] + }, + "routeOptions": [ + { + "$type": "Tfl.Api.Presentation.Entities.JourneyPlanner.RouteOption, Tfl.Api.Presentation.Entities", + "name": "", + "directions": [""] + } + ], + "mode": { + "$type": "Tfl.Api.Presentation.Entities.Identifier, Tfl.Api.Presentation.Entities", + "id": "walking", + "name": "walking", + "type": "Mode", + "routeType": "Unknown", + "status": "Unknown" + }, + "disruptions": [ + { + "$type": "Tfl.Api.Presentation.Entities.Disruption, Tfl.Api.Presentation.Entities", + "category": "RealTime", + "type": "routeBlocking", + "categoryDescription": "RealTime", + "description": "CHANGES TO SOUTHDOWN PSV ROUTES 357 and 409: Until further notice, Route 357 will no longer operate between Selsdon and Redhill, and operates between Redhill and Reigate only. Route 409 continues to operate between Selsdon and Godstone / East Grinstead on Monday to Saturday to a revised timetable.", + "summary": "", + "additionalInfo": "", + "created": "2020-04-01T10:01:00", + "lastUpdate": "2020-06-03T14:54:00" + } + ], + "plannedWorks": [], + "isDisrupted": true, + "hasFixedLocations": true + } + ] + }, + { + "$type": "Tfl.Api.Presentation.Entities.JourneyPlanner.Journey, Tfl.Api.Presentation.Entities", + "startDateTime": "2020-08-22T16:31:00", + "duration": 39, + "arrivalDateTime": "2020-08-22T17:10:00", + "legs": [ + { + "$type": "Tfl.Api.Presentation.Entities.JourneyPlanner.Leg, Tfl.Api.Presentation.Entities", + "duration": 9, + "instruction": { + "$type": "Tfl.Api.Presentation.Entities.Instruction, Tfl.Api.Presentation.Entities", + "summary": "Southern to East Croydon", + "detailed": "Southern towards Eastbourne", + "steps": [] + }, + "obstacles": [], + "departureTime": "2020-08-22T16:31:00", + "arrivalTime": "2020-08-22T16:40:00", + "departurePoint": { + "$type": "Tfl.Api.Presentation.Entities.StopPoint, Tfl.Api.Presentation.Entities", + "naptanId": "910GCLPHMJ1", + "platformName": "", + "icsCode": "1001069", + "commonName": "Clapham Junction Rail Station", + "placeType": "StopPoint", + "additionalProperties": [], + "lat": 51.464213513690005, + "lon": -0.17030672354 + }, + "arrivalPoint": { + "$type": "Tfl.Api.Presentation.Entities.StopPoint, Tfl.Api.Presentation.Entities", + "naptanId": "910GECROYDN", + "platformName": "", + "icsCode": "1001089", + "commonName": "East Croydon Rail Station", + "placeType": "StopPoint", + "additionalProperties": [], + "lat": 51.375282995250004, + "lon": -0.092887309559999992 + }, + "path": { + "$type": "Tfl.Api.Presentation.Entities.JourneyPlanner.Path, Tfl.Api.Presentation.Entities", + "lineString": "[[51.46422312424, -0.16951944213],[51.46411376332, -0.16967726788],[51.46347995298, -0.17055200838],[51.46312698529, -0.17098361318],[51.46265785887, -0.17146304237],[51.46219524963, -0.17178384645],[51.4612581257, -0.17223876773],[51.4604266007, -0.17254549894],[51.45993411241, -0.17268033187],[51.45934142215, -0.17273279358],[51.45841599036, -0.17278414734],[51.45775859754, -0.17272403341],[51.45709963504, -0.17256322372],[51.45644853799, -0.1723301339],[51.45527912786, -0.17172912523],[51.45450648694, -0.17119864988],[51.45153655, -0.16874106988],[51.44842007248, -0.16611697559],[51.4469517943, -0.16480864885],[51.44650377862, -0.16433731872],[51.44619191657, -0.16394688128],[51.44577714135, -0.16330154479],[51.44504147541, -0.1616905458],[51.44465744628, -0.16071303162],[51.44436327822, -0.15973192116],[51.44415066185, -0.15879071364],[51.4435801381, -0.15567662974],[51.44336364082, -0.1544909833],[51.44187762412, -0.14693882928],[51.44155319714, -0.14575763821],[51.44123444826, -0.14493596688],[51.44091774271, -0.14424372715],[51.44061206957, -0.14368055178],[51.44024371376, -0.14313431517],[51.44005043418, -0.14285437483],[51.43952838699, -0.1422568322],[51.43903648869, -0.14185952038],[51.43857360141, -0.14159053586],[51.43665311686, -0.14070449306],[51.43420614155, -0.13950900527],[51.43271167509, -0.13883600034],[51.43192525555, -0.13858023196],[51.43109595644, -0.13845569046],[51.43044822029, -0.13843886047],[51.42935114292, -0.1384402942],[51.42585084625, -0.13887023787],[51.42497912355, -0.13890565508],[51.42399818914, -0.13885920377],[51.42308709479, -0.13868046373],[51.4210596592, -0.13785670461],[51.42052486819, -0.1375907842],[51.41989769534, -0.13717041657],[51.41808280425, -0.13557588296],[51.41747153973, -0.13502547996],[51.41661998006, -0.13406780756],[51.41554608915, -0.13270217102],[51.41506709403, -0.13198825188],[51.41452060338, -0.13098948064],[51.41411051168, -0.1300858328],[51.41323317345, -0.12807959152],[51.41274404509, -0.12673343163],[51.41238370477, -0.12556897601],[51.4116173754, -0.12263802554],[51.41123833033, -0.12143125677],[51.41089107355, -0.12052518062],[51.40993706587, -0.11823481587],[51.40870624947, -0.1155101696],[51.40810177022, -0.11426967235],[51.40752794012, -0.1132580065],[51.40694719795, -0.11237605791],[51.39722145241, -0.09818524642],[51.39660138723, -0.09710405814],[51.39591046823, -0.09553708433],[51.39504538185, -0.09321552573],[51.39456812242, -0.09207101411],[51.39405794792, -0.09111476628],[51.39323660065, -0.08982651384],[51.39281595553, -0.08939843361],[51.39179792032, -0.08845759891],[51.39179792032, -0.08845759891],[51.39132770483, -0.08802305744],[51.38998080471, -0.08704432592],[51.38934400185, -0.08659657186],[51.38870907419, -0.0862637353],[51.38821129115, -0.08606891253],[51.38782322428, -0.08598449664],[51.38732896036, -0.08600512126],[51.38690752782, -0.08608019584],[51.38623822326, -0.08639556551],[51.38508168848, -0.08716240169],[51.38403908093, -0.08829810822],[51.38263699598, -0.08944873295],[51.38108118942, -0.09054820136],[51.37907744183, -0.09175244385],[51.37835466746, -0.09209863631],[51.37760376282, -0.09237413971],[51.37622355678, -0.09266142225],[51.37551431117, -0.09273400821],[51.37528195435, -0.09273864687]]", + "stopPoints": [ + { + "$type": "Tfl.Api.Presentation.Entities.Identifier, Tfl.Api.Presentation.Entities", + "id": "910GECROYDN", + "name": "East Croydon Rail Station", + "uri": "/StopPoint/910GECROYDN", + "type": "StopPoint", + "routeType": "Unknown", + "status": "Unknown" + } + ], + "elevation": [] + }, + "routeOptions": [ + { + "$type": "Tfl.Api.Presentation.Entities.JourneyPlanner.RouteOption, Tfl.Api.Presentation.Entities", + "name": "Southern", + "directions": ["Eastbourne Rail Station"], + "lineIdentifier": { + "$type": "Tfl.Api.Presentation.Entities.Identifier, Tfl.Api.Presentation.Entities", + "id": "southern", + "name": "Southern", + "uri": "/Line/southern", + "type": "Line", + "crowding": { + "$type": "Tfl.Api.Presentation.Entities.Crowding, Tfl.Api.Presentation.Entities" + }, + "routeType": "Unknown", + "status": "Unknown" + } + } + ], + "mode": { + "$type": "Tfl.Api.Presentation.Entities.Identifier, Tfl.Api.Presentation.Entities", + "id": "national-rail", + "name": "national-rail", + "type": "Mode", + "routeType": "Unknown", + "status": "Unknown" + }, + "disruptions": [ + { + "$type": "Tfl.Api.Presentation.Entities.Disruption, Tfl.Api.Presentation.Entities", + "category": "PlannedWork", + "type": "routeBlocking", + "categoryDescription": "PlannedWork", + "description": "LONDON OVERGROUND: Saturday 22 and Sunday 23 August, no service between Clapham Junction and Willesden Junction. Please use local London Buses or London Underground connections.", + "summary": "", + "additionalInfo": "", + "created": "2020-07-20T13:05:00", + "lastUpdate": "2020-07-20T13:08:00" + }, + { + "$type": "Tfl.Api.Presentation.Entities.Disruption, Tfl.Api.Presentation.Entities", + "category": "PlannedWork", + "type": "routeBlocking", + "categoryDescription": "PlannedWork", + "description": "LONDON OVERGROUND: Saturday 22 and Sunday 23 August, no service between Highbury & Islington and New Cross / Clapham Junction / Crystal Palace / West Croydon. Use alternative London Overground services between Highbury & Islington and Dalston Kingsland, and Southern services between New Cross Gate and West Croydon / Crystal Palace. Replacement buses operate between Dalston Kingsland and New Cross Gate, and between Canada Water and Clapham Junction.", + "summary": "", + "additionalInfo": "Replacement buses operate:

Service M: Canada Water - Surrey Quays - Queens Road Peckham - Peckham Rye - Denmark Hill - Clapham High Street - Wandsworth Road - Clapham Junction.

Service X: Dalston Kingsland - Dalston Junction - Haggerston - Hoxton - Shoreditch High Street - Whitechapel (for local London Buses Route D3 to Shadwell and Wapping) - Tower Gateway DLR - Bermondsey (Jubilee line and for local London Buses 381 and C10 to Rotherhithe) - Canada Water - Surrey Quays - Deptford Bridge DLR - New Cross - New Cross Gate.", + "created": "2020-07-20T12:59:00", + "lastUpdate": "2020-07-20T12:59:00" + } + ], + "plannedWorks": [], + "isDisrupted": true, + "hasFixedLocations": true + }, + { + "$type": "Tfl.Api.Presentation.Entities.JourneyPlanner.Leg, Tfl.Api.Presentation.Entities", + "duration": 16, + "instruction": { + "$type": "Tfl.Api.Presentation.Entities.Instruction, Tfl.Api.Presentation.Entities", + "summary": "Southern to Whyteleafe", + "detailed": "Southern towards Caterham", + "steps": [] + }, + "obstacles": [], + "departureTime": "2020-08-22T16:54:00", + "arrivalTime": "2020-08-22T17:10:00", + "departurePoint": { + "$type": "Tfl.Api.Presentation.Entities.StopPoint, Tfl.Api.Presentation.Entities", + "naptanId": "910GECROYDN", + "platformName": "", + "icsCode": "1001089", + "commonName": "East Croydon Rail Station", + "placeType": "StopPoint", + "additionalProperties": [], + "lat": 51.375282995250004, + "lon": -0.092887309559999992 + }, + "arrivalPoint": { + "$type": "Tfl.Api.Presentation.Entities.StopPoint, Tfl.Api.Presentation.Entities", + "naptanId": "910GWHYTELF", + "platformName": "", + "icsCode": "1001536", + "commonName": "Whyteleafe Rail Station", + "placeType": "StopPoint", + "additionalProperties": [], + "lat": 51.31011721212, + "lon": -0.081084275970000008 + }, + "path": { + "$type": "Tfl.Api.Presentation.Entities.JourneyPlanner.Path, Tfl.Api.Presentation.Entities", + "lineString": "[[51.37528195435, -0.09273864687],[51.37152282546, -0.09281368148],[51.36772286184, -0.09305777053],[51.36351160993, -0.09344817794],[51.36275051071, -0.09351500208],[51.36275051071, -0.09351500208],[51.3613384651, -0.0936389722],[51.35697828007, -0.09371945213],[51.3561063361, -0.09374128617],[51.35520031368, -0.09387943302],[51.35425052503, -0.09409120106],[51.35323946321, -0.0944060351],[51.35059876679, -0.09570756019],[51.35011791631, -0.0960003524],[51.34940714168, -0.09653243776],[51.34860836215, -0.09718303515],[51.34700222738, -0.09874728356],[51.34700222738, -0.09874728356],[51.34677583601, -0.09896776024],[51.34603445448, -0.0998312954],[51.34537371433, -0.10067710882],[51.34474109096, -0.10159353137],[51.34365555724, -0.10341888068],[51.3419242316, -0.10646251093],[51.33765275882, -0.11361806006],[51.33765275882, -0.11361806006],[51.33685440701, -0.11495522308],[51.33640300448, -0.11540443545],[51.33586080835, -0.11579993602],[51.3353057007, -0.1159519014],[51.33476718183, -0.11601704687],[51.33432405649, -0.11586294219],[51.33390650658, -0.11562165735],[51.33348572406, -0.11517953088],[51.3330170034, -0.11455275785],[51.33181431142, -0.11302303643],[51.33131171304, -0.11252689328],[51.32909024347, -0.11083818875],[51.3282862097, -0.11005305598],[51.32774464156, -0.10937198519],[51.32726435575, -0.10858793314],[51.32684674084, -0.10778696406],[51.32640558178, -0.1066424971],[51.3260277835, -0.10552414726],[51.32476063955, -0.10096477688],[51.32476063955, -0.10096477688],[51.32432796476, -0.09940815207],[51.32379885573, -0.09783688626],[51.32325781404, -0.0966393138],[51.32252477244, -0.09524879176],[51.32162855229, -0.09377896698],[51.3162455421, -0.08573635823],[51.31572087174, -0.08499764247],[51.3148490705, -0.08392900764],[51.31422647412, -0.08325181443],[51.31366014223, -0.08271578822],[51.31287742232, -0.08214575055],[51.31236001252, -0.08185164673],[51.31185323316, -0.08165754833],[51.31074034975, -0.08124481017],[51.31021653589, -0.08110882907],[51.30996246403, -0.08106288566]]", + "stopPoints": [ + { + "$type": "Tfl.Api.Presentation.Entities.Identifier, Tfl.Api.Presentation.Entities", + "id": "910GPURLEY", + "name": "Purley Rail Station", + "uri": "/StopPoint/910GPURLEY", + "type": "StopPoint", + "routeType": "Unknown", + "status": "Unknown" + }, + { + "$type": "Tfl.Api.Presentation.Entities.Identifier, Tfl.Api.Presentation.Entities", + "id": "910GKNLY", + "name": "Kenley Rail Station", + "uri": "/StopPoint/910GKNLY", + "type": "StopPoint", + "routeType": "Unknown", + "status": "Unknown" + }, + { + "$type": "Tfl.Api.Presentation.Entities.Identifier, Tfl.Api.Presentation.Entities", + "id": "910GWHYTELF", + "name": "Whyteleafe Rail Station", + "uri": "/StopPoint/910GWHYTELF", + "type": "StopPoint", + "routeType": "Unknown", + "status": "Unknown" + } + ], + "elevation": [] + }, + "routeOptions": [ + { + "$type": "Tfl.Api.Presentation.Entities.JourneyPlanner.RouteOption, Tfl.Api.Presentation.Entities", + "name": "Southern", + "directions": ["Caterham Rail Station"], + "lineIdentifier": { + "$type": "Tfl.Api.Presentation.Entities.Identifier, Tfl.Api.Presentation.Entities", + "id": "southern", + "name": "Southern", + "uri": "/Line/southern", + "type": "Line", + "crowding": { + "$type": "Tfl.Api.Presentation.Entities.Crowding, Tfl.Api.Presentation.Entities" + }, + "routeType": "Unknown", + "status": "Unknown" + } + } + ], + "mode": { + "$type": "Tfl.Api.Presentation.Entities.Identifier, Tfl.Api.Presentation.Entities", + "id": "national-rail", + "name": "national-rail", + "type": "Mode", + "routeType": "Unknown", + "status": "Unknown" + }, + "disruptions": [], + "plannedWorks": [], + "isDisrupted": false, + "hasFixedLocations": true + } + ] + } + ], + "lines": [], + "stopMessages": [ + "LONDON OVERGROUND: Saturday 22 and Sunday 23 August, no service between Clapham Junction and Willesden Junction. Please use local London Buses or London Underground connections.", + "LONDON OVERGROUND: Saturday 22 and Sunday 23 August, no service between Highbury & Islington and New Cross / Clapham Junction / Crystal Palace / West Croydon. Use alternative London Overground services between Highbury & Islington and Dalston Kingsland, and Southern services between New Cross Gate and West Croydon / Crystal Palace. Replacement buses operate between Dalston Kingsland and New Cross Gate, and between Canada Water and Clapham Junction." + ], + "recommendedMaxAgeMinutes": 5, + "searchCriteria": { + "$type": "Tfl.Api.Presentation.Entities.JourneyPlanner.SearchCriteria, Tfl.Api.Presentation.Entities", + "dateTime": "2020-08-22T16:25:00", + "dateTimeType": "Departing", + "timeAdjustments": { + "$type": "Tfl.Api.Presentation.Entities.JourneyPlanner.TimeAdjustments, Tfl.Api.Presentation.Entities", + "earliest": { + "$type": "Tfl.Api.Presentation.Entities.JourneyPlanner.TimeAdjustment, Tfl.Api.Presentation.Entities", + "date": "20200822", + "time": "0300", + "timeIs": "departing", + "uri": "/journey/journeyresults/1001069/to/9100whytelf?app_id=5f8da806&app_key=e430cb9dedfdcb75dee6cfbe77c4e108&time=0300&date=20200822&timeIs=departing" + }, + "earlier": { + "$type": "Tfl.Api.Presentation.Entities.JourneyPlanner.TimeAdjustment, Tfl.Api.Presentation.Entities", + "date": "20200822", + "time": "1616", + "timeIs": "departing", + "uri": "/journey/journeyresults/1001069/to/9100whytelf?app_id=5f8da806&app_key=e430cb9dedfdcb75dee6cfbe77c4e108&time=1616&date=20200822&timeIs=departing" + }, + "later": { + "$type": "Tfl.Api.Presentation.Entities.JourneyPlanner.TimeAdjustment, Tfl.Api.Presentation.Entities", + "date": "20200822", + "time": "1631", + "timeIs": "departing", + "uri": "/journey/journeyresults/1001069/to/9100whytelf?app_id=5f8da806&app_key=e430cb9dedfdcb75dee6cfbe77c4e108&time=1631&date=20200822&timeIs=departing" + }, + "latest": { + "$type": "Tfl.Api.Presentation.Entities.JourneyPlanner.TimeAdjustment, Tfl.Api.Presentation.Entities", + "date": "20200823", + "time": "0300", + "timeIs": "departing", + "uri": "/journey/journeyresults/1001069/to/9100whytelf?app_id=5f8da806&app_key=e430cb9dedfdcb75dee6cfbe77c4e108&time=0300&date=20200823&timeIs=departing" + } + } + }, + "journeyVector": { + "$type": "Tfl.Api.Presentation.Entities.JourneyPlanner.JourneyVector, Tfl.Api.Presentation.Entities", + "from": "1001069", + "to": "1001536", + "via": "", + "uri": "/journey/journeyresults/1001069/to/9100whytelf?app_id=5f8da806&app_key=e430cb9dedfdcb75dee6cfbe77c4e108&time=1625&date=20200822" + } +} diff --git a/testdata/single_fare_finder.json b/testdata/single_fare_finder.json new file mode 100644 index 0000000..807f2d2 --- /dev/null +++ b/testdata/single_fare_finder.json @@ -0,0 +1,191 @@ +[ + { + "$type": "Tfl.Api.Presentation.Entities.Fares.FaresSection, Tfl.Api.Presentation.Entities", + "header": "Single Fare Finder", + "index": 1, + "journey": { + "$type": "Tfl.Api.Presentation.Entities.Fares.Journey, Tfl.Api.Presentation.Entities", + "fromStation": { + "$type": "Tfl.Api.Presentation.Entities.Fares.FareStation, Tfl.Api.Presentation.Entities", + "atcoCode": "940GZZLUCYF", + "commonName": "Canary Wharf Underground Station", + "fareCategory": "All" + }, + "toStation": { + "$type": "Tfl.Api.Presentation.Entities.Fares.FareStation, Tfl.Api.Presentation.Entities", + "atcoCode": "910GPURLEYO", + "commonName": "Purley Oaks Rail Station", + "fareCategory": "All" + } + }, + "rows": [ + { + "$type": "Tfl.Api.Presentation.Entities.Fares.FareDetails, Tfl.Api.Presentation.Entities", + "startDate": "2020-04-19T23:00:00Z", + "endDate": "2021-04-19T23:00:00Z", + "passengerType": "Adult", + "contactlessPAYGOnlyFare": false, + "from": "Canary Wharf Underground Station", + "to": "Purley Oaks Rail Station", + "fromStation": "940GZZLUCYF", + "toStation": "910GPURLEYO", + "displayName": "Default Route", + "displayOrder": 0, + "routeDescription": "Default route", + "specialFare": false, + "throughFare": false, + "isTour": false, + "ticketsAvailable": [ + { + "$type": "Tfl.Api.Presentation.Entities.Fares.Ticket, Tfl.Api.Presentation.Entities", + "passengerType": "Adult", + "ticketType": { + "$type": "Tfl.Api.Presentation.Entities.Fares.TicketType, Tfl.Api.Presentation.Entities", + "type": "Pay as you go", + "description": "Pay as you go" + }, + "ticketTime": { + "$type": "Tfl.Api.Presentation.Entities.Fares.TicketTime, Tfl.Api.Presentation.Entities", + "type": "Off Peak", + "description": "At all other times including public holidays." + }, + "cost": "5.70", + "description": "Pay as you go", + "mode": "national-rail", + "displayOrder": 1, + "messages": [] + }, + { + "$type": "Tfl.Api.Presentation.Entities.Fares.Ticket, Tfl.Api.Presentation.Entities", + "passengerType": "Adult", + "ticketType": { + "$type": "Tfl.Api.Presentation.Entities.Fares.TicketType, Tfl.Api.Presentation.Entities", + "type": "Pay as you go", + "description": "Pay as you go" + }, + "ticketTime": { + "$type": "Tfl.Api.Presentation.Entities.Fares.TicketTime, Tfl.Api.Presentation.Entities", + "type": "Peak", + "description": "Monday to Friday from 0630 to 0930 and from 1600 to 1900." + }, + "cost": "8.40", + "description": "Pay as you go", + "mode": "national-rail", + "displayOrder": 2, + "messages": [] + } + ], + "messages": [] + } + ], + "messages": [ + { + "$type": "Tfl.Api.Presentation.Entities.Message, Tfl.Api.Presentation.Entities", + "bulletOrder": 0, + "messageText": "When you pay as you go, you must touch your card on a yellow card reader at the start and end of your journey. If you do not, you may be charged a maximum fare." + }, + { + "$type": "Tfl.Api.Presentation.Entities.Message, Tfl.Api.Presentation.Entities", + "bulletOrder": 0, + "messageText": "Some journeys are charged via Zone 1 irrespective of the route taken." + }, + { + "$type": "Tfl.Api.Presentation.Entities.Message, Tfl.Api.Presentation.Entities", + "bulletOrder": 0, + "messageText": "Cash single and return tickets are valid for travel only on the date shown on the ticket and up to 04:29 the next day." + }, + { + "$type": "Tfl.Api.Presentation.Entities.Message, Tfl.Api.Presentation.Entities", + "bulletOrder": 0, + "messageText": "Cash return fares are double the equivalent single fare. In some cases a Day Travelcard may be cheaper." + }, + { + "$type": "Tfl.Api.Presentation.Entities.Message, Tfl.Api.Presentation.Entities", + "bulletOrder": 0, + "messageText": "Fares shown do not include travel on Gatwick Express, Heathrow Express or Southeastern high speed services unless stated." + } + ] + }, + { + "$type": "Tfl.Api.Presentation.Entities.Fares.FaresSection, Tfl.Api.Presentation.Entities", + "header": "Alternate Fares", + "index": 2, + "journey": { + "$type": "Tfl.Api.Presentation.Entities.Fares.Journey, Tfl.Api.Presentation.Entities", + "fromStation": { + "$type": "Tfl.Api.Presentation.Entities.Fares.FareStation, Tfl.Api.Presentation.Entities", + "atcoCode": "940GZZLUCYF", + "commonName": "Canary Wharf Underground Station", + "fareCategory": "All" + }, + "toStation": { + "$type": "Tfl.Api.Presentation.Entities.Fares.FareStation, Tfl.Api.Presentation.Entities", + "atcoCode": "910GPURLEYO", + "commonName": "Purley Oaks Rail Station", + "fareCategory": "All" + } + }, + "rows": [ + { + "$type": "Tfl.Api.Presentation.Entities.Fares.FareDetails, Tfl.Api.Presentation.Entities", + "startDate": "2020-04-19T23:00:00Z", + "endDate": "2021-04-19T23:00:00Z", + "passengerType": "Adult", + "contactlessPAYGOnlyFare": false, + "from": "Canary Wharf Underground Station", + "to": "Purley Oaks Rail Station", + "fromStation": "940GZZLUCYF", + "toStation": "910GPURLEYO", + "displayName": "Alternative Route", + "displayOrder": 0, + "routeDescription": "Avoiding Zone 1 via Canada Water", + "validatorInformation": "Canada Water", + "specialFare": false, + "throughFare": false, + "isTour": false, + "ticketsAvailable": [ + { + "$type": "Tfl.Api.Presentation.Entities.Fares.Ticket, Tfl.Api.Presentation.Entities", + "passengerType": "Adult", + "ticketType": { + "$type": "Tfl.Api.Presentation.Entities.Fares.TicketType, Tfl.Api.Presentation.Entities", + "type": "Pay as you go", + "description": "Pay as you go" + }, + "ticketTime": { + "$type": "Tfl.Api.Presentation.Entities.Fares.TicketTime, Tfl.Api.Presentation.Entities", + "type": "Off Peak", + "description": "At all other times including public holidays." + }, + "cost": "3.10", + "description": "Pay as you go", + "mode": "national-rail", + "displayOrder": 1, + "messages": [] + }, + { + "$type": "Tfl.Api.Presentation.Entities.Fares.Ticket, Tfl.Api.Presentation.Entities", + "passengerType": "Adult", + "ticketType": { + "$type": "Tfl.Api.Presentation.Entities.Fares.TicketType, Tfl.Api.Presentation.Entities", + "type": "Pay as you go", + "description": "Pay as you go" + }, + "ticketTime": { + "$type": "Tfl.Api.Presentation.Entities.Fares.TicketTime, Tfl.Api.Presentation.Entities", + "type": "Peak", + "description": "Monday to Friday from 0630 to 0930 and from 1600 to 1900." + }, + "cost": "4.50", + "description": "Pay as you go", + "mode": "national-rail", + "displayOrder": 2, + "messages": [] + } + ], + "messages": [] + } + ], + "messages": [] + } +] diff --git a/types.go b/types.go index f5ece43..a23a5bc 100644 --- a/types.go +++ b/types.go @@ -132,3 +132,78 @@ type FareTapDetails struct { ModeType string `json:"modeType"` TapTimestamp string `json:"tapTimestamp"` } + +// FaresSection represents Tfl.Api.Presentation.Entities.Fares.FaresSection +type FaresSection struct { + Header string `json:"header"` + Index int `json:"index"` + Journey FaresJourney `json:"journey"` + Rows []FareDetails `json:"rows"` + Messages []Message `json:"messages"` +} + +// FaresJourney represents Tfl.Api.Presentation.Entities.Fares.Journey +type FaresJourney struct { + FromStation FareStation `json:"fromStation"` + ToStation FareStation `json:"toStation"` +} + +// FareStation represents Tfl.Api.Presentation.Entities.Fares.Journey +type FareStation struct { + AtcoCode string `json:"atcoCode"` + CommonName string `json:"commonName"` + FareCategory string `json:"fareCategory"` +} + +// Message represents Tfl.Api.Presentation.Entities.Message +type Message struct { + BulletOrder int `json:"bulletOrder"` + Text string `json:"messageText"` +} + +// FareDetails represents Tfl.Api.Presentation.Fares.FareDetails +type FareDetails struct { + StartDate string `json:"startDate"` + EndDate string `json:"endDate"` + PassengerType string `json:"passengerType"` + ContactlessPaygOnlyFare bool `json:"contactlessPAYGOnlyFare"` + From string `json:"from"` + To string `json:"to"` + FromStation string `json:"fromStation"` + ToStation string `json:"toStation"` + DisplayName string `json:"displayName"` + DisplayOrder int `json:"displayOrder"` + RouteDescription string `json:"routeDescription"` + SpecialFare bool `json:"specialFare"` + ThroughFare bool `json:"throughFare"` + IsTour bool `json:"isTour"` + TicketsAvailable []Ticket `json:"ticketsAvailable"` +} + +// Ticket represents Tfl.Api.Presentation.Entities.Fares.Ticket +type Ticket struct { + PassengerType string `json:"passengerType"` + TicketType TicketType `json:"ticketType"` + TicketTime TicketTime `json:"ticketTime"` + Cost string `json:"cost"` + Description string `json:"description"` + Mode string `json:"mode"` + DisplayOrder int `json:"displayOrder"` +} + +// TicketType represents Tfl.Api.Presentation.Entities.Fares.TicketType +type TicketType struct { + Type string `json:"type"` + Description string `json:"description"` +} + +// TicketTime represents Tfl.Api.Presentation.Entities.Fares.TicketTime +type TicketTime struct { + Type string `json:"type"` + Description string `json:"description"` +} + +// SingleFareFinderInput is used as the input object for SingleFareFinder +type SingleFareFinderInput struct { + From, To string +}