Giter Site home page Giter Site logo

mobilitydata / gbfs-validator Goto Github PK

View Code? Open in Web Editor NEW
17.0 17.0 12.0 4.31 MB

The canonical GBFS validator. Maintained by the GBFS community, facilitated by MobilityData.

Home Page: https://gbfs-validator.mobilitydata.org/

License: Apache License 2.0

JavaScript 75.88% HTML 0.70% Vue 23.42%
bike bikeshare bikesharing gbfs

gbfs-validator's People

Contributors

alessandro100 avatar antoineaugusti avatar davidgamez avatar dependabot[bot] avatar dersvenhesse avatar evansiroky avatar fchabouis avatar fnogatz avatar fredericsimard avatar isabelle-dr avatar jcpitre avatar josee-sabourin avatar mobilitydataio avatar nbdh avatar pierrickp avatar renovate-bot avatar richfab avatar tdelmas avatar testower avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

gbfs-validator's Issues

Support Oauth 2.0 client credentials grant flow

It is common to use Bearer token authentication with the Oauth 2.0 client credentials grant flow to grant the token itself. The flow uses basic auth against a token endpoint to retreive the bearer token. We have several feed providers who use this method. I think it is standard enough to warrant support in the core validator.

I'd be happy to contribute to getting the change in, if it is agreed that it should be supported.

Response code 500 on Link.city feeds

Observed

Currently, the validator does not work on some Link.city feeds (I tested 5 different Link systems from systems.csv and they all returned the same error message).

ie: https://gbfs-validator.mobilitydata.org/validator?url=https%3A%2F%2Fmds.linkyour.city%2Fgbfs%2Fus_tx_dallas%2Fgbfs.json
image
Feed: https://mds.linkyour.city/gbfs/us_tx_dallas/gbfs.json

Expected

The validation report should be displayed.

Investigation

In debug mode, we see that the response for the URL https://mds.linkyour.city/gbfs/us_tx_dallas/gbfs.json is code 500. I would need help to continue the investigation please. Thank you!

https://github.com/MobilityData/gbfs-validator/blob/master/gbfs-validator/gbfs.js#L282

image

Upgrade node version to a newer release

The minimum and recommended node versions, v12.x.x and v14.x.x, had reached their end-of-life date( version 14 will reach EOL at the end of this month), references Node Release Schedule. This can mean no new patches will be released and code dependent on it can be exposed to security and performance risks. In addition, the code is using currently the Optional chain operator (field?.innerFieldMightBeNullOrUndefined) that is only available in node versions 13+.

To solve this issue the node version should be upgraded to a newer release, preferably an LTS release(18+).

Get a acces to "GBFS validator API" ?

Hello @PierrickP,
I'm Alban GOUGOUA, Data Analyst in the French Transport Regulatory Body (Autorité de régulation des Transports in french).

Within the framework of our control mission, we use a plateform of validation tools which contains validators of data mobility like MobilityData tools gtfs-validator for GTFS, DATA4PTTools for NeTEx, etc.
We are interested to integrate your validator for GBFS format in our plateform but it is not possible to use your tool via CLI. However, it is possible to request your validator via this URL : "https://gbfs-validator.netlify.app/.netlify/functions/validator". Just like for French National Acces Point, can we access to your API ?

Thanks in advance for your attention.

Best regards,
Alban GOUGOUA
Data Analyst in French Transport Regulatory Body (ART - Autorité de Régulaton des Transports)

Response code 500 on the LINK Knoxville feed

What is the issue and why is it an issue?

When using the validator on a random feed (LINK Knoxville from systems.csv#L686), I realized that it returns "Sorry, this version is not yet implemented or not detectable !". However, the filegbfs.json is conform to v2.2 when testing it against the JSON Schema.

It could be a problem for other feeds too.

gbfs.json Output
image image

Please describe some potential solutions you have considered (even if they aren’t related to GBFS).

I don't have a solution but I did some debugging, if it helps.

The checkAutodiscovery() method in gbfs.js catches this error:

HTTPError: Response code 500 (Internal Server Error)
    at Request.<anonymous> (/Users/fabien/GitHub/MobilityData/gbfs-validator/gbfs-validator/node_modules/got/dist/source/as-promise/index.js:118:42)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5) {name: 'HTTPError', code: 'ERR_NON_2XX_3XX_RESPONSE', timings: {…}, stack: 'HTTPError: Response code 500 (Internal Server…ions (node:internal/process/task_queues:95:5)', message: 'Response code 500 (Internal Server Error)', …}

But the feed loads correctly in the browser 🤔

Add `API Key` authentification method

Some private feeds require an API Key to be fetched.
It would be useful to add the API Key authentification method to validate such feeds.

Before After
image image

Validate for both lowercase and uppercase enums?

The spec states that Enum values SHOULD be lowercase.. As a reminder the spec uses RFC 2119 for requirement level language.

The validator is flagging errors in datasets that use uppercase enum values. Example here.

Because the lowercase is recommended and not required (and effectively a best practice), should the validator consider feeds using uppercase as valid? This opens the question on whether the validator should validate for best practices, or just the specification.

Timezone not properly validated

Timezone as defined in https://github.com/NABSA/gbfs/blob/v2.3/gbfs.md#field-types
states:

Timezone - TZ timezone from the https://www.iana.org/time-zones. Timezone names never contain the space character but MAY contain an underscore. Refer to https://en.wikipedia.org/wiki/List_of_tz_zones for a list of valid values. Example: Asia/Tokyo, America/Los_Angeles or Africa/Cairo.

