mbta.sh
I’ve been interested in making a public transit application for my Apple Watch for a while. In Boston, where I live, there are some good iOS applications for tracking buses and trains, but none of them provide a complementary extension for the Apple Watch. So I finally decided to take a crack at one myself. The only problem: I know little about transit APIs, and even less about Swift. Thankfully, I enjoy a good challenge!
First Things First
My first step: get familiar with the API(s) provided by the MBTA, the public transportation authority in the Boston area. The V3 API provides a variety of endpoints which can be used to gather information about stops, routes, schedules, or even vehicles in real-time. The API, which returns JSON in accordance with the json-api specification, is well documented on the MBTA website here.
I ended up writing a little tool to help me make simple queries right from the command line. While it might make more sense to do this type of thing from Python - or some other scripting language with better networking/JSON support - I actually enjoy doing this type of thing in bash. I like staying in the shell, unless I absolutely need to leave it. Plus, I like to keep things as simple as possible, and for something as simple as building some simple URLs and sending an HTTP request, bash is perfect.
mbta.sh
The tool I wrote is mbta-sh, a simple
command-line utility for querying the MBTA V3 API. All of the API endpoints are
available with the tool, as well as all of the filters, includes, and additional
field and page-limit constraints. You can string together all of the parameters
you need to make your request. For instance, if I want to get a list of the
next few Red Line trains entering South Station, I can hit the predictions
endpoint like so:
$ mbta.sh predictions \
--filter route Red \
--filter stop place-sstat \
--include trip,vehicle \
--fields id
The response gets “pretty printed” with jq
on it’s way to STDOUT
:
{
"data": [
{
"attributes": {},
"id": "prediction-47254508-70079-90",
"relationships": {
"route": {
"data": {
"id": "Red",
"type": "route"
}
},
"stop": {
"data": {
"id": "70079",
"type": "stop"
}
},
"trip": {
"data": {
"id": "47254508",
"type": "trip"
}
},
"vehicle": {
"data": {
"id": "R-5469A04C",
"type": "vehicle"
}
}
},
"type": "prediction"
}
],
"included": [
{
"attributes": {
"bikes_allowed": 0,
"block_id": "S931_-4",
"direction_id": 0,
"headsign": "Ashmont",
"name": "",
"wheelchair_accessible": 1
},
"id": "47254508",
"links": {
"self": "/trips/47254508"
},
"relationships": {
...
},
"type": "trip"
},
{
"attributes": {
"bearing": 135,
"current_status": "INCOMING_AT",
"current_stop_sequence": 90,
"direction_id": 0,
"label": "1814",
"latitude": 42.35449,
"longitude": -71.0588,
"occupancy_status": null,
"speed": null,
"updated_at": "2021-03-14T14:40:27-04:00"
},
"id": "R-5469A04C",
"relationships": {
...
},
"type": "vehicle"
}
],
"jsonapi": {
"version": "1.0"
}
}
You can also easily pipe the output to jq
if you want to pull a few fields.
For instance, if I want the headsign of the first train:
$ mbta.sh predictions \
--filter route Red \
--filter stop place-sstat \
--include trip,vehicle \
--fields id | jq -r '.included[0].headsign'
Ashmont
This little tool helped me get my bearings with the V3 API pretty quickly. Plus, it was immensely helpful as I moved to performing these queries in Swift. Once I’ve made some decent progress on that front, I’ll post another update.