From 50a5a0c1c8352a643b1a1c590903459012cf860a Mon Sep 17 00:00:00 2001 From: Traines Date: Mon, 20 Jan 2025 17:42:05 +0000 Subject: [PATCH 1/4] switch to db-vendo-client as backend --- api.js | 16 +++++------ package-lock.json | 70 ++++++++++++++++++++++++++++++++++++++++------- package.json | 2 +- 3 files changed, 68 insertions(+), 20 deletions(-) diff --git a/api.js b/api.js index 8753238..294c9ae 100644 --- a/api.js +++ b/api.js @@ -5,10 +5,8 @@ const require = createRequire(import.meta.url) import {dirname, join as pathJoin} from 'node:path' import {fileURLToPath} from 'node:url' -import { - createDbHafas as createHafas, - defaults as dbHafasDefaults, -} from 'db-hafas' +import {createClient} from 'db-vendo-client' +import {profile as dbnavProfile} from 'db-vendo-client/p/dbnav/index.js' import {createWriteStream} from 'node:fs' import {createHafasRestApi} from 'hafas-rest-api' import createHealthCheck from 'hafas-client-health-check' @@ -31,7 +29,7 @@ const docsRoot = pathJoin(__dirname, 'docs') const berlinHbf = '8011160' const customDbProfile = { - ...dbHafasDefaults.profile, + ...dbnavProfile, } // todo: DRY env var check with localaddress-agent/random-from-env.js @@ -60,10 +58,10 @@ if (process.env.HAFAS_REQ_RES_LOG_FILE) { } } -// todo: use process.env.HAFAS_USER_AGENT if defined -let hafas = createHafas(pkg.name, { - profile: customDbProfile, -}) +let hafas = createClient( + customDbProfile, + process.env.USER_AGENT || process.env.HAFAS_USER_AGENT || pkg.name +) let healthCheck = createHealthCheck(hafas, berlinHbf) if (process.env.REDIS_URL) { diff --git a/package-lock.json b/package-lock.json index 2905f47..c9a73c8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,9 +11,9 @@ "dependencies": { "cached-hafas-client": "^5.0.1", "cli-native": "^1.0.0", - "db-hafas": "^6.0.0", "db-stations": "^5.0.0", "db-stations-autocomplete": "^4.0.0", + "db-vendo-client": "^6.3.3", "etag": "^1.8.1", "hafas-client-health-check": "^2.1.1", "hafas-rest-api": "^5.1.0", @@ -58,6 +58,7 @@ "resolved": "https://registry.npmjs.org/@derhuerst/br2nl/-/br2nl-1.0.0.tgz", "integrity": "sha512-aGzqSMKM9eqHd9orDSe7yOvekRM9EMt9Jbc9vAG+a3jbn50WOTThVQX20c75yk0WBmu+6A5hdHGRM49dlp0I9w==", "license": "ISC", + "peer": true, "engines": { "node": ">=6" } @@ -322,7 +323,8 @@ "version": "0.12.2", "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.2.tgz", "integrity": "sha512-XISRgDJ2Tc5q4TRqvgJtzsRkFYNJzZrhTdtMoGVBttwzzQJkPnS3WWTFc7kuDRoPtPakl+T+OfdEUjYJj7Jbow==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/@types/unist": { "version": "2.0.11", @@ -894,6 +896,7 @@ "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.6.tgz", "integrity": "sha512-3Ek9H3X6pj5TgenXYtNWdaBon1tgYCaebd+XPg0keyjEbEfkD4KkmAxkQ/i1vYvxdcT5nscLBfq9VJRmCBcFSw==", "license": "MIT", + "peer": true, "dependencies": { "inherits": "^2.0.4", "safe-buffer": "^5.2.1" @@ -1090,6 +1093,7 @@ "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", "license": "MIT", + "peer": true, "dependencies": { "cipher-base": "^1.0.1", "inherits": "^2.0.1", @@ -1209,16 +1213,15 @@ "node": "*" } }, - "node_modules/db-hafas": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/db-hafas/-/db-hafas-6.0.0.tgz", - "integrity": "sha512-jk1iGhC2WhR2YB7pArGoxAsdVNTCP3FK/4uOWC+lGE6U/vwiDjP0XlaMhw78pPvDUHb7qPKpj8nAhwlEYm0R6w==", - "license": "ISC", + "node_modules/db-hafas-stations": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/db-hafas-stations/-/db-hafas-stations-1.0.0.tgz", + "integrity": "sha512-F14CaUHz4EZnUTrUGm9EXxeqsbxWnbp8aJIulV/wJ9LnVruYXXmTrRHVsa9DoK5fT9WEInyYSjMLlEspq2wqRw==", "dependencies": { - "hafas-client": "^6.0.1" + "ndjson": "^2.0.0" }, "engines": { - "node": ">=18" + "node": ">=14" } }, "node_modules/db-stations": { @@ -1247,6 +1250,30 @@ "node": ">=18" } }, + "node_modules/db-vendo-client": { + "version": "6.3.3", + "resolved": "https://registry.npmjs.org/db-vendo-client/-/db-vendo-client-6.3.3.tgz", + "integrity": "sha512-q4ErpRIqthKj+uOZJkt1VwA12gFutC7cGszyKDOf5BH9EF6WLYq7BYlK8s0HmCpsUAzTQ6UehWLZFhMsCJk/dQ==", + "dependencies": { + "@derhuerst/round-robin-scheduler": "^1.0.4", + "content-type": "^1.0.4", + "cross-fetch": "^4.0.0", + "db-hafas-stations": "^1.0.0", + "gps-distance": "0.0.4", + "https-proxy-agent": "^7.0.0", + "lodash": "^4.17.5", + "luxon": "^3.1.1", + "qs": "^6.6.0", + "slugg": "^1.2.0", + "uuid": "^11.0.5" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/derhuerst" + } + }, "node_modules/debug": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", @@ -2409,7 +2436,8 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/google-polyline/-/google-polyline-1.0.3.tgz", "integrity": "sha512-36BnqVxmVcR8lTvzO6aeXdICNChAwQLlfMkR1P9IBpTWE8hA6bAbQHCVArwMHB5WIMq9owywtAkjioe3crNq4Q==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/gopd": { "version": "1.2.0", @@ -2445,6 +2473,7 @@ "resolved": "https://registry.npmjs.org/hafas-client/-/hafas-client-6.3.3.tgz", "integrity": "sha512-esyatU2Bc3YaEUcHSYr9vLaVIi3qyG4R90SEq3GV1binaF7wVBqYPILUcJb14QimQBxLJ5GsZMIVRsQaUu1CvQ==", "license": "ISC", + "peer": true, "dependencies": { "@derhuerst/br2nl": "^1.0.0", "@derhuerst/round-robin-scheduler": "^1.0.4", @@ -2626,6 +2655,7 @@ "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", "license": "MIT", + "peer": true, "dependencies": { "inherits": "^2.0.4", "readable-stream": "^3.6.0", @@ -3451,6 +3481,7 @@ "resolved": "https://registry.npmjs.org/is-network-error/-/is-network-error-1.1.0.tgz", "integrity": "sha512-tUdRRAnhT+OtCZR/LxZelH/C7QtjtFrTu5tXCA8pl55eTUElUHT+GPYV8MBMBvea/j+NxQqVt3LbWMRir7Gx9g==", "license": "MIT", + "peer": true, "engines": { "node": ">=16" }, @@ -3910,6 +3941,7 @@ "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", "license": "MIT", + "peer": true, "dependencies": { "hash-base": "^3.0.0", "inherits": "^2.0.1", @@ -4257,6 +4289,7 @@ "resolved": "https://registry.npmjs.org/object-scan/-/object-scan-19.0.5.tgz", "integrity": "sha512-5rr03NDQJ3oW4gWamHxON45ZLoFe6VCsRJ+trMlYWXlnYTGsuX/eD6MPp9yItzqFhd0pUpgzPm0jrYoeubIsIA==", "license": "MIT", + "peer": true, "engines": { "node": ">= 16" } @@ -4395,6 +4428,7 @@ "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-6.2.1.tgz", "integrity": "sha512-hEt02O4hUct5wtwg4H4KcWgDdm+l1bOaEy/hWzd8xtXB9BqxTWBBhb+2ImAtH4Cv4rPjV76xN3Zumqk3k3AhhQ==", "license": "MIT", + "peer": true, "dependencies": { "@types/retry": "0.12.2", "is-network-error": "^1.0.0", @@ -4412,6 +4446,7 @@ "resolved": "https://registry.npmjs.org/p-throttle/-/p-throttle-5.1.0.tgz", "integrity": "sha512-+N+s2g01w1Zch4D0K3OpnPDqLOKmLcQ4BvIFq3JC0K29R28vUOjWpO+OJZBNt8X9i3pFCksZJZ0YXkUGjaFE6g==", "license": "MIT", + "peer": true, "engines": { "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, @@ -5129,6 +5164,7 @@ "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", "license": "MIT", + "peer": true, "engines": { "node": ">= 4" } @@ -5188,6 +5224,7 @@ "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", "license": "MIT", + "peer": true, "dependencies": { "hash-base": "^3.0.0", "inherits": "^2.0.1" @@ -5452,6 +5489,7 @@ "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", "license": "(MIT AND BSD-3-Clause)", + "peer": true, "dependencies": { "inherits": "^2.0.1", "safe-buffer": "^5.0.1" @@ -6405,6 +6443,18 @@ "node": ">= 0.4.0" } }, + "node_modules/uuid": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.0.5.tgz", + "integrity": "sha512-508e6IcKLrhxKdBbcA2b4KQZlLVp2+J5UwQ6F7Drckkc5N9ZJwFa4TgWtsww9UG8fGHbm6gbV19TdM5pQ4GaIA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "bin": { + "uuid": "dist/esm/bin/uuid" + } + }, "node_modules/varint": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/varint/-/varint-5.0.0.tgz", diff --git a/package.json b/package.json index 1fd6e84..67e433f 100644 --- a/package.json +++ b/package.json @@ -35,9 +35,9 @@ "dependencies": { "cached-hafas-client": "^5.0.1", "cli-native": "^1.0.0", - "db-hafas": "^6.0.0", "db-stations": "^5.0.0", "db-stations-autocomplete": "^4.0.0", + "db-vendo-client": "^6.3.3", "etag": "^1.8.1", "hafas-client-health-check": "^2.1.1", "hafas-rest-api": "^5.1.0", From eadd16a696324e625d7f2f41177c692bc354985e Mon Sep 17 00:00:00 2001 From: Traines Date: Mon, 20 Jan 2025 18:13:22 +0000 Subject: [PATCH 2/4] add support for multiple travellers --- api.js | 15 ++++++++++++--- lib/loyalty-cards.js | 1 + 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/api.js b/api.js index 294c9ae..a00e6d6 100644 --- a/api.js +++ b/api.js @@ -15,7 +15,7 @@ import {createCachedHafasClient} from 'cached-hafas-client' import {createRedisStore} from 'cached-hafas-client/stores/redis.js' import serveStatic from 'serve-static' import {parseBoolean, parseInteger} from 'hafas-rest-api/lib/parse.js' -import {loyaltyCardParser} from './lib/loyalty-cards.js' +import {loyaltyCardParser, parseLoyaltyCard} from './lib/loyalty-cards.js' import {route as stations} from './routes/stations.js' import {route as station} from './routes/station.js' import {parseRoutingMode} from './lib/parse.js' @@ -86,11 +86,20 @@ if (process.env.REDIS_URL) { ) } +const parseArrayOr = (parseEntry) => { + return (key, val) => { + if (Array.isArray(val)) { + return val.map(e => parseEntry(key, e)); + } + return parseEntry(key, val); + } +} + const mapRouteParsers = (route, parsers) => { if (route !== 'journeys') return parsers return { ...parsers, - loyaltyCard: loyaltyCardParser, + loyaltyCard: {...loyaltyCardParser, parse: parseArrayOr(parseLoyaltyCard)}, firstClass: { description: 'Search for first-class options?', type: 'boolean', @@ -101,7 +110,7 @@ const mapRouteParsers = (route, parsers) => { description: 'Age of traveller', type: 'integer', defaultStr: '*adult*', - parse: parseInteger + parse: parseArrayOr(parseInteger) }, routingMode: { description: 'HAFAS routing mode, see the "Routing Mode" section', diff --git a/lib/loyalty-cards.js b/lib/loyalty-cards.js index b54c508..1499ad2 100644 --- a/lib/loyalty-cards.js +++ b/lib/loyalty-cards.js @@ -18,6 +18,7 @@ const types = Array.from(typesByName.keys()) const parseLoyaltyCard = (key, val) => { if (typesByName.has(val)) return typesByName.get(val) + if (!val) return null; throw new Error(key + ' must be one of ' + types.join(', ')) } From f9c73c25fa349c9e06f38bbe29d13c827c427211 Mon Sep 17 00:00:00 2001 From: Traines Date: Mon, 27 Jan 2025 22:10:35 +0000 Subject: [PATCH 3/4] docs, why not to use --- architecture.svg | 18 ++---------------- docs/readme.md | 30 ++++++++++++++++++++++-------- readme.md | 4 ++-- 3 files changed, 26 insertions(+), 26 deletions(-) diff --git a/architecture.svg b/architecture.svg index 4d66e47..456f260 100644 --- a/architecture.svg +++ b/architecture.svg @@ -53,27 +53,13 @@ hafas-rest-api - - - - exposes - - - - db-hafas - exposes - - extends - - - - - hafas-client + + db-vendo-client diff --git a/docs/readme.md b/docs/readme.md index e06dcf7..94d4c64 100644 --- a/docs/readme.md +++ b/docs/readme.md @@ -2,29 +2,43 @@ [`v6.db.transport.rest`](https://v6.db.transport.rest/) is a [REST API](https://restfulapi.net) for the public transportation system in Germany. -## The API is currently unavailable! - -**The underlying [DB HAFAS API is currently not available](https://github.com/public-transport/hafas-client/issues/331)**, and it seems like it has been shut off permanently. We're considering changing `db-rest` to use [`db-vendo-client`](https://github.com/public-transport/db-vendo-client), **please follow [Issue #60](https://github.com/derhuerst/db-rest/issues/60) for updates**. - -You can also use [`db-vendo-client`](https://github.com/public-transport/db-vendo-client) yourself as a replacement, it covers most of the use cases served by `db-rest`, but [the underlying APIs seem to have a **much lower rate limit**](https://github.com/public-transport/db-vendo-client/issues/10). +The [DB HAFAS API is currently not available](https://github.com/public-transport/hafas-client/issues/331), and it seems like it has been shut off permanently. `db-rest` now uses [`db-vendo-client`](https://github.com/public-transport/db-vendo-client) as a backend. It covers most of the use cases served by `db-rest`, notably except for `/stops/reachable-from` and `/radar`. Please also note some further limitations and caveats over in the readme and documentation of [`db-vendo-client`](https://github.com/public-transport/db-vendo-client). Also, [the underlying APIs seem to have a **much lower rate limit**](https://github.com/public-transport/db-vendo-client/issues/10). ⚠️ Hence, make sure [that you cannot obtain the data needed for your use case in a more efficient manner, e.g. using the available GTFS feeds](#why-not-to-use-this-api). [![API status](https://badgen.net/uptime-robot/status/m793274556-25c5e9bbab0297d91cda7134)](https://stats.uptimerobot.com/57wNLs39M/793274556) ## How it works -Because it wraps [an API](https://github.com/public-transport/hafas-client/blob/6/readme.md#background) of [Deutsche Bahn](https://de.wikipedia.org/wiki/Deutsche_Bahn), it **includes most of the long-distance and regional traffic, as well as some international trains and local buses**. Essentially, it returns whatever data the [*DB Navigator* app](https://www.bahn.de/p/view/service/mobile/db-navigator.shtml) shows*, **including realtime delays and disruptions**. +Because it wraps [an API](https://github.com/public-transport/db-vendo-client/blob/main/docs/db-apis.md) of [Deutsche Bahn](https://de.wikipedia.org/wiki/Deutsche_Bahn), it **includes most of the long-distance and regional traffic, as well as some international trains and local buses**. Essentially, it returns whatever data the [*DB Navigator* app](https://www.bahn.de/p/view/service/mobile/db-navigator.shtml) shows*, **including realtime delays and disruptions**. -*When comparing results from this API to what the DB Navigator app shows there might be occasional differences due to them utilizing different, not 100% identical backends.* +*When comparing results from this API to what the DB Navigator app shows there might be occasional differences due to them utilizing different, not 100% identical backends.* - [Getting Started](getting-started.md) - [API documentation](api.md) (run `npm run build` to generate) - [OpenAPI playground with API documentation](https://petstore.swagger.io/?url=https%3A%2F%2Fv6.db.transport.rest%2F.well-known%2Fservice-desc%0A) +## Why not to use this API? + +### Low rate limits + +[The underlying APIs seem to have a **much lower rate limit**](https://github.com/public-transport/db-vendo-client/issues/10) than before, i.e. you should not use this service to send many requests in an automated manner. Instead, you may: + +### Use GTFS and GTFS-RT + +[GTFS](https://gtfs.org) and [GTFS-RT](https://gtfs.org/documentation/realtime/reference/) are file format/feed specifications for scheduled timetables and realtime updates like delays, respectively. They enable you to download datasets for entire transport associations, regions or even countries in one go, for local querying (e.g. with [MOTIS](https://github.com/motis-project/motis) or [OTP](https://github.com/opentripplanner/OpenTripPlanner/)) and analysis (e.g. with [gtfs-via-postgres](https://github.com/public-transport/gtfs-via-postgres) and [print-gtfs-rt-cli](https://github.com/derhuerst/print-gtfs-rt-cli)). For Germany, [GTFS](https://www.opendata-oepnv.de/ht/de/organisation/delfi/startseite?tx_vrrkit_view%5Baction%5D=details&tx_vrrkit_view%5Bcontroller%5D=View&tx_vrrkit_view%5Bdataset_name%5D=deutschlandweite-sollfahrplandaten-gtfs&cHash=af4be4c0a9de59953fb9ee2325ef818f) and [GTFS-RT](https://mobilithek.info/offers/755009281410899968) feeds are provided by [DELFI e.V.](https://www.delfi.de/) Refined, publicly available feeds based on these and other sources can be obtained from [gtfs.de](https://gtfs.de) and [stc.traines.eu](https://stc.traines.eu/mirror/). I.e. by using these you do not need to make any excessive API requests, however, the data quality and coverage of these feeds will currently in many cases still be inferior to what is provided by Deutsche Bahn. + +### Use other APIs + +[transitous.org](https://transitous.org) may be another option, even with worldwide coverage based on GTFS/RT-feeds, however, as with any other APIs, it should not be flooded with requests. + +### Run your own instance of this API + +It may help to distribute the load by running your own instance of `db-rest`/[`db-vendo-client`](https://github.com/public-transport/db-vendo-client/). Both provide Dockerfiles/Docker images for easy setup of the REST API server. `db-rest` additionally includes a caching layer (if configured correctly), serves the OpenAPI specification, and does some more plumbing. + ## Why use this API? ### Realtime Data -This API returns realtime data whenever it is upstream. The [API for DB's mobile app](https://github.com/public-transport/hafas-client/blob/6/p/db/readme.md) provides it. +This API returns realtime data whenever it is available upstream, as the API for DB's mobile app provides it. *Note: Different endpoints might remove realtime data like delays and cancellations at different times, i.e. after a journey's arrival.* diff --git a/readme.md b/readme.md index f308dec..0c31674 100644 --- a/readme.md +++ b/readme.md @@ -5,8 +5,8 @@ [**API Documentation**](docs/readme.md) > [!IMPORTANT] -> The [DB HAFAS API is currently not available](https://github.com/public-transport/hafas-client/issues/331), and it seems like it has been shut off permanently. We're considering changing `db-rest` to use [`db-vendo-client`](https://github.com/public-transport/db-vendo-client), please follow [Issue #60](https://github.com/derhuerst/db-rest/issues/60) for updates. -> You can also use [`db-vendo-client`](https://github.com/public-transport/db-vendo-client) yourself as a replacement, it covers most of the use cases served by `db-rest`, but [the underlying APIs seem to have a **much lower rate limit**](https://github.com/public-transport/db-vendo-client/issues/10). ⚠️ +> The [DB HAFAS API is currently not available](https://github.com/public-transport/hafas-client/issues/331), and it seems like it has been shut off permanently. `db-rest` now uses [`db-vendo-client`](https://github.com/public-transport/db-vendo-client) as a backend. It covers most of the use cases served by `db-rest`, notably except for `/stops/reachable-from` and `/radar`. Please also note some further limitations and caveats over in the readme and documentation of [`db-vendo-client`](https://github.com/public-transport/db-vendo-client). Also, [the underlying APIs seem to have a **much lower rate limit**](https://github.com/public-transport/db-vendo-client/issues/10). ⚠️ Hence, make sure [that you cannot obtain the data needed for your use case in a more efficient manner, e.g. using the available GTFS feeds](docs#why-not-to-use-this-api). + ![db-rest architecture diagram](architecture.svg) From ae0e238e79c3f18f3e2d8a0b4953e5ef65319165 Mon Sep 17 00:00:00 2001 From: Traines Date: Fri, 14 Feb 2025 00:06:30 +0000 Subject: [PATCH 4/4] move loyaltyCard parsing to db-vendo-client, remove routingModes --- api.js | 41 +---------------------------------------- lib/loyalty-cards.js | 37 ------------------------------------- lib/parse.js | 12 ------------ package-lock.json | 8 ++++---- package.json | 2 +- test/index.js | 5 +++-- 6 files changed, 9 insertions(+), 96 deletions(-) delete mode 100644 lib/loyalty-cards.js delete mode 100644 lib/parse.js diff --git a/api.js b/api.js index a00e6d6..d270979 100644 --- a/api.js +++ b/api.js @@ -14,12 +14,9 @@ import Redis from 'ioredis' import {createCachedHafasClient} from 'cached-hafas-client' import {createRedisStore} from 'cached-hafas-client/stores/redis.js' import serveStatic from 'serve-static' -import {parseBoolean, parseInteger} from 'hafas-rest-api/lib/parse.js' -import {loyaltyCardParser, parseLoyaltyCard} from './lib/loyalty-cards.js' +import {mapRouteParsers} from 'db-vendo-client/lib/api-parsers.js' import {route as stations} from './routes/stations.js' import {route as station} from './routes/station.js' -import {parseRoutingMode} from './lib/parse.js' -import {routingModes} from 'hafas-client/p/db/routing-modes.js' const pkg = require('./package.json') @@ -86,42 +83,6 @@ if (process.env.REDIS_URL) { ) } -const parseArrayOr = (parseEntry) => { - return (key, val) => { - if (Array.isArray(val)) { - return val.map(e => parseEntry(key, e)); - } - return parseEntry(key, val); - } -} - -const mapRouteParsers = (route, parsers) => { - if (route !== 'journeys') return parsers - return { - ...parsers, - loyaltyCard: {...loyaltyCardParser, parse: parseArrayOr(parseLoyaltyCard)}, - firstClass: { - description: 'Search for first-class options?', - type: 'boolean', - default: 'false', - parse: parseBoolean, - }, - age: { - description: 'Age of traveller', - type: 'integer', - defaultStr: '*adult*', - parse: parseArrayOr(parseInteger) - }, - routingMode: { - description: 'HAFAS routing mode, see the "Routing Mode" section', - type: 'string', - enum: Object.keys(routingModes), - defaultStr: '`REALTIME`', - parse: parseRoutingMode - }, - } -} - const modifyRoutes = (routes, hafas, config) => { routes['/stations/:id'] = station routes['/stations'] = stations diff --git a/lib/loyalty-cards.js b/lib/loyalty-cards.js deleted file mode 100644 index 1499ad2..0000000 --- a/lib/loyalty-cards.js +++ /dev/null @@ -1,37 +0,0 @@ -import {data as cards} from 'hafas-client/p/db/loyalty-cards.js' - -const typesByName = new Map([ - // https://github.com/public-transport/hafas-client/blob/68ecd7c5e976dd2f51c5c64a81600e7e181a8996/p/db/loyalty-cards.js#L6-L11 - ['bahncard-1st-25', {type: cards.BAHNCARD, discount: 25, class: 1}], - ['bahncard-2nd-25', {type: cards.BAHNCARD, discount: 25, class: 2}], - ['bahncard-1st-50', {type: cards.BAHNCARD, discount: 50, class: 1}], - ['bahncard-2nd-50', {type: cards.BAHNCARD, discount: 50, class: 2}], - ['vorteilscard', {type: cards.VORTEILSCARD}], - ['halbtaxabo-railplus', {type: cards.HALBTAXABO, railplus: true}], - ['halbtaxabo', {type: cards.HALBTAXABO, railplus: false}], - ['voordeelurenabo-railplus', {type: cards.VOORDEELURENABO, railplus: true}], - ['voordeelurenabo', {type: cards.VOORDEELURENABO, railplus: false}], - ['shcard', {type: cards.SHCARD}], - ['generalabonnement', {type: cards.GENERALABONNEMENT}], -]) -const types = Array.from(typesByName.keys()) - -const parseLoyaltyCard = (key, val) => { - if (typesByName.has(val)) return typesByName.get(val) - if (!val) return null; - throw new Error(key + ' must be one of ' + types.join(', ')) -} - -const loyaltyCardParser = { - description: `Type of loyalty card in use.`, - type: 'string', - enum: types, - defaultStr: '*none*', - parse: parseLoyaltyCard, -} - -export { - cards as loyaltyCards, - parseLoyaltyCard, - loyaltyCardParser, -} diff --git a/lib/parse.js b/lib/parse.js deleted file mode 100644 index 3ec0f1c..0000000 --- a/lib/parse.js +++ /dev/null @@ -1,12 +0,0 @@ -import {routingModes} from 'hafas-client/p/db/routing-modes.js' - -const parseRoutingMode = (key, val) => { - if ('string' !== typeof val) throw new Error(key + ' must be a string') - val = val.toUpperCase() - if(Object.prototype.hasOwnProperty.call(routingModes, val)) return routingModes[val] - throw new Error(key + ' must be one of ' + Object.keys(routingModes).join(', ')) -} - -export { - parseRoutingMode -} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index c9a73c8..323cc1b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,7 +13,7 @@ "cli-native": "^1.0.0", "db-stations": "^5.0.0", "db-stations-autocomplete": "^4.0.0", - "db-vendo-client": "^6.3.3", + "db-vendo-client": "^6.5.0", "etag": "^1.8.1", "hafas-client-health-check": "^2.1.1", "hafas-rest-api": "^5.1.0", @@ -1251,9 +1251,9 @@ } }, "node_modules/db-vendo-client": { - "version": "6.3.3", - "resolved": "https://registry.npmjs.org/db-vendo-client/-/db-vendo-client-6.3.3.tgz", - "integrity": "sha512-q4ErpRIqthKj+uOZJkt1VwA12gFutC7cGszyKDOf5BH9EF6WLYq7BYlK8s0HmCpsUAzTQ6UehWLZFhMsCJk/dQ==", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/db-vendo-client/-/db-vendo-client-6.5.0.tgz", + "integrity": "sha512-wPdI0Cv+omo2UiiB4rT6cf/Td53snetS1vtifqVW3iy0RV64c5jkJhfCQuCfp3c/IrMs/npZRBUmBPyKG2Kebg==", "dependencies": { "@derhuerst/round-robin-scheduler": "^1.0.4", "content-type": "^1.0.4", diff --git a/package.json b/package.json index 67e433f..78c9c4a 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,7 @@ "cli-native": "^1.0.0", "db-stations": "^5.0.0", "db-stations-autocomplete": "^4.0.0", - "db-vendo-client": "^6.3.3", + "db-vendo-client": "^6.5.0", "etag": "^1.8.1", "hafas-client-health-check": "^2.1.1", "hafas-rest-api": "^5.1.0", diff --git a/test/index.js b/test/index.js index a04b358..0cb9ec2 100644 --- a/test/index.js +++ b/test/index.js @@ -1,7 +1,7 @@ import tape from 'tape' import _ndjson from 'ndjson' const {parse: ndjsonParser} = _ndjson -import {loyaltyCards} from '../lib/loyalty-cards.js' +import {data as loyaltyCards} from 'db-vendo-client/format/loyalty-cards.js' import {fetchWithTestApi} from './util.js' import {pStations as pAllStations} from '../lib/db-stations.js' @@ -40,7 +40,7 @@ tape.test('/journeys?loyaltyCard works', async (t) => { } }, {}, '/journeys?from=123&to=234&loyaltyCard=bahncard-2nd-50') }) - +/* tape.test('/journeys?routingMode works', async (t) => { await fetchWithTestApi({ journeys: async (from, to, opt = {}) => { @@ -49,6 +49,7 @@ tape.test('/journeys?routingMode works', async (t) => { } }, {}, '/journeys?from=123&to=234&routingMode=HYbriD') }) +*/ tape.test('/stations works', async (t) => { const {data: allStations} = await pAllStations