The schema in system_information.json seems to not make any requirements of the field:

"timezone": {
    "description": "The time zone where the system is located.",
    "type": "string"
},

This does not seem to comply to the gbfs standard

Output gbfs-validator version in the HTTP API response

This is a suggestion for an enhancement.

It would be helpful to be able to know the version of the gbfs-validator used when validating a GBFS feed. As this repository evolves, it seems like a good idea to store the specific version used to validate a feed.

Maybe add a field in the summary or add a new meta field?

Sample response
{
   "summary":{
      "version":{
         "detected":"1.0",
         "validated":"1.0"
      },
      "hasErrors":false,
      "errorsCount":0
   },
   "files":[
      {
         "schema":{
            "$schema":"http://json-schema.org/draft-07/schema",
            "$id":"https://github.com/NABSA/gbfs/blob/v1.0/gbfs.md#gbfsjson",
            "description":"Auto-discovery file that links to all of the other files published by the system.",
            "type":"object",
            "properties":{
               "last_updated":{
                  "description":"Last time the data in the feed was updated in POSIX time.",
                  "type":"integer",
                  "minimum":0,
                  "maximum":1924988399
               },
               "ttl":{
                  "description":"Number of seconds before the data in the feed will be updated again (0 if the data should always be refreshed).",
                  "type":"integer",
                  "minimum":0
               },
               "data":{
                  "description":"Response data in the form of name:value pairs.",
                  "type":"object",
                  "patternProperties":{
                     "^[a-zA-Z]{2}$":{
                        "type":"object",
                        "properties":{
                           "feeds":{
                              "description":"An array of all of the feeds that are published by the auto-discovery file. Each element in the array is an object with the keys below.",
                              "type":"array",
                              "items":{
                                 "type":"object",
                                 "properties":{
                                    "name":{
                                       "type":"string"
                                    },
                                    "url":{
                                       "type":"string"
                                    }
                                 },
                                 "required":[
                                    "name",
                                    "url"
                                 ]
                              }
                           }
                        },
                        "required":[
                           "feeds"
                        ]
                     },
                     "required":true
                  },
                  "additionalProperties":false
               }
            },
            "required":[
               "last_updated",
               "ttl",
               "data"
            ]
         },
         "errors":false,
         "url":"https://saint-etienne-fr-smoove.klervi.net/gbfs/gbfs.json",
         "version":"1.0",
         "recommanded":true,
         "required":false,
         "exists":true,
         "file":"gbfs.json",
         "hasErrors":false,
         "errorsCount":0
      },
      {
         "languages":[
            
         ],
         "required":false,
         "exists":false,
         "file":"gbfs_versions.json",
         "hasErrors":false,
         "errorsCount":0
      },
      {
         "languages":[
            {
               "body":{
                  "last_updated":1658923809,
                  "ttl":0,
                  "data":{
                     "system_id":"Velivert_FR_Saint-Etienne",
                     "language":"en",
                     "name":"Vélivert Saint-Etienne",
                     "timezone":"Europe/Paris"
                  }
               },
               "exists":true,
               "lang":"en",
               "url":"https://saint-etienne-gbfs.klervi.net/gbfs/en/system_information.json",
               "schema":{
                  "$schema":"http://json-schema.org/draft-07/schema",
                  "$id":"https://github.com/NABSA/gbfs/blob/v1.0/gbfs.md#system_informationjson",
                  "description":"Details including system operator, system location, year implemented, URL, contact info, time zone.",
                  "type":"object",
                  "properties":{
                     "last_updated":{
                        "description":"Last time the data in the feed was updated in POSIX time.",
                        "type":"integer",
                        "minimum":0,
                        "maximum":1924988399
                     },
                     "ttl":{
                        "description":"Number of seconds before the data in the feed will be updated again (0 if the data should always be refreshed).",
                        "type":"integer",
                        "minimum":0
                     },
                     "data":{
                        "description":"Response data in the form of name:value pairs.",
                        "type":"object",
                        "properties":{
                           "system_id":{
                              "description":"Identifier for this vehicle share system. This should be globally unique (even between different systems).",
                              "type":"string"
                           },
                           "language":{
                              "description":"The language that will be used throughout the rest of the files. It must match the value in the gbfs.json file.",
                              "type":"string",
                              "pattern":"^[a-z]{2}$"
                           },
                           "name":{
                              "description":"Name of the system to be displayed to customers.",
                              "type":"string"
                           },
                           "short_name":{
                              "description":"Optional abbreviation for a system.",
                              "type":"string"
                           },
                           "operator":{
                              "description":"Name of the operator",
                              "type":"string"
                           },
                           "url":{
                              "description":"The URL of the vehicle share system.",
                              "type":"string"
                           },
                           "purchase_url":{
                              "description":"URL where a customer can purchase a membership.",
                              "type":"string"
                           },
                           "start_date":{
                              "description":"Date that the system began operations.",
                              "type":"string",
                              "format":"date"
                           },
                           "phone_number":{
                              "description":"A single voice telephone number for the specified system that presents the telephone number as typical for the system's service area.",
                              "type":"string"
                           },
                           "email":{
                              "description":"Email address actively monitored by the operator's customer service department.",
                              "type":"string"
                           },
                           "timezone":{
                              "description":"The time zone where the system is located.",
                              "type":"string"
                           },
                           "license_url":{
                              "description":"A fully qualified URL of a page that defines the license terms for the GBFS data for this system.",
                              "type":"string"
                           }
                        },
                        "required":[
                           "system_id",
                           "language",
                           "name",
                           "timezone"
                        ]
                     }
                  },
                  "required":[
                     "last_updated",
                     "ttl",
                     "data"
                  ]
               },
               "errors":false
            }
         ],
         "required":true,
         "exists":true,
         "file":"system_information.json",
         "hasErrors":false,
         "errorsCount":0
      },
      {
         "languages":[
            {
               "body":{
                  "last_updated":1658923809,
                  "ttl":0,
                  "data":{
                     "stations":[
                        {
                           "station_id":"101",
                           "name":"Châteaucreux",
                           "lat":45.442972,
                           "lon":4.398855,
                           "capacity":32
                        },
                        {
                           "station_id":"102",
                           "name":"Chaléassiere",
                           "lat":45.453601,
                           "lon":4.383062,
                           "capacity":16
                        },
                        {
                           "station_id":"103",
                           "name":"Carnot",
                           "lat":45.447093,
                           "lon":4.385487,
                           "capacity":24
                        },
                        {
                           "station_id":"104",
                           "name":"Jacquard",
                           "lat":45.441888,
                           "lon":4.382492,
                           "capacity":12
                        },
                        {
                           "station_id":"105",
                           "name":"Jaures",
                           "lat":45.440725,
                           "lon":4.387295,
                           "capacity":32
                        },
                        {
                           "station_id":"106",
                           "name":"Dorian",
                           "lat":45.43836,
                           "lon":4.388435,
                           "capacity":32
                        },
                        {
                           "station_id":"107",
                           "name":"Clapier",
                           "lat":45.436903,
                           "lon":4.378789,
                           "capacity":16
                        },
                        {
                           "station_id":"108",
                           "name":"Peuple",
                           "lat":45.436265,
                           "lon":4.387539,
                           "capacity":32
                        },
                        {
                           "station_id":"109",
                           "name":"A. Thomas",
                           "lat":45.4328,
                           "lon":4.388035,
                           "capacity":16
                        },
                        {
                           "station_id":"110",
                           "name":"A. France",
                           "lat":45.43065,
                           "lon":4.389752,
                           "capacity":16
                        },
                        {
                           "station_id":"111",
                           "name":"Tardy",
                           "lat":45.427396,
                           "lon":4.386718,
                           "capacity":16
                        },
                        {
                           "station_id":"112",
                           "name":"Tréfilerie",
                           "lat":45.427296,
                           "lon":4.390669,
                           "capacity":24
                        },
                        {
                           "station_id":"113",
                           "name":"Centre 2",
                           "lat":45.42342,
                           "lon":4.392292,
                           "capacity":24
                        },
                        {
                           "station_id":"114",
                           "name":"Bellevue",
                           "lat":45.415579,
                           "lon":4.393322,
                           "capacity":24
                        },
                        {
                           "station_id":"115",
                           "name":"Congrès",
                           "lat":45.426972,
                           "lon":4.404048,
                           "capacity":32
                        },
                        {
                           "station_id":"116",
                           "name":"Villeboeuf",
                           "lat":45.431808,
                           "lon":4.395127,
                           "capacity":16
                        },
                        {
                           "station_id":"117",
                           "name":"Chavanelle",
                           "lat":45.435109,
                           "lon":4.391962,
                           "capacity":24
                        },
                        {
                           "station_id":"118",
                           "name":"J. Moulin",
                           "lat":45.437404,
                           "lon":4.392469,
                           "capacity":16
                        },
                        {
                           "station_id":"119",
                           "name":"Fourneyron",
                           "lat":45.4395,
                           "lon":4.395669,
                           "capacity":24
                        },
                        {
                           "station_id":"120",
                           "name":"St Francois",
                           "lat":45.439538,
                           "lon":4.403407,
                           "capacity":16
                        },
                        {
                           "station_id":"121",
                           "name":"Bergson-Odde",
                           "lat":45.45915,
                           "lon":4.382838,
                           "capacity":16
                        },
                        {
                           "station_id":"122",
                           "name":"Terrasse",
                           "lat":45.46502,
                           "lon":4.37874,
                           "capacity":16
                        },
                        {
                           "station_id":"123",
                           "name":"Marx",
                           "lat":45.422732,
                           "lon":4.409376,
                           "capacity":24
                        },
                        {
                           "station_id":"124",
                           "name":"Janin",
                           "lat":45.448458,
                           "lon":4.39492,
                           "capacity":16
                        },
                        {
                           "station_id":"125",
                           "name":"Soleil",
                           "lat":45.450015,
                           "lon":4.402351,
                           "capacity":16
                        },
                        {
                           "station_id":"126",
                           "name":"Hôp. Nord",
                           "lat":45.479487,
                           "lon":4.362541,
                           "capacity":32
                        },
                        {
                           "station_id":"127",
                           "name":"J. Marc",
                           "lat":45.4732778,
                           "lon":4.3665277,
                           "capacity":24
                        },
                        {
                           "station_id":"128",
                           "name":"Technopole",
                           "lat":45.457,
                           "lon":4.39241,
                           "capacity":16
                        },
                        {
                           "station_id":"129",
                           "name":"Roannelle",
                           "lat":45.4357171,
                           "lon":4.3829931,
                           "capacity":16
                        },
                        {
                           "station_id":"130",
                           "name":"Bicentenaire",
                           "lat":45.420286,
                           "lon":4.392776,
                           "capacity":16
                        },
                        {
                           "station_id":"131",
                           "name":"Technopole-Christian Cabal",
                           "lat":45.459291,
                           "lon":4.395342,
                           "capacity":16
                        },
                        {
                           "station_id":"132",
                           "name":"Manufacture - Le Fil",
                           "lat":45.45168,
                           "lon":4.388004,
                           "capacity":16
                        }
                     ]
                  }
               },
               "exists":true,
               "lang":"en",
               "url":"https://saint-etienne-gbfs.klervi.net/gbfs/en/station_information.json",
               "schema":{
                  "$schema":"http://json-schema.org/draft-07/schema",
                  "$id":"https://github.com/NABSA/gbfs/blob/v1.0/gbfs.md#station_informationjson",
                  "description":"Details including system operator, system location, year implemented, URL, contact info, time zone.",
                  "type":"object",
                  "properties":{
                     "last_updated":{
                        "description":"Last time the data in the feed was updated in POSIX time.",
                        "type":"integer",
                        "minimum":0,
                        "maximum":1924988399
                     },
                     "ttl":{
                        "description":"Number of seconds before the data in the feed will be updated again (0 if the data should always be refreshed).",
                        "type":"integer",
                        "minimum":0
                     },
                     "data":{
                        "description":"Array that contains one object per station as defined below.",
                        "type":"object",
                        "properties":{
                           "stations":{
                              "type":"array",
                              "items":{
                                 "type":"object",
                                 "properties":{
                                    "station_id":{
                                       "description":"Identifier of a station.",
                                       "type":"string"
                                    },
                                    "name":{
                                       "description":"Public name of the station.",
                                       "type":"string"
                                    },
                                    "short_name":{
                                       "description":"Short name or other type of identifier.",
                                       "type":"string"
                                    },
                                    "lat":{
                                       "description":"The latitude of the station.",
                                       "type":"number",
                                       "minimum":-90,
                                       "maximum":90
                                    },
                                    "lon":{
                                       "description":"The longitude fo the station.",
                                       "type":"number",
                                       "minimum":-180,
                                       "maximum":180
                                    },
                                    "address":{
                                       "description":"Address where station is located.",
                                       "type":"string"
                                    },
                                    "cross_street":{
                                       "description":"Cross street or landmark…the station is located.",
                                       "type":"string"
                                    },
                                    "region_id":{
                                       "description":"Identifier of the region…the station is located.",
                                       "type":"string"
                                    },
                                    "post_code":{
                                       "description":"Postal code where station is located.",
                                       "type":"string"
                                    },
                                    "rental_methods":{
                                       "description":"Payment methods accepted at this station.",
                                       "type":"array",
                                       "items":{
                                          "type":"string",
                                          "enum":[
                                             "KEY",
                                             "CREDITCARD",
                                             "PAYPASS",
                                             "APPLEPAY",
                                             "ANDROIDPAY",
                                             "TRANSITCARD",
                                             "ACCOUNTNUMBER",
                                             "PHONE"
                                          ]
                                       }
                                    },
                                    "capacity":{
                                       "description":"Number of total docking …ilable and unavailable.",
                                       "type":"integer",
                                       "minimum":0
                                    }
                                 },
                                 "required":[
                                    "station_id",
                                    "name",
                                    "lat",
                                    "lon"
                                 ]
                              }
                           }
                        },
                        "required":[
                           "stations"
                        ]
                     }
                  },
                  "required":[
                     "last_updated",
                     "ttl",
                     "data"
                  ]
               },
               "errors":false
            }
         ],
         "required":false,
         "exists":true,
         "file":"station_information.json",
         "hasErrors":false,
         "errorsCount":0
      },
      {
         "languages":[
            {
               "body":{
                  "last_updated":1658923809,
                  "ttl":0,
                  "data":{
                     "stations":[
                        {
                           "station_id":"101",
                           "num_bikes_available":13,
                           "num_bikes_disabled":0,
                           "num_docks_available":19,
                           "is_installed":1,
                           "is_renting":1,
                           "is_returning":1,
                           "last_reported":1658923637
                        },
                        {
                           "station_id":"102",
                           "num_bikes_available":4,
                           "num_bikes_disabled":0,
                           "num_docks_available":12,
                           "is_installed":1,
                           "is_renting":1,
                           "is_returning":1,
                           "last_reported":1658922931
                        },
                        {
                           "station_id":"103",
                           "num_bikes_available":6,
                           "num_bikes_disabled":0,
                           "num_docks_available":18,
                           "is_installed":1,
                           "is_renting":1,
                           "is_returning":1,
                           "last_reported":1658923242
                        },
                        {
                           "station_id":"104",
                           "num_bikes_available":0,
                           "num_bikes_disabled":0,
                           "num_docks_available":12,
                           "is_installed":1,
                           "is_renting":1,
                           "is_returning":1,
                           "last_reported":1658923350
                        },
                        {
                           "station_id":"105",
                           "num_bikes_available":3,
                           "num_bikes_disabled":0,
                           "num_docks_available":29,
                           "is_installed":1,
                           "is_renting":1,
                           "is_returning":1,
                           "last_reported":1658923020
                        },
                        {
                           "station_id":"106",
                           "num_bikes_available":7,
                           "num_bikes_disabled":0,
                           "num_docks_available":25,
                           "is_installed":1,
                           "is_renting":1,
                           "is_returning":1,
                           "last_reported":1658923443
                        },
                        {
                           "station_id":"107",
                           "num_bikes_available":2,
                           "num_bikes_disabled":0,
                           "num_docks_available":14,
                           "is_installed":1,
                           "is_renting":1,
                           "is_returning":1,
                           "last_reported":1658923460
                        },
                        {
                           "station_id":"108",
                           "num_bikes_available":8,
                           "num_bikes_disabled":0,
                           "num_docks_available":24,
                           "is_installed":1,
                           "is_renting":1,
                           "is_returning":1,
                           "last_reported":1658923049
                        },
                        {
                           "station_id":"109",
                           "num_bikes_available":2,
                           "num_bikes_disabled":0,
                           "num_docks_available":14,
                           "is_installed":1,
                           "is_renting":1,
                           "is_returning":1,
                           "last_reported":1658923788
                        },
                        {
                           "station_id":"110",
                           "num_bikes_available":2,
                           "num_bikes_disabled":0,
                           "num_docks_available":14,
                           "is_installed":1,
                           "is_renting":1,
                           "is_returning":1,
                           "last_reported":1658923277
                        },
                        {
                           "station_id":"111",
                           "num_bikes_available":1,
                           "num_bikes_disabled":0,
                           "num_docks_available":15,
                           "is_installed":1,
                           "is_renting":1,
                           "is_returning":1,
                           "last_reported":1658923714
                        },
                        {
                           "station_id":"112",
                           "num_bikes_available":2,
                           "num_bikes_disabled":0,
                           "num_docks_available":22,
                           "is_installed":1,
                           "is_renting":1,
                           "is_returning":1,
                           "last_reported":1658923459
                        },
                        {
                           "station_id":"113",
                           "num_bikes_available":4,
                           "num_bikes_disabled":0,
                           "num_docks_available":20,
                           "is_installed":1,
                           "is_renting":1,
                           "is_returning":1,
                           "last_reported":1658923687
                        },
                        {
                           "station_id":"114",
                           "num_bikes_available":3,
                           "num_bikes_disabled":0,
                           "num_docks_available":21,
                           "is_installed":1,
                           "is_renting":1,
                           "is_returning":1,
                           "last_reported":1658923605
                        },
                        {
                           "station_id":"115",
                           "num_bikes_available":12,
                           "num_bikes_disabled":0,
                           "num_docks_available":20,
                           "is_installed":1,
                           "is_renting":1,
                           "is_returning":1,
                           "last_reported":1658923584
                        },
                        {
                           "station_id":"116",
                           "num_bikes_available":0,
                           "num_bikes_disabled":0,
                           "num_docks_available":16,
                           "is_installed":1,
                           "is_renting":1,
                           "is_returning":1,
                           "last_reported":1658923140
                        },
                        {
                           "station_id":"117",
                           "num_bikes_available":6,
                           "num_bikes_disabled":0,
                           "num_docks_available":18,
                           "is_installed":1,
                           "is_renting":1,
                           "is_returning":1,
                           "last_reported":1658923549
                        },
                        {
                           "station_id":"118",
                           "num_bikes_available":6,
                           "num_bikes_disabled":0,
                           "num_docks_available":10,
                           "is_installed":1,
                           "is_renting":1,
                           "is_returning":1,
                           "last_reported":1658923444
                        },
                        {
                           "station_id":"119",
                           "num_bikes_available":2,
                           "num_bikes_disabled":0,
                           "num_docks_available":22,
                           "is_installed":1,
                           "is_renting":1,
                           "is_returning":1,
                           "last_reported":1658923694
                        },
                        {
                           "station_id":"120",
                           "num_bikes_available":6,
                           "num_bikes_disabled":0,
                           "num_docks_available":10,
                           "is_installed":1,
                           "is_renting":1,
                           "is_returning":1,
                           "last_reported":1658923702
                        },
                        {
                           "station_id":"121",
                           "num_bikes_available":3,
                           "num_bikes_disabled":0,
                           "num_docks_available":13,
                           "is_installed":1,
                           "is_renting":1,
                           "is_returning":1,
                           "last_reported":1658923510
                        },
                        {
                           "station_id":"122",
                           "num_bikes_available":2,
                           "num_bikes_disabled":0,
                           "num_docks_available":14,
                           "is_installed":1,
                           "is_renting":1,
                           "is_returning":1,
                           "last_reported":1658923163
                        },
                        {
                           "station_id":"123",
                           "num_bikes_available":0,
                           "num_bikes_disabled":0,
                           "num_docks_available":24,
                           "is_installed":1,
                           "is_renting":1,
                           "is_returning":1,
                           "last_reported":1658923376
                        },
                        {
                           "station_id":"124",
                           "num_bikes_available":3,
                           "num_bikes_disabled":0,
                           "num_docks_available":13,
                           "is_installed":1,
                           "is_renting":1,
                           "is_returning":1,
                           "last_reported":1658923789
                        },
                        {
                           "station_id":"125",
                           "num_bikes_available":7,
                           "num_bikes_disabled":0,
                           "num_docks_available":9,
                           "is_installed":1,
                           "is_renting":1,
                           "is_returning":1,
                           "last_reported":1658923028
                        },
                        {
                           "station_id":"126",
                           "num_bikes_available":5,
                           "num_bikes_disabled":0,
                           "num_docks_available":27,
                           "is_installed":1,
                           "is_renting":1,
                           "is_returning":1,
                           "last_reported":1658923341
                        },
                        {
                           "station_id":"127",
                           "num_bikes_available":6,
                           "num_bikes_disabled":0,
                           "num_docks_available":18,
                           "is_installed":1,
                           "is_renting":1,
                           "is_returning":1,
                           "last_reported":1658923245
                        },
                        {
                           "station_id":"128",
                           "num_bikes_available":2,
                           "num_bikes_disabled":0,
                           "num_docks_available":14,
                           "is_installed":1,
                           "is_renting":1,
                           "is_returning":1,
                           "last_reported":1658923709
                        },
                        {
                           "station_id":"129",
                           "num_bikes_available":0,
                           "num_bikes_disabled":0,
                           "num_docks_available":16,
                           "is_installed":1,
                           "is_renting":1,
                           "is_returning":1,
                           "last_reported":1658923235
                        },
                        {
                           "station_id":"130",
                           "num_bikes_available":0,
                           "num_bikes_disabled":0,
                           "num_docks_available":16,
                           "is_installed":1,
                           "is_renting":1,
                           "is_returning":1,
                           "last_reported":1658923578
                        },
                        {
                           "station_id":"131",
                           "num_bikes_available":9,
                           "num_bikes_disabled":0,
                           "num_docks_available":7,
                           "is_installed":1,
                           "is_renting":1,
                           "is_returning":1,
                           "last_reported":1658923479
                        },
                        {
                           "station_id":"132",
                           "num_bikes_available":3,
                           "num_bikes_disabled":0,
                           "num_docks_available":13,
                           "is_installed":1,
                           "is_renting":1,
                           "is_returning":1,
                           "last_reported":1658923091
                        }
                     ]
                  }
               },
               "exists":true,
               "lang":"en",
               "url":"https://saint-etienne-gbfs.klervi.net/gbfs/en/station_status.json",
               "schema":{
                  "$schema":"http://json-schema.org/draft-07/schema",
                  "$id":"https://github.com/NABSA/gbfs/blob/v1.0/gbfs.md#station_statusjson",
                  "description":"Describes the capacity and rental availability of the station",
                  "type":"object",
                  "properties":{
                     "last_updated":{
                        "description":"Last time the data in the feed was updated in POSIX time.",
                        "type":"integer",
                        "minimum":0,
                        "maximum":1924988399
                     },
                     "ttl":{
                        "description":"Number of seconds before the data in the feed will be updated again (0 if the data should always be refreshed).",
                        "type":"integer",
                        "minimum":0
                     },
                     "data":{
                        "description":"Array that contains one object per station as defined below.",
                        "type":"object",
                        "properties":{
                           "stations":{
                              "type":"array",
                              "items":{
                                 "type":"object",
                                 "properties":{
                                    "station_id":{
                                       "description":"Identifier of a station.",
                                       "type":"string"
                                    },
                                    "num_bikes_available":{
                                       "description":"Number of vehicles of any type physically available for rental at the station.",
                                       "type":"integer",
                                       "minimum":0
                                    },
                                    "num_bikes_disabled":{
                                       "description":"Number of disabled vehic…ny type at the station.",
                                       "type":"integer",
                                       "minimum":0
                                    },
                                    "num_docks_available":{
                                       "description":"Number of functional doc…sically at the station.",
                                       "type":"integer",
                                       "minimum":0
                                    },
                                    "num_docks_disabled":{
                                       "description":"Number of empty but disabled docks at the station.",
                                       "type":"integer",
                                       "minimum":0
                                    },
                                    "is_installed":{
                                       "description":"Is the station currently on the street?",
                                       "oneOf":[
                                          {
                                             "type":"boolean"
                                          },
                                          {
                                             "type":"number"
                                          }
                                       ]
                                    },
                                    "is_renting":{
                                       "description":"Is the station currently renting vehicles?",
                                       "oneOf":[
                                          {
                                             "type":"boolean"
                                          },
                                          {
                                             "type":"number"
                                          }
                                       ]
                                    },
                                    "is_returning":{
                                       "description":"Is the station accepting vehicle returns?",
                                       "oneOf":[
                                          {
                                             "type":"boolean"
                                          },
                                          {
                                             "type":"number"
                                          }
                                       ]
                                    },
                                    "last_reported":{
                                       "description":"The last time this station reported its status to the operator's backend in POSIX time.",
                                       "type":"number"
                                    }
                                 },
                                 "required":[
                                    "station_id",
                                    "num_bikes_available",
                                    "num_docks_available",
                                    "is_installed",
                                    "is_renting",
                                    "is_returning",
                                    "last_reported"
                                 ]
                              }
                           }
                        },
                        "required":[
                           "stations"
                        ]
                     }
                  },
                  "required":[
                     "last_updated",
                     "ttl",
                     "data"
                  ]
               },
               "errors":false
            }
         ],
         "required":false,
         "exists":true,
         "file":"station_status.json",
         "hasErrors":false,
         "errorsCount":0
      },
      {
         "languages":[
            
         ],
         "required":false,
         "exists":false,
         "file":"free_bike_status.json",
         "hasErrors":false,
         "errorsCount":0
      },
      {
         "languages":[
            
         ],
         "required":false,
         "exists":false,
         "file":"system_hours.json",
         "hasErrors":false,
         "errorsCount":0
      },
      {
         "languages":[
            
         ],
         "required":false,
         "exists":false,
         "file":"system_calendar.json",
         "hasErrors":false,
         "errorsCount":0
      },
      {
         "languages":[
            
         ],
         "required":false,
         "exists":false,
         "file":"system_regions.json",
         "hasErrors":false,
         "errorsCount":0
      },
      {
         "languages":[
            
         ],
         "required":false,
         "exists":false,
         "file":"system_pricing_plans.json",
         "hasErrors":false,
         "errorsCount":0
      },
      {
         "languages":[
            
         ],
         "required":false,
         "exists":false,
         "file":"system_alerts.json",
         "hasErrors":false,
         "errorsCount":0
      }
   ]
}

