Swagger file outdated?

The Swagger file at https://api.tfl.gov.uk/swagger/docs/v1 seems to refer to the (somewhat outdated) https://api.tfl.gov.uk/swagger/ui/index.html instead of the newer https://api-portal.tfl.gov.uk/apis.
If you paste it into a swagger editor, you can see many issues:

Note: the LineStatus path isn’t the only path with most of these issues, but it does show them clearly.

I ran into these issues after realising that none of the response attributes are marked as required, implying every field in the response could be undefined / missing, which causes issues when using the Swagger file to generate TypeScript files. (see issue on Github for more detail). Request fields are properly marked as required/optional, while response fields are not. I started looking into modifying the Swagger file myself before coming across these inconsistencies.

I therefore have 2 requests:

  1. Is there any updated Swagger file available which is consistent with https://api-portal.tfl.gov.uk/apis?
  2. Is it possible to have the latest available Swagger file updated to include required definitions for the response types?

Updating the swagger file and keeping up to date would be really helpful as it allows packages such as the JS to stay up to date and be easily maintainable.

Welcome @qwrwed

There are new docs here - APIs: List - Transport for London - API - which seem to have new versions of the OpenAPI format interface definitions. I’m not keen on them myself so I don’t use them.

I’ve seen those new docs (my post has linked to them several times to demonstrate that the Swagger file does not match them) but there does not seem to be any way to export them into a new Swagger file or other program-readable type definition file.

If I go to APIs: Details - Transport for London - API and then pick from the “API Definition” drop down list, as an example, it downloads a YAML/JSONWADL definition file.

Not a standard user interface design, I agree, but it does trigger a file/save…

Thanks, I didn’t know about that. That’s very useful to have (the schemas being renamed from things like Tfl.Api.Presentation.Entities.TrainLoading to things like Tfl-4 is less useful, but still manageable).
I guess that just leaves my second request, - probably a long shot, but worth asking just in case it can be implemented upstream:

  • Is it possible to have the OpenAPI files updated on TFL’s end to indicate that the response types (e.g. Tfl, Tfl-2, Tfl-3) have properties which are required?

This would entail adding an additional field, required, to each definition like so. In e.g. Line.json,

"Tfl-2": {
    "type": "object",
    "properties": {
        "modeName": {
            "type": "string"
        },
        "severityLevel": {
            "type": "integer",
            "format": "int32"
        },
        "description": {
            "type": "string"
        }
    }
},

would become

"Tfl-2": {
    "type": "object",
    "required": [
        "modeName",
        "severityLevel",
        "description"
    ],
    "properties": {
        "modeName": {
            "type": "string"
        },
        "severityLevel": {
            "type": "integer",
            "format": "int32"
        },
        "description": {
            "type": "string"
        }
    }
},

This would be done for each schema of each API definition. Can this be done on TFL’s end or would it have to be done on our end?

@qwrwed Sadly I’m only here as a user… but I can ping @jamesevans with your sensible suggestion as I believe the new help system is a work-in-progress.

I mapped all of the ‘entity aliases’ (Tfl, Tfl-1, Tfl-2, etc.) back to the full entity names (from the unified API), like Tfl.Api.Presentation.Entities.TrainLoading in case it’s of use to anyone:

