This project provides a convenient wrapper around the LTA DataMall API, simplifying access to bus-related information. Built using Koa and TypeScript, it offers a more streamlined interface for common use cases.
The main reason for building this was that the raw LTA DataMall endpoints for bus stops, services, and routes can be a bit tricky to use, especially when you just want to grab specific details. This service grabs all the bus stop, service, and route data, gives it a good shake, and re-parses it into a data structure that's actually useful.
Specifically, bus stop, service, and route data are retrieved, processed and then stored into two handy JSON files: bus-services.json and bus-stops.json. These files are the backbone of the server, providing the data for all your bus-related queries.
That's a great question! Yes, bus information can change. That's why the data is refreshed every week. This refresh is handled by a cron job running on a Cloudflare Worker, ensuring the data stays reasonably up-to-date.
After generating the JSON files, the server also publishes a compact route distance index (route-distances/v1.json.gz) to the project's Firebase Storage bucket, which the app uses to measure how far a bus is from a stop along its route. See ADR-0002. The upload is skipped when the index hasn't changed, and a failed upload never fails JSON generation.
It uses Google application default credentials:
| Variable | Purpose |
|---|---|
GOOGLE_APPLICATION_CREDENTIALS |
Path to a service account key that can write to the bucket. Not needed on the GCE VM, which uses its attached service account (it needs a Storage write role and the devstorage.read_write or cloud-platform scope). |
FIREBASE_STORAGE_EMULATOR_HOST |
Upload to the Firebase Storage emulator instead, e.g. localhost:9199 for the emulator in the app repo. |
With ENV=dev, the upload only runs when FIREBASE_STORAGE_EMULATOR_HOST is set. Without credentials, the upload is skipped with a warning.
The beta server runs from docker-compose.beta.yml behind a Cloudflare Tunnel pointed at http://localhost:8088. docker-compose.yml is the production image that CI builds and pushes, so leave it alone.
cp .env.example .env # then fill in the values
docker compose -f docker-compose.beta.yml up -d --build
curl http://localhost:8088/
curl -X POST http://localhost:8088/generate-json --header "secret: $SECRET"To publish the route distance index from beta, put a service account key at secrets/firebase-sa.json and set GOOGLE_APPLICATION_CREDENTIALS=/app/secrets/firebase-sa.json in .env.
