This is the backend companion to transit-app-next, and provides static GTFS data via PostgreSQL/PostGIS, as well as serves JSON endpoints to access GTFS-Realtime data.
This project built with NestJS, TypeORM and TypeScript. This project is in its infancy, and should be considered a work-in-progress! There is so much more to do.
The database back-end for transit-app-api
allows for multiple feeds to be stored simultaneously. A good use case for this would be to serve data for not only subways, but also bus routes/stops, metro trains, ferries, etc. An example of this will eventually be built into this project.
Run:
npm run start:dev
Api is available at http://localhost:5000/api/v1/
. Swagger documentation is enabled at http://localhost:5000/api/v1/docs/
, though this is presently minimal while the api is being hashed out. The appropriate decorators from @nestjs/swagger
will be implemented once this becomes stable.
This application uses Redis for caching and session management, which can be configured in .env
:
REDIS_HOST=localhost
REDIS_PORT=6379
REDIS_AUTH=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Example .env
configuration:
DB_HOST=<hostname>
DB_PORT=5432
DB_USERNAME=<username>
DB_PASSWORD=<password>
DB_DATABASE=gtfs
This project depends on a PostgrSQL database populated using the gtfs-sql-importer: https://github.com/fitnr/gtfs-sql-importer. This requires a PostGIS-enabled PostgreSQL database.
Basic usage is as follows (executed from within the repo):
Export the following environment variables:
PGDATABASE=mydbname
PGHOST=example.com
PGUSER=username
(NOTE: You may need to export PGPASSWORD=password
if not otherwise authenticated to use psql
).
Then:
make init
make load GTFS=gtfs.zip
Where gtfs.zip
is the name of the downloaded .zip
file containing the GTFS data.
You will need to configure the GTFS-Realtime endpoint URLs, as well as specify the name of the access key in your .env
config which corresponds to the value provided by the transit authority to authenticate these requests:
NOTE: routes: []
is optional, and is only used to determine whether we should only request only a particular URL to boost performance. If this parameter is left out, the API will query all provided URLs.
NOTE: proto
is currently unused and may be left out. The intention is that in the future, this API may be able to extend the default gtfs-realtime.proto
with additional data specific to the transit authority. This is currently not implemented.
const gtfsRealtime = [
{
feedIndex: 1,
agencyId: 'MTA NYCT',
feedUrls: [
{
routes: ['1', '2', '3', '4', '5', '6', '7'],
url: 'https://api-endpoint.mta.info/Dataservice/mtagtfsfeeds/nyct%2Fgtfs',
},
{
routes: ['A', 'C', 'E'],
url: 'https://api-endpoint.mta.info/Dataservice/mtagtfsfeeds/nyct%2Fgtfs-ace',
},
{
routes: ['B', 'D', 'F', 'M'],
url: 'https://api-endpoint.mta.info/Dataservice/mtagtfsfeeds/nyct%2Fgtfs-bdfm',
},
],
proto: 'nyct-subway',
accessKey: 'GTFS_REALTIME_ACCESS_KEY',
},
];
Using the above configuration as an example, you would need the following variable defined in a .env
file:
GTFS_REALTIME_ACCESS_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
You will need a unique access key for each group of feed endpoints you want to authenticate. In general, you may only have one configuration in here (for this example, we are configuring for the NYC MTA subway system, but we may want to add endpoints for buses as well). These are keyed by the unique feedIndex
and agencyId
values found in the agency table (in this example, 1
and MTA NYCT
).
The proto
string refers to a complied .proto
file that is an extension of the base gtfs-realtime.proto
, in this case, nyct-subway.proto
. This gets dynamically loaded should it appear in the config, however, making use of the additional bindings it provides is still in the works.
If you have the protobuf-compiler installed (protoc
), and have a specific .proto
file you wish to use in addition to gtfs-realtime.proto
, this can be generated as follows:
From the 'proto/' directory:
npx protoc --plugin=../node_modules/.bin/protoc-gen-ts_proto --ts_proto_out=./ ./path-to-your.proto
protobufjs
is required to make use of compiled protobufs, and is included in this project's package.json
.
Swagger is currently available at:
http://localhost:5000/api/v1/docs
/api/v1/agency/feeds/1
- Get agencies by
feedIndex
=1
- Get agencies by
/api/v1/location/1
- Get center coordinates by
feedIndex
=1
- Get center coordinates by
/api/v1/routes/1
- Get all route data by
feedIndex
=1
- Get all route data by
/api/v1/routes/1/trips/7
- Get trips for route identified by
feedIndex
=1
androuteId
=7
- Get trips for route identified by
/api/v1/routes/1/id
- Get list of all route IDs for
feedIndex
=1
- Get list of all route IDs for
Note that both stops and shapes can be returned in JSON or GeoJSON. This is to provide data to clients using something like Deck.GL, where a layer (such as GeoJsonLayer
) might expect a GeoJSON object, versus something like PathLayer
which expects an array of coordinates.
/api/v1/geo/1/shapes
- Get all route line shapes by
feedIndex
=1
- Get all route line shapes by
/api/v1/geo/1/shapes?geojson=true
- Same as above, in GeoJSON format (FeatureCollection)
/api/v1/geo/1/shapes/GS.N04R
- Get GeoJSON LineString geometry identified by
feedIndex
=1
andshapeId
=GS.N04R
- Get GeoJSON LineString geometry identified by
/api/v1/geo/1/stops
- Get all stops identified by
feedIndex
=1
- Get all stops identified by
/api/v1/geo/1/stops?geojson=true
- Same as above, in GeoJSON format (FeatureCollection)
/api/v1/geo/1/stops/S09N
- Get raw station data identified by
feedIndex
=1
andstationId
=S09N
- Get raw station data identified by
Note that this API also utilizes WebSockets to deliver the following data, but provides the following endpoints for clients that prefer to use a Rest endpoint. The data structure will be identical:
/api/v1/realtime/1/alerts
- Get all real-time alerts for
feedIndex
=1
- Get all real-time alerts for
/api/v1/realtime/1/trip-updates/101,102,103,201,301,410
- Get all real-time trip-updates for
feedIndex
=1
, andstationIds
=101,102,103,201,301,410
, which is a comma-delimited list of stops (by parent-station ID) for which to receive trip-updates.
- Get all real-time trip-updates for
Your client can subscribe to the following messages to receive Alerts and Trip-Updates:
alerts
- Begin receiving alerts at 1 minute intervals
cancel_alerts
- Stop receiving alerts
trip_updates
- Begin receiving trip-updates at 30 second intervals
cancel_trip_updates
- Stop receiving trip-updates
Once connected to alerts
or trip_updates
, you can subscribe to one of the following to receive data:
received_trip_updates
, whose data adheres to the following interface:
{
feedIndex: number;
stationId: string;
transfers: string[];
routeIds: string[];
stopTimeUpdates: IStopTimeUpdate[];
}
received_alerts
:
{
feedIndex: number;
alerts: IAlert[];
}