{'AccidentStats': {'Tfl-Api-Presentation-Entities-AccidentStats-AccidentDetailArray': ['Tfl-Api-Presentation-Entities-AccidentStats-AccidentDetailArray'],
                   'Tfl-Api-Presentation-Entities-AccidentStats-AccidentDetailArray-1': ['Tfl-Api-Presentation-Entities-AccidentStats-AccidentDetailArray-1'],
                   'Tfl-Api-Presentation-Entities-AccidentStats-AccidentDetailArray-2': ['Tfl-Api-Presentation-Entities-AccidentStats-AccidentDetailArray-2'],
                   'Tfl-Api-Presentation-Entities-AccidentStats-AccidentDetailArray-3': ['Tfl-Api-Presentation-Entities-AccidentStats-AccidentDetailArray-3'],
                   'Tfl.Api.Presentation.Entities.AccidentStats.AccidentDetail': ['Tfl.Api.Presentation.Entities.AccidentStats.AccidentDetail'],
                   'Tfl.Api.Presentation.Entities.AccidentStats.Casualty': ['Tfl.Api.Presentation.Entities.AccidentStats.Casualty'],
                   'Tfl.Api.Presentation.Entities.AccidentStats.Vehicle': ['Tfl.Api.Presentation.Entities.AccidentStats.Vehicle']},
 'AirQuality': {'System.Object': ['System.Object']},
 'BikePoint': {'Tfl-Api-Presentation-Entities-PlaceArray': ['Tfl-Api-Presentation-Entities-PlaceArray'],
               'Tfl-Api-Presentation-Entities-PlaceArray-1': ['Tfl-Api-Presentation-Entities-PlaceArray-1'],
               'Tfl-Api-Presentation-Entities-PlaceArray-2': ['Tfl-Api-Presentation-Entities-PlaceArray-2'],
               'Tfl-Api-Presentation-Entities-PlaceArray-3': ['Tfl-Api-Presentation-Entities-PlaceArray-3'],
               'Tfl-Api-Presentation-Entities-PlaceArray-4': ['Tfl-Api-Presentation-Entities-PlaceArray-4'],
               'Tfl-Api-Presentation-Entities-PlaceArray-5': ['Tfl-Api-Presentation-Entities-PlaceArray-5'],
               'Tfl-Api-Presentation-Entities-PlaceArray-6': ['Tfl-Api-Presentation-Entities-PlaceArray-6'],
               'Tfl-Api-Presentation-Entities-PlaceArray-7': ['Tfl-Api-Presentation-Entities-PlaceArray-7'],
               'Tfl.Api.Presentation.Entities.AdditionalProperties': ['Tfl.Api.Presentation.Entities.AdditionalProperties'],
               'Tfl.Api.Presentation.Entities.Place': ['Tfl.Api.Presentation.Entities.Place']},
 'Disruptions-Lifts-v2': {'LiftDisruption': []},
 'Journey': {'Tfl': ['Tfl.Api.Presentation.Entities.Mode'],
             'Tfl-10': ['Tfl.Api.Presentation.Entities.Identifier'],
             'Tfl-11': ['Tfl.Api.Common.JourneyPlanner.JpElevation'],
             'Tfl-12': ['Tfl.Api.Presentation.Entities.JourneyPlanner.Path'],
             'Tfl-13': ['Tfl.Api.Presentation.Entities.JourneyPlanner.RouteOption'],
             'Tfl-14': ['Tfl.Api.Presentation.Entities.LineGroup'],
             'Tfl-15': ['Tfl.Api.Presentation.Entities.LineModeGroup'],
             'Tfl-16': ['Tfl.Api.Presentation.Entities.AdditionalProperties'],
             'Tfl-17': ['Tfl.Api.Presentation.Entities.Place'],
             'Tfl-18': ['Tfl.Api.Presentation.Entities.StopPoint'],
             'Tfl-19': ['Tfl.Api.Presentation.Entities.RouteSectionNaptanEntrySequence'],
             'Tfl-2': ['Tfl.Api.Presentation.Entities.PathAttribute'],
             'Tfl-20': ['Tfl.Api.Presentation.Entities.RouteSection'],
             'Tfl-21': ['Tfl.Api.Presentation.Entities.Disruption'],
             'Tfl-22': ['Tfl.Api.Presentation.Entities.JourneyPlanner.PlannedWork'],
             'Tfl-23': ['Tfl.Api.Presentation.Entities.JourneyPlanner.Leg'],
             'Tfl-24': ['Tfl.Api.Presentation.Entities.JourneyPlanner.FareTapDetails'],
             'Tfl-25': ['Tfl.Api.Presentation.Entities.JourneyPlanner.FareTap'],
             'Tfl-26': ['Tfl.Api.Presentation.Entities.JourneyPlanner.Fare'],
             'Tfl-27': ['Tfl.Api.Presentation.Entities.JourneyPlanner.FareCaveat'],
             'Tfl-28': ['Tfl.Api.Presentation.Entities.JourneyPlanner.JourneyFare'],
             'Tfl-29': ['Tfl.Api.Presentation.Entities.JourneyPlanner.Journey'],
             'Tfl-3': ['Tfl.Api.Presentation.Entities.InstructionStep'],
             'Tfl-30': ['Tfl.Api.Presentation.Entities.ValidityPeriod'],
             'Tfl-31': ['Tfl.Api.Presentation.Entities.LineStatus'],
             'Tfl-32': ['Tfl.Api.Presentation.Entities.MatchedRoute'],
             'Tfl-33': ['Tfl.Api.Presentation.Entities.LineServiceTypeInfo'],
             'Tfl-34': ['Tfl.Api.Presentation.Entities.Line'],
             'Tfl-35': ['Tfl.Api.Presentation.Entities.JourneyPlanner.JourneyPlannerCycleHireDockingStationData'],
             'Tfl-36': ['Tfl.Api.Presentation.Entities.JourneyPlanner.TimeAdjustment'],
             'Tfl-37': ['Tfl.Api.Presentation.Entities.JourneyPlanner.TimeAdjustments'],
             'Tfl-38': ['Tfl.Api.Presentation.Entities.JourneyPlanner.SearchCriteria'],
             'Tfl-39': ['Tfl.Api.Presentation.Entities.JourneyPlanner.JourneyVector'],
             'Tfl-4': ['Tfl.Api.Presentation.Entities.Instruction'],
             'Tfl-40': ['Tfl.Api.Presentation.Entities.JourneyPlanner.ItineraryResult'],
             'Tfl-5': ['Tfl.Api.Presentation.Entities.JourneyPlanner.Obstacle'],
             'Tfl-6': ['Tfl.Api.Presentation.Entities.Point'],
             'Tfl-7': ['Tfl.Api.Presentation.Entities.PassengerFlow'],
             'Tfl-8': ['Tfl.Api.Presentation.Entities.TrainLoading'],
             'Tfl-9': ['Tfl.Api.Presentation.Entities.Crowding']},
 'Line': {'Tfl': ['Tfl.Api.Presentation.Entities.Mode'],
          'Tfl-10': ['Tfl.Api.Presentation.Entities.Place'],
          'Tfl-11': ['Tfl.Api.Presentation.Entities.StopPoint'],
          'Tfl-12': ['Tfl.Api.Presentation.Entities.RouteSectionNaptanEntrySequence'],
          'Tfl-13': ['Tfl.Api.Presentation.Entities.RouteSection'],
          'Tfl-14': ['Tfl.Api.Presentation.Entities.Disruption'],
          'Tfl-15': ['Tfl.Api.Presentation.Entities.ValidityPeriod'],
          'Tfl-16': ['Tfl.Api.Presentation.Entities.LineStatus'],
          'Tfl-17': ['Tfl.Api.Presentation.Entities.MatchedRoute'],
          'Tfl-18': ['Tfl.Api.Presentation.Entities.LineServiceTypeInfo'],
          'Tfl-19': ['Tfl.Api.Presentation.Entities.Line'],
          'Tfl-2': ['Tfl.Api.Presentation.Entities.StatusSeverity'],
          'Tfl-20': ['Tfl.Api.Presentation.Entities.MatchedStop'],
          'Tfl-21': ['Tfl.Api.Presentation.Entities.StopPointSequence'],
          'Tfl-22': ['Tfl.Api.Presentation.Entities.OrderedRoute'],
          'Tfl-23': ['Tfl.Api.Presentation.Entities.RouteSequence'],
          'Tfl-24': ['Tfl.Api.Presentation.Entities.LineRouteSection'],
          'Tfl-25': ['Tfl.Api.Presentation.Entities.MatchedRouteSections'],
          'Tfl-26': ['Tfl.Api.Presentation.Entities.RouteSearchMatch'],
          'Tfl-27': ['Tfl.Api.Presentation.Entities.RouteSearchResponse'],
          'Tfl-28': ['Tfl.Api.Presentation.Entities.Interval'],
          'Tfl-29': ['Tfl.Api.Presentation.Entities.StationInterval'],
          'Tfl-3': ['Tfl.Api.Presentation.Entities.PassengerFlow'],
          'Tfl-30': ['Tfl.Api.Presentation.Entities.KnownJourney'],
          'Tfl-31': ['Tfl.Api.Presentation.Entities.TwentyFourHourClockTime'],
          'Tfl-32': ['Tfl.Api.Presentation.Entities.ServiceFrequency'],
          'Tfl-33': ['Tfl.Api.Presentation.Entities.Period'],
          'Tfl-34': ['Tfl.Api.Presentation.Entities.Schedule'],
          'Tfl-35': ['Tfl.Api.Presentation.Entities.TimetableRoute'],
          'Tfl-36': ['Tfl.Api.Presentation.Entities.Timetable'],
          'Tfl-37': ['Tfl.Api.Presentation.Entities.Timetables.DisambiguationOption'],
          'Tfl-38': ['Tfl.Api.Presentation.Entities.Timetables.Disambiguation'],
          'Tfl-39': ['Tfl.Api.Presentation.Entities.TimetableResponse'],
          'Tfl-4': ['Tfl.Api.Presentation.Entities.TrainLoading'],
          'Tfl-40': ['Tfl.Api.Presentation.Entities.PredictionTiming'],
          'Tfl-41': ['Tfl.Api.Presentation.Entities.Prediction'],
          'Tfl-5': ['Tfl.Api.Presentation.Entities.Crowding'],
          'Tfl-6': ['Tfl.Api.Presentation.Entities.Identifier'],
          'Tfl-7': ['Tfl.Api.Presentation.Entities.LineGroup'],
          'Tfl-8': ['Tfl.Api.Presentation.Entities.LineModeGroup'],
          'Tfl-9': ['Tfl.Api.Presentation.Entities.AdditionalProperties']},
 'Mode': {'Tfl-Api-Presentation-Entities-ActiveServiceTypeArray': ['Tfl-Api-Presentation-Entities-ActiveServiceTypeArray'],
          'Tfl-Api-Presentation-Entities-ActiveServiceTypeArray-1': ['Tfl-Api-Presentation-Entities-ActiveServiceTypeArray-1'],
          'Tfl-Api-Presentation-Entities-ActiveServiceTypeArray-2': ['Tfl-Api-Presentation-Entities-ActiveServiceTypeArray-2'],
          'Tfl-Api-Presentation-Entities-ActiveServiceTypeArray-3': ['Tfl-Api-Presentation-Entities-ActiveServiceTypeArray-3'],
          'Tfl-Api-Presentation-Entities-PredictionArray-4': ['Tfl-Api-Presentation-Entities-PredictionArray-4'],
          'Tfl-Api-Presentation-Entities-PredictionArray-5': ['Tfl-Api-Presentation-Entities-PredictionArray-5'],
          'Tfl-Api-Presentation-Entities-PredictionArray-6': ['Tfl-Api-Presentation-Entities-PredictionArray-6'],
          'Tfl-Api-Presentation-Entities-PredictionArray-7': ['Tfl-Api-Presentation-Entities-PredictionArray-7'],
          'Tfl.Api.Presentation.Entities.ActiveServiceType': ['Tfl.Api.Presentation.Entities.ActiveServiceType'],
          'Tfl.Api.Presentation.Entities.Prediction': ['Tfl.Api.Presentation.Entities.Prediction'],
          'Tfl.Api.Presentation.Entities.PredictionTiming': ['Tfl.Api.Presentation.Entities.PredictionTiming']},
 'Place': {'System': ['System.Object'],
           'Tfl': ['Tfl.Api.Presentation.Entities.PlaceCategory',
                   'Tfl.Api.Presentation.Entities.StopPointCategory'],
           'Tfl-10': ['Tfl.Api.Presentation.Entities.StopPoint'],
           'Tfl-2': ['Tfl.Api.Presentation.Entities.AdditionalProperties'],
           'Tfl-3': ['Tfl.Api.Presentation.Entities.Place'],
           'Tfl-4': ['Tfl.Api.Presentation.Entities.PassengerFlow'],
           'Tfl-5': ['Tfl.Api.Presentation.Entities.TrainLoading'],
           'Tfl-6': ['Tfl.Api.Presentation.Entities.Crowding'],
           'Tfl-7': ['Tfl.Api.Presentation.Entities.Identifier'],
           'Tfl-8': ['Tfl.Api.Presentation.Entities.LineGroup'],
           'Tfl-9': ['Tfl.Api.Presentation.Entities.LineModeGroup']},
 'Road': {'System': ['System.Data.Spatial.DbGeographyWellKnownValue'],
          'System-2': ['System.Data.Spatial.DbGeography'],
          'System-3': ['System.Object'],
          'Tfl': ['Tfl.Api.Presentation.Entities.RoadCorridor'],
          'Tfl-2': ['Tfl.Api.Presentation.Entities.StreetSegment'],
          'Tfl-3': ['Tfl.Api.Presentation.Entities.Street'],
          'Tfl-4': ['Tfl.Api.Presentation.Entities.RoadProject'],
          'Tfl-5': ['Tfl.Api.Presentation.Entities.RoadDisruptionLine'],
          'Tfl-6': ['Tfl.Api.Presentation.Entities.RoadDisruptionImpactArea'],
          'Tfl-7': ['Tfl.Api.Presentation.Entities.RoadDisruptionSchedule'],
          'Tfl-8': ['Tfl.Api.Presentation.Entities.RoadDisruption'],
          'Tfl-9': ['Tfl.Api.Presentation.Entities.StatusSeverity']},
 'Search': {'Tfl': ['Tfl.Api.Presentation.Entities.SearchMatch'],
            'Tfl-2': ['Tfl.Api.Presentation.Entities.SearchResponse']},
 'StopPoint': {'System': ['System.Object'],
               'Tfl': ['Tfl.Api.Presentation.Entities.PlaceCategory',
                       'Tfl.Api.Presentation.Entities.StopPointCategory'],
               'Tfl-10': ['Tfl.Api.Presentation.Entities.Place'],
               'Tfl-11': ['Tfl.Api.Presentation.Entities.StopPoint'],
               'Tfl-12': ['Tfl.Api.Presentation.Entities.LineServiceTypeInfo'],
               'Tfl-13': ['Tfl.Api.Presentation.Entities.LineSpecificServiceType'],
               'Tfl-14': ['Tfl.Api.Presentation.Entities.LineServiceType'],
               'Tfl-15': ['Tfl.Api.Presentation.Entities.PredictionTiming'],
               'Tfl-16': ['Tfl.Api.Presentation.Entities.Prediction'],
               'Tfl-17': ['Tfl.Api.Presentation.Entities.ArrivalDeparture'],
               'Tfl-18': ['Tfl.Api.Presentation.Entities.StopPointRouteSection'],
               'Tfl-19': ['Tfl.Api.Presentation.Entities.DisruptedPoint'],
               'Tfl-2': ['Tfl.Api.Presentation.Entities.Mode'],
               'Tfl-20': ['Tfl.Api.Presentation.Entities.StopPointsResponse'],
               'Tfl-21': ['Tfl.Api.Presentation.Entities.SearchMatch'],
               'Tfl-22': ['Tfl.Api.Presentation.Entities.SearchResponse'],
               'Tfl-3': ['Tfl.Api.Presentation.Entities.PassengerFlow'],
               'Tfl-4': ['Tfl.Api.Presentation.Entities.TrainLoading'],
               'Tfl-5': ['Tfl.Api.Presentation.Entities.Crowding'],
               'Tfl-6': ['Tfl.Api.Presentation.Entities.Identifier'],
               'Tfl-7': ['Tfl.Api.Presentation.Entities.LineGroup'],
               'Tfl-8': ['Tfl.Api.Presentation.Entities.LineModeGroup'],
               'Tfl-9': ['Tfl.Api.Presentation.Entities.AdditionalProperties']},
 'Vehicle': {'Tfl': ['Tfl.Api.Presentation.Entities.PredictionTiming'],
             'Tfl-2': ['Tfl.Api.Presentation.Entities.Prediction'],
             'Tfl-3': ['Tfl.Api.Presentation.Entities.VehicleMatch']},
 'crowding': {},
 'occupancy': {'Tfl': ['Tfl.Api.Presentation.Entities.Bay'],
               'Tfl-2': ['Tfl.Api.Presentation.Entities.CarParkOccupancy'],
               'Tfl-3': ['Tfl.Api.Presentation.Entities.ChargeConnectorOccupancy'],
               'Tfl-4': ['Tfl.Api.Presentation.Entities.BikePointOccupancy']}}
1 Like