AfterBridge Released to Serve Old CSV Exports and SQLite Files as a JSON API
Aftermarket 0.9.0 adds AfterBridge, run as aftermarket bridge. It’s for the app that never got an API. It drops a CSV export into a folder every night, or keeps everything in a SQLite file, and anything else that wants the data has to go and parse the files.
So everyone writes their own little parser. One forgets the quoted commas, one reads the file while the app is still writing it, one treats the empty cell as zero. AfterBridge does that part once, and gives the rest a JSON API.
A config
version: 1
sources:
- id: orders
csv: {folder: exports, pattern: "orders-*.csv"}
key: id
columns: {id: integer, total: number, paid: boolean, placed: date}
exclude: [internal_note]
- id: products
sqlite: {db: inventory.db, table: products}
key: sku
exclude: [photo]
endpoints:
- path: /orders
source: orders
filters: [paid, placed]
- path: /orders/{id}
source: orders
- path: /products/{sku}
source: products
The orders come from the newest export in the folder, picked by name, so dated exports give the latest day. The columns get real types, the internal note never leaves, and /orders?paid=false or /orders/1003 answer in JSON. The products come straight out of the app’s SQLite database, read-only.
Never half a file
The hard part of reading another program’s files is reading them at the wrong moment. AfterBridge reads each source into a snapshot in memory and serves from that. When the file changes, it waits until the file has been left alone for a couple of seconds, reads it, and checks it is whole: a final line break, every row complete, every value its declared type, every order number there once. Only then do requests move to the new snapshot.
A file that fails any of that is refused, logged once, and the previous good version keeps being served. In the case study, an export written in two pieces and one with twelve in a price column both stay out.
Read only, all the way down
Only GET and HEAD are answered. The only SQL that ever runs is the query in your config, through the sqlite3 program in read-only safe mode, and a request just picks rows out of a snapshot. Order numbers, filter values and anything else a client sends never get near SQL or the file system, and the log records which endpoint was asked, not what for.
What it doesn’t do
No writes, no logins, no joins across sources. For logins and rate limits, put AfterGuard in front. Filters are exact matches, and a whole source sits in memory.
The AfterBridge reference has the full format, the testing post covers what the review found, and the download page has the binaries.