validating gbfs version incorrect

Validating https://nitro.openvelo.org/aachen/velocity/v1/gbfs.json leads to the same error in each feed:

Errors in https://nitro.openvelo.org/aachen/velocity/v1/*.json

[
  {
    "keyword": "pattern",
    "dataPath": ".version",
    "schemaPath": "#/properties/version/pattern",
    "params": {
      "pattern": "^d+\\.d+$"
    },
    "message": "should match pattern \"^d+\\.d+$\""
  }
]

but the version is reported correctly as 1.1

This error can be fixed by adjusting the regex which checks the version (in each file of https://github.com/fluctuo/gbfs-validator/tree/master/gbfs-validator/schema), current value is ^d+\\.d+$, but should be ^\\d+\\.\\d+$. Thanks for implementing the validator

vehicle_types.json wrongly required

I suspect that this change broke #41. For v2.2 feeds the vehicle_types.json is thought to be required again, even if the criteria stated in gbfs.md

REQUIRED of systems that include information about vehicle types in the free_bike_status file.

is not given.

Example feed: https://gbfs-validator.netlify.app/?url=https%3A%2F%2Fgbfs.nextbike.net%2Fmaps%2Fgbfs%2Fv2%2Fnextbike_le%2Fgbfs.json
which states

Missing file and required

for the vehicle_types.json.

Should I open a new issue?

Best regards

Originally posted by @nbdh in #63 (comment)

CLI or http for local gbfs files

Would it be possible to use the cli for validating gbfs files that are not hosted anywhere? For example:

node cli.js ~/Downloads/gbfs.json

The workaround I use now is using a local server python3 -m SimpleHTTPServer 8000

Also the example referenced in Issue #53 does not seem to work anymore (commit 35a2299)

node cli.js https://transport.data.gouv.fr/gbfs/strasbourg/gbfs.json
gbfs-validator/gbfs-validator/gbfs.js:63
      lang.body?.data?.vehicle_types.map(vt => {
                ^

SyntaxError: Unexpected token '.'
    at wrapSafe (internal/modules/cjs/loader.js:915:16)
    at Module._compile (internal/modules/cjs/loader.js:963:27)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1027:10)
    at Module.load (internal/modules/cjs/loader.js:863:32)
    at Function.Module._load (internal/modules/cjs/loader.js:708:14)
    at Module.require (internal/modules/cjs/loader.js:887:19)
    at require (internal/modules/cjs/helpers.js:74:18)
    at Object.<anonymous> (gbfs-validator/gbfs-validator/index.js:1:14)
    at Module._compile (internal/modules/cjs/loader.js:999:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1027:10)

The source code compile fine, but get alway "Proxy error: Could not proxy request"

Hello to everyone,
I've downloaded and compiled the source code, but when I try so put the url, for some reason I got this error:

Proxy error: Could not proxy request /validator from localhost:8080 to http://localhost:9000/.
See https://nodejs.org/api/errors.html#errors_common_system_errors for more information (ECONNREFUSED).

I tried everything I could, but nothing works. Can someone tell me how to fix this error? Thanks!

Fix error when `manifest.json` file is not found

Currently, when manifest_url is specified in system_information.json, but the file is not found at the URL, the validator fails.
Instead, the validator should inform that the manifest.json file is missing.

Before After
before after

Validate version 2.3

Hi all!

At the moment the latest version available here is 2.3-RC2, but 2.3 has been released on 2022-04-05.

Is it possible to upgrade the validator to 2.3? I could make a PR if it's not too long and if you describe what I need to take care.

CLI or HTTP API?

Hello there!

Thanks for providing an awesome tool. We @ https://transport.data.gouv.fr are very interested in using/contributing to this repository (and we already did! #39)

We'd like to know if it's possible to use this tool as a CLI tool or an HTTP API.

It seems like we can use it as a CLI by doing

cd gbfs-validator
npm install
node cli.js https://transport.data.gouv.fr/gbfs/strasbourg/gbfs.json

which gives a JSON report

There is also an HTTP API available at https://gbfs-validator.netlify.app/.netlify/functions/validator

curl -X POST -d '{"url": "https://transport.data.gouv.fr/gbfs/strasbourg/gbfs.json"}' https://gbfs-validator.netlify.app/.netlify/functions/validator

Is this safe to use? Should this be documented?

Create different error messages

What is the issue and why is it an issue?

Currently it seems the only error the validator throws when it is unable to process a feed is "Sorry, this version is not yet implemented or not detectable !", this can be confusing when issues are not related to versioning.

Please describe some potential solutions you have considered (even if they aren’t related to GBFS).

I suggest adding a variety of different error messages for various situations like:

  • when a feed has a 404 or 502 error
  • blocked user-agent (see issue #90)
  • etc.

Please feel free to use this thread to add more ideas for error messages.

Impossible de validate Salavador pbsc

Url: https://salvador.publicbikesystem.net/operation/customer/gbfs/v2/gbfs.json

Timeout on prod,
In local, the GBFS file is invalid (2 wrong filename) and no file are founded

Validate that timestamps are POSIX

Per GBFS spec, last_updated timestamps need to be POSIX timestamp format (i.e. no of seconds since 1 Jan 1970 UTC). A range-based check would make sure that the time is sensible (e.g. no of seconds rather than no of milliseconds).

Validator does not flag additional fields as invalid

Certain feeds with additional non-GBFS fields are being checked as valid.
Example: Citibike includes fields in station_information.json like electric_bike_surcharge_waiver and external_id, but the validation report says no errors.

I believe this might actually be an issue with the schemas and not the validator itself. I am opening the issue on both repositories to be sure.

My initial instinct for a solution would be to add an additionalProperties: false to the schemas, but would like to make sure before opening a PR.

Publish core validator on npm

To allow using the core validator in bespoke pipelines, I would love to see it published as a standalone package on npm.

Map may not be displayed when the feed has errors

What is the issue and why is it an issue?

When using the visualization tool on a random feed (Nextbike UsedomRad Germany from systems.csv#L184), I noticed that it fails to display the map:

https://gbfs-validator.netlify.app/?url=https%3A%2F%2Fgbfs.nextbike.net%2Fmaps%2Fgbfs%2Fv2%2Fnextbike_ur%2Fgbfs.json

Maybe the map fails to display because the feed contains errors (the validation report of this feed shows 447 errors).

The problem is that users may think that the visualization tool is broken.

Please describe some potential solutions you have considered (even if they aren’t related to GBFS).

A potential solution could be to display a message suggesting to check the validation report when the map cannot be displayed.

Before After
image Screenshot 2023-09-27 at 11 43 59

Add summary option to cli

Description

As suggested here, cli consumer needs a summary option to reduce the amount of information to process on the output report. This should be done after #101 and #106 are reviewed and merged.

Summary response schema

TBD

Write a custom rule to check conditional requirement of vehicle_types.json file presence

The GBFS specification mentions the following in the vehicle_types.json file:

REQUIRED of systems that include information about vehicle types in the free_bike_status file. If this file is not included, then all vehicles in the feed are assumed to be non-motorized bicycles. This file SHOULD be published by systems offering multiple vehicle types for rental, for example pedal bikes and bikes.

A custom rule should be written to include this rule in the validator.

The additional context in:

error in system_alerts example

The example of payload for the system_alerts data model does not validate against its schema, start and end should be literal numbers and not strings as provided.
Additionally in other examples of data models (sorry I did not take notes of which ones) failed validations against their schemas because the version attribute has not the enumeration value "3.0"

Issue originally opened on NABSA/gbfs

Introduce a GBFS Validator API product offering

People have expressed the desire to use the GBFS Validator through an HTTP API (#53 #95 at least). At the moment it's possible but it's hidden and it's not a proper feature offered by MobilityData.

As discussed during the recent workshop in Valencia, Spain it would be great to:

  • clarify that there is an API available
  • define terms of services/restrictions/support/pricing (if applicable)
  • write a documentation
  • make sure HTTP responses are stable over time to avoid breaking integrations

We @ transport.data.gouv.fr rely on this hidden API every day at the moment and are more than happy to help you review these things.

Validating v1.0 feed gives "unimplemented version" error

It seems like this is a bug that is caused by v1.0 feed not having a version field, since this field was introduced in v1.1. Even specifying v1.0 in the options gives the same error.

To reproduce

Try to validate the following feed: https://eu-feeds.joyridecity.bike/api/v1/zvipp/trondheim-2021/gbfs/gbfs.json

Update: I patched the validator locally so that feeds without a version would be validated as v1.0, and this seems to work:

@@ -144,7 +145,7 @@ class GBFS {
         this.autoDiscovery = body

         const errors = this.validateFile(
-          this.options.version || body.version,
+          this.options.version || body.version || '1.0',
           'gbfs',
           this.autoDiscovery
         )
@@ -152,7 +153,7 @@ class GBFS {
         return {
           errors,
           url: this.url,
-          version: body.version,
+          version: body.version || '1.0',
           recommanded: true,
           required: this.isGBFSFileRequire(
             this.options.version || body.version || '1.0'

This may or may not be the correct or optimal solution though.

On top of this, it seems like the schema for 1.0 incorrectly requires the "version" field, despite it not existing in 1.0:

https://github.com/MobilityData/gbfs-validator/blob/master/gbfs-validator/schema/v1.0/gbfs.json#L16
https://github.com/MobilityData/gbfs-validator/blob/master/gbfs-validator/schema/v1.0/gbfs.json#L49

Validation timeout for Paris' GBFS

When trying to validate the GBFS at https://velib-metropole-opendata.smoove.pro/opendata/Velib_Metropole/gbfs.json, I get a timeout error on the website.

{ "errorMessage": "2021-11-03T10:46:57.077Z fcd0740d-998f-4b3c-b45e-da4fb7e0553a Task timed out after 10.01 seconds" }

Validating this GBFS locally takes 19 seconds

time node cli.js https://velib-metropole-opendata.smoove.pro/opendata/Velib_Metropole/gbfs.json

it seems like the server is not slow to send responses, maybe a good opportunity to tackle performance improvements?

Validating a 1.1 station_status.json doesn't flag presence of incorrect 'num_bikes_available_types' attribute.

When validating a v1.1 station_status.json which uses 'num_bike_available_types' in place of 'vehicles_types_available' (as per the 1.1 schema), the validator doesn't flag this.

An example of this can be seen in Bcycle's feed https://gbfs.bcycle.com/bcycle_lametro/gbfs.json :

{ is_returning: 1, is_renting: 1, is_installed: 1, num_docks_available: 23, num_bikes_available: 8, last_reported: 1635497046, num_bikes_available_types: { electric: 4, smart: 0, classic: 4 }, station_id: "bcycle_lametro_3005" }

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.