/journeys: expose loyaltyCard and firstClass, rebuild API docs 📝

fixes #9
closes #23
This commit is contained in:
Julian Schmidhuber 2022-04-02 17:02:25 +02:00 committed by Jannis R
parent 622fcfbf70
commit 666c84b5f7
No known key found for this signature in database
GPG key ID: 0FE83946296A88A5
5 changed files with 93 additions and 3 deletions

19
api.js
View file

@ -8,7 +8,9 @@ const withCache = require('cached-hafas-client')
const redisStore = require('cached-hafas-client/stores/redis')
const {join: pathJoin} = require('path')
const serveStatic = require('serve-static')
const {parseBoolean} = require('hafas-rest-api/lib/parse')
const pkg = require('./package.json')
const {loyaltyCardParser} = require('./lib/loyalty-cards')
const stations = require('./routes/stations')
const station = require('./routes/station')
@ -41,7 +43,21 @@ if (process.env.REDIS_URL) {
)
}
const modifyRoutes = (routes) => {
const mapRouteParsers = (route, parsers) => {
if (route !== 'journeys') return parsers
return {
...parsers,
loyaltyCard: loyaltyCardParser,
firstClass: {
description: 'Search for first-class options?',
type: 'boolean',
default: 'false',
parse: parseBoolean,
},
}
}
const modifyRoutes = (routes, hafas, config) => {
routes['/stations/:id'] = station
routes['/stations'] = stations
return routes
@ -61,6 +77,7 @@ const config = {
etags: 'strong',
csp: `default-src 'none' style-src 'self' 'unsafe-inline' img-src https:`,
healthCheck,
mapRouteParsers,
modifyRoutes,
}

View file

@ -381,6 +381,8 @@ parameter | description | type | default value
`remarks` | Parse & return hints & warnings? | boolean | `true`
`scheduledDays` | Parse & return dates each journey is valid on? | boolean | `false`
`language` | Language of the results. | string | `en`
`loyaltyCard` | Type of loyalty card in use. See https://github.com/public-transport/hafas-client/blob/68ecd7c5e976dd2f51c5c64a81600e7e181a8996/p/db/loyalty-cards.js#L6-L11. | string | *none*
`firstClass` | Search for first-class options? | boolean | `false`
`nationalExpress` | Include InterCityExpress (ICE)? | boolean | `true`
`national` | Include InterCity & EuroCity (IC/EC)? | boolean | `true`
`regionalExp` | Include RegionalExpress & InterRegio (RE/IR)? | boolean | `true`

36
lib/loyalty-cards.js Normal file
View file

@ -0,0 +1,36 @@
const {data: cards} = require('hafas-client/p/db/loyalty-cards')
const DOCS_URL = 'https://github.com/public-transport/hafas-client/blob/68ecd7c5e976dd2f51c5c64a81600e7e181a8996/p/db/loyalty-cards.js#L6-L11'
const typesByName = new Map([
['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)
throw new Error(key + ' must be one of ' + types.join(', '))
}
const loyaltyCardParser = {
description: `Type of loyalty card in use. See ${DOCS_URL}.`,
type: 'string',
enum: types,
defaultStr: '*none*',
parse: parseLoyaltyCard,
}
module.exports = {
parseLoyaltyCard,
loyaltyCardParser,
}

View file

@ -29,7 +29,7 @@
"db-stations-autocomplete": "^2.2.0",
"etag": "^1.8.1",
"hafas-client-health-check": "^2.1.1",
"hafas-rest-api": "^3.7.0",
"hafas-rest-api": "^3.8.0",
"ioredis": "^4.28.1",
"serve-buffer": "^2.0.0",
"serve-static": "^1.14.1"

View file

@ -1,6 +1,41 @@
'use strict'
const tape = require('tape')
const {loyaltyCards} = require('../lib/loyalty-cards')
const {fetchWithTestApi} = require('./util')
// todo
const NO_JOURNEYS = {
// todo?
journeys: [],
}
tape.test('/journeys?firstClass works', async (t) => {
await fetchWithTestApi({
journeys: async (from, to, opt = {}) => {
t.equal(opt.firstClass, true, 'journeys() called with invalid opt.firstClass')
return NO_JOURNEYS
}
}, {}, '/journeys?from=123&to=234&firstClass=true')
})
tape.test('/journeys?loyaltyCard works', async (t) => {
await fetchWithTestApi({
journeys: async (from, to, opt = {}) => {
t.deepEqual(opt.loyaltyCard, {
type: loyaltyCards.SHCARD,
}, 'journeys() called with invalid opt.loyaltyCard')
return NO_JOURNEYS
}
}, {}, '/journeys?from=123&to=234&loyaltyCard=shcard')
await fetchWithTestApi({
journeys: async (from, to, opt = {}) => {
t.deepEqual(opt.loyaltyCard, {
type: loyaltyCards.BAHNCARD,
discount: 50,
class: 2,
}, 'journeys() called with invalid opt.loyaltyCard')
return NO_JOURNEYS
}
}, {}, '/journeys?from=123&to=234&loyaltyCard=bahncard-2nd-50')
})