cached-hafas-client

Pass in a HAFAS client, cache data from it.

Usage no npm install needed!

<script type="module">
  import cachedHafasClient from 'https://cdn.skypack.dev/cached-hafas-client';
</script>

README

cached-hafas-client

Pass in a HAFAS client, cache data from it.

npm version build status ISC-licensed support me via GitHub Sponsors chat with me on Twitter

Note: This package is mainly intended to prevent expensive and/or frequent API calls to HAFAS. As a side effect, it may reduce local CPU load & latency, but that depends on the specific use case.

cached-hafas-client's core logic is separated from data storage code; You can pick the store implementation that fits your use case best. Right now the following stores are implemented:

store name built on top of notes
cached-hafas-client/stores/redis Redis
cached-hafas-client/stores/sqlite SQLite TTL not implemented yet
cached-hafas-client/stores/in-memory in-memory (using quick-lru)

Installation

npm install cached-hafas-client

Usage

Let's set up a cached hafas-client instance.

// create HAFAS client
const createHafas = require('vbb-hafas')
const hafas = createHafas('my-awesome-program')

// create a store backed by Redis
const Redis = require('ioredis')
const createRedisStore = require('cached-hafas-client/stores/redis')
const redis = new Redis()
const store = createRedisStore(redis)

// wrap HAFAS client with cache
const withCache = require('cached-hafas-client')
const cachedHafas = withCache(hafas, store)

Because cached-hafas-client caches HAFAS responses by "request signature", it is build on the assumption that, HAFAS works deterministically, aside from the ever-changing transit data underneath. Because there are no guarantees for this, use cached-hafas-client with a grain of salt.

This is why you must send deterministic queries; for example, you must pass opt.duration to departures()/arrivals() for it to know which "time range" the data returned by HAFAS is for.

const wollinerStr = '900000007105'
const husemannstr = '900000110511'
const when = new Date(Date.now() + 60 * 60 * 1000)

// will fetch fresh data from HAFAS
await cachedHafas.departures(wollinerStr, {duration: 10, when})

// within the "time range" of the departures() call above,
// so it will use the cached data
await cachedHafas.departures(wollinerStr, {
    duration: 3, when: new Date(+when + 3 * 60 * 1000)
})

Note: cached-hafas-client is only compatible with hafas-client@5.

Using a custom TTL

const cachePeriod = 5 * 60 * 1000 // 5 minutes
const cachedHafas = withCache(hafas, store, cachePeriod)

Counting cache hits & misses

cachedHafas.on('hit', (hafasClientMethod, ...args) => {
    console.info('cache hit!', hafasClientMethod, ...args)
})
cachedHafas.on('miss', (hafasClientMethod, ...args) => {
    console.info('cache miss!', hafasClientMethod, ...args)
})

Bypassing the cache

const {CACHED} = require('cached-hafas-client')

// will always fresh data
await cachedHafas.departures(wollinerStr, {[CACHED]: false})

API

createCachedHafas(hafas, storage, opt = {})

hafas must be a hafas-client@5-compatible API client.

opt overrides this default configuration:

{
    cachePeriods: {
        departures: 30_1000, arrivals: 30_1000, // 30s
        journeys: 30_1000, // 30s
        refreshJourney: 60_1000, // 1m
        trip: 30_1000, // 30s
        radar: 10_1000, // 10s
        locations: 3_600_1000, // 1h
        stop: 3_600_1000, // 1h
        nearby: 3_600_1000, // 1h
        reachableFrom: 30_1000,
    },
}

Contributing

If you have a question or need support using cached-hafas-client, please double-check your code and setup first. If you think you have found a bug or want to propose a feature, use the issues page.