872 lines
20 KiB
Markdown
872 lines
20 KiB
Markdown
# GTFS API Documentation
|
|
|
|
Comprehensive API documentation for the Skopje Bus Tracker GTFS-based API.
|
|
|
|
## Table of Contents
|
|
|
|
- [Overview](#overview)
|
|
- [OpenAPI Specification](#openapi-specification)
|
|
- [Base URL](#base-url)
|
|
- [GTFS Static Data Endpoints](#gtfs-static-data-endpoints)
|
|
- [Real-Time Data Endpoints](#real-time-data-endpoints)
|
|
- [Historical Data Endpoints](#historical-data-endpoints)
|
|
- [Statistics & Analytics Endpoints](#statistics--analytics-endpoints)
|
|
- [Data Models](#data-models)
|
|
- [Error Handling](#error-handling)
|
|
- [Rate Limiting](#rate-limiting)
|
|
|
|
---
|
|
|
|
## Overview
|
|
|
|
This API provides access to Skopje public transport data based on the **GTFS (General Transit Feed Specification)** standard. It combines static GTFS data with real-time information and historical analytics stored in TimescaleDB.
|
|
|
|
### Key Features
|
|
- **GTFS-compliant** static data (stops, routes)
|
|
- **Real-time** vehicle positions and arrival predictions
|
|
- **Historical** time-series data for analytics
|
|
- **Statistical** analysis of delays and patterns
|
|
|
|
### Upstream API
|
|
|
|
This application consumes data from the **ModeShift GTFS API**. For documentation on the upstream API endpoints:
|
|
- See **[UPSTREAM-API-DOCUMENTATION.md](UPSTREAM-API-DOCUMENTATION.md)**
|
|
|
|
---
|
|
|
|
## OpenAPI Specification
|
|
|
|
A complete **OpenAPI 3.0** specification is available at [openapi.yaml](openapi.yaml). This machine-readable specification includes:
|
|
|
|
- All API endpoints with parameters and responses
|
|
- Request/response schemas and data models
|
|
- Examples for all operations
|
|
- Error response formats
|
|
|
|
### Using the OpenAPI Spec
|
|
|
|
**Interactive Documentation (Local):**
|
|
|
|
Once the server is running, visit:
|
|
```
|
|
http://localhost:3000/api-docs.html
|
|
```
|
|
|
|
This provides an interactive Swagger UI where you can:
|
|
- Browse all API endpoints
|
|
- View request/response schemas
|
|
- Try out API calls directly from the browser
|
|
- Download the OpenAPI specification
|
|
|
|
**Interactive Documentation with Swagger UI (Alternative):**
|
|
```bash
|
|
# Using Docker
|
|
docker run -p 8080:8080 -e SWAGGER_JSON=/openapi.yaml -v $(pwd)/openapi.yaml:/openapi.yaml swaggerapi/swagger-ui
|
|
|
|
# Or use online editor
|
|
# Visit: https://editor.swagger.io/
|
|
# Then paste the contents of openapi.yaml
|
|
```
|
|
|
|
**Generate Client Libraries:**
|
|
```bash
|
|
# Install OpenAPI Generator
|
|
npm install -g @openapitools/openapi-generator-cli
|
|
|
|
# Generate TypeScript client
|
|
openapi-generator-cli generate -i openapi.yaml -g typescript-fetch -o ./client/typescript
|
|
|
|
# Generate Python client
|
|
openapi-generator-cli generate -i openapi.yaml -g python -o ./client/python
|
|
|
|
# Generate Go client
|
|
openapi-generator-cli generate -i openapi.yaml -g go -o ./client/go
|
|
```
|
|
|
|
**VS Code Integration:**
|
|
Install the "OpenAPI (Swagger) Editor" extension to view and edit the spec with validation and IntelliSense.
|
|
|
|
---
|
|
|
|
## Base URL
|
|
|
|
```
|
|
http://localhost:3000
|
|
```
|
|
|
|
For production, replace with your deployed server URL.
|
|
|
|
---
|
|
|
|
## GTFS Static Data Endpoints
|
|
|
|
### Get Configuration
|
|
|
|
Retrieve configuration including default stop and route information.
|
|
|
|
**Endpoint:** `GET /api/config`
|
|
|
|
**Query Parameters:**
|
|
| Parameter | Type | Required | Description |
|
|
|-----------|------|----------|-------------|
|
|
| `stopId` | string | No | Specific stop ID to query (defaults to configured default) |
|
|
| `routeId` | string | No | Specific route ID to query (defaults to configured default) |
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"stop": {
|
|
"id": "1563",
|
|
"code": "363",
|
|
"name": "KARPOS II - STIV NAUMOV",
|
|
"lat": 41.97964,
|
|
"lon": 21.41283
|
|
},
|
|
"route": {
|
|
"id": "125",
|
|
"shortName": "7",
|
|
"longName": "Centar - GTC - Karpos 4 - Karposh 2"
|
|
},
|
|
"defaults": {
|
|
"stopId": "1563",
|
|
"routeId": "125"
|
|
}
|
|
}
|
|
```
|
|
|
|
**Example:**
|
|
```bash
|
|
curl "http://localhost:3000/api/config?stopId=1571&routeId=125"
|
|
```
|
|
|
|
---
|
|
|
|
### Get All Stops
|
|
|
|
Retrieve all GTFS stops in the system.
|
|
|
|
**Endpoint:** `GET /api/stops`
|
|
|
|
**Query Parameters:** None
|
|
|
|
**Response:**
|
|
```json
|
|
[
|
|
{
|
|
"id": "1563",
|
|
"code": "363",
|
|
"name": "KARPOS II - STIV NAUMOV",
|
|
"lat": 41.97964,
|
|
"lon": 21.41283
|
|
},
|
|
{
|
|
"id": "1571",
|
|
"code": "371",
|
|
"name": "AMERICAN COLLEGE - VASIL GLAVINOV",
|
|
"lat": 42.00437,
|
|
"lon": 21.39687
|
|
}
|
|
]
|
|
```
|
|
|
|
**Example:**
|
|
```bash
|
|
curl "http://localhost:3000/api/stops"
|
|
```
|
|
|
|
**Use Cases:**
|
|
- Populate stop selection dropdowns
|
|
- Build stop search functionality
|
|
- Generate maps with all stops
|
|
|
|
---
|
|
|
|
### Get All Routes
|
|
|
|
Retrieve all GTFS routes in the system.
|
|
|
|
**Endpoint:** `GET /api/routes`
|
|
|
|
**Query Parameters:** None
|
|
|
|
**Response:**
|
|
```json
|
|
[
|
|
{
|
|
"id": "125",
|
|
"shortName": "7",
|
|
"longName": "Centar - GTC - Karpos 4 - Karposh 2"
|
|
},
|
|
{
|
|
"id": "128",
|
|
"shortName": "2",
|
|
"longName": "Kisela Voda - Centar - 11 Oktomvri - Avtokomanda"
|
|
}
|
|
]
|
|
```
|
|
|
|
**Example:**
|
|
```bash
|
|
curl "http://localhost:3000/api/routes"
|
|
```
|
|
|
|
**Use Cases:**
|
|
- Display available routes
|
|
- Filter by route number
|
|
- Route selection interfaces
|
|
|
|
---
|
|
|
|
## Real-Time Data Endpoints
|
|
|
|
### Get Real-Time Arrivals
|
|
|
|
Get upcoming bus arrivals at a specific stop with real-time predictions.
|
|
|
|
**Endpoint:** `GET /api/arrivals`
|
|
|
|
**Query Parameters:**
|
|
| Parameter | Type | Required | Description |
|
|
|-----------|------|----------|-------------|
|
|
| `stopId` | string | No | Stop ID to query (defaults to configured default) |
|
|
| `routeId` | string | No | Filter by specific route ID (defaults to configured default) |
|
|
|
|
**Response:**
|
|
```json
|
|
[
|
|
{
|
|
"arrivalTime": "2026-02-07T14:35:00.000Z",
|
|
"scheduledTime": "2026-02-07T14:33:00.000Z",
|
|
"minutesUntil": 8,
|
|
"delaySeconds": 120,
|
|
"headsign": "Karpos 2",
|
|
"isRealtime": true,
|
|
"realtimeState": "UPDATED"
|
|
},
|
|
{
|
|
"arrivalTime": "2026-02-07T14:48:00.000Z",
|
|
"scheduledTime": "2026-02-07T14:48:00.000Z",
|
|
"minutesUntil": 21,
|
|
"delaySeconds": 0,
|
|
"headsign": "Centar",
|
|
"isRealtime": true,
|
|
"realtimeState": "SCHEDULED"
|
|
}
|
|
]
|
|
```
|
|
|
|
**Fields:**
|
|
- `arrivalTime`: Predicted arrival time (ISO 8601)
|
|
- `scheduledTime`: Originally scheduled time (ISO 8601)
|
|
- `minutesUntil`: Minutes until arrival (can be negative if bus passed)
|
|
- `delaySeconds`: Delay in seconds (positive = late, negative = early)
|
|
- `headsign`: Destination shown on bus
|
|
- `isRealtime`: Whether prediction is based on real-time data
|
|
- `realtimeState`: `SCHEDULED`, `UPDATED`, or `CANCELED`
|
|
|
|
**Example:**
|
|
```bash
|
|
curl "http://localhost:3000/api/arrivals?stopId=1563&routeId=125"
|
|
```
|
|
|
|
**Notes:**
|
|
- Returns arrivals from 2 minutes ago up to configured minutes ahead
|
|
- Results are sorted by arrival time
|
|
- Data is also logged to database for historical analysis
|
|
|
|
---
|
|
|
|
### Get Real-Time Vehicle Positions
|
|
|
|
Get current positions of all vehicles on a specific route.
|
|
|
|
**Endpoint:** `GET /api/vehicles`
|
|
|
|
**Query Parameters:**
|
|
| Parameter | Type | Required | Description |
|
|
|-----------|------|----------|-------------|
|
|
| `routeId` | string | No | Route ID to filter vehicles (defaults to configured default) |
|
|
|
|
**Response:**
|
|
```json
|
|
[
|
|
{
|
|
"id": 12345,
|
|
"vehicleId": "MK-SK-1234",
|
|
"label": "1234",
|
|
"lat": 41.9981,
|
|
"lon": 21.4254,
|
|
"bearing": 87.5,
|
|
"speed": 15.3,
|
|
"timestamp": "2026-02-07T14:27:15Z",
|
|
"tripId": "trip_789",
|
|
"currentStopSequence": 0,
|
|
"currentStatus": "IN_TRANSIT_TO"
|
|
}
|
|
]
|
|
```
|
|
|
|
**Fields:**
|
|
- `id`: Internal vehicle database ID
|
|
- `vehicleId`: Vehicle identification number (license plate)
|
|
- `label`: Bus inventory number (shown on bus)
|
|
- `lat`/`lon`: Current GPS coordinates
|
|
- `bearing`: Direction of travel (0-360 degrees, 0=North)
|
|
- `speed`: Current speed in km/h
|
|
- `timestamp`: Last position update time
|
|
- `tripId`: GTFS trip ID vehicle is currently serving
|
|
- `currentStatus`: `IN_TRANSIT_TO`, `STOPPED_AT`, or `UNKNOWN`
|
|
|
|
**Example:**
|
|
```bash
|
|
curl "http://localhost:3000/api/vehicles?routeId=125"
|
|
```
|
|
|
|
**Notes:**
|
|
- Combines GTFS-RT trip updates with JSON vehicle API
|
|
- Vehicle positions are logged to database
|
|
- Updates typically every 10-30 seconds from source
|
|
|
|
---
|
|
|
|
## Historical Data Endpoints
|
|
|
|
### Get Database Statistics
|
|
|
|
Get overview statistics about stored historical data.
|
|
|
|
**Endpoint:** `GET /api/stats/db`
|
|
|
|
**Query Parameters:** None
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"vehiclePositions": {
|
|
"totalRecords": 1523847,
|
|
"oldestRecord": "2026-01-15T08:00:00.000Z",
|
|
"newestRecord": "2026-02-07T14:27:30.000Z",
|
|
"dataRetentionDays": 90
|
|
},
|
|
"arrivalRecords": {
|
|
"totalRecords": 456231,
|
|
"oldestRecord": "2026-01-15T08:00:00.000Z",
|
|
"newestRecord": "2026-02-07T14:27:30.000Z",
|
|
"dataRetentionDays": 90
|
|
},
|
|
"databaseSize": "2.3 GB",
|
|
"status": "healthy"
|
|
}
|
|
```
|
|
|
|
**Example:**
|
|
```bash
|
|
curl "http://localhost:3000/api/stats/db"
|
|
```
|
|
|
|
---
|
|
|
|
### Get Vehicle Position History
|
|
|
|
Retrieve historical GPS positions for a specific vehicle.
|
|
|
|
**Endpoint:** `GET /api/history/vehicle/:vehicleId`
|
|
|
|
**Path Parameters:**
|
|
| Parameter | Type | Required | Description |
|
|
|-----------|------|----------|-------------|
|
|
| `vehicleId` | string | Yes | Vehicle identification number or label |
|
|
|
|
**Query Parameters:**
|
|
| Parameter | Type | Required | Default | Description |
|
|
|-----------|------|----------|---------|-------------|
|
|
| `hours` | integer | No | 24 | Number of hours to look back |
|
|
|
|
**Response:**
|
|
```json
|
|
[
|
|
{
|
|
"time": "2026-02-07T10:00:00.000Z",
|
|
"vehicleId": "MK-SK-1234",
|
|
"routeId": "125",
|
|
"tripId": "trip_789",
|
|
"latitude": 41.9981,
|
|
"longitude": 21.4254,
|
|
"speed": 15.3,
|
|
"bearing": 87.5,
|
|
"currentStatus": "IN_TRANSIT_TO"
|
|
}
|
|
]
|
|
```
|
|
|
|
**Example:**
|
|
```bash
|
|
curl "http://localhost:3000/api/history/vehicle/1234?hours=12"
|
|
```
|
|
|
|
**Use Cases:**
|
|
- Visualize vehicle path on map
|
|
- Analyze driving patterns
|
|
- Calculate actual travel times
|
|
|
|
---
|
|
|
|
### Get Route Vehicle History
|
|
|
|
Get historical positions of all vehicles that served a specific route.
|
|
|
|
**Endpoint:** `GET /api/history/route/:routeId/vehicles`
|
|
|
|
**Path Parameters:**
|
|
| Parameter | Type | Required | Description |
|
|
|-----------|------|----------|-------------|
|
|
| `routeId` | string | Yes | GTFS route ID |
|
|
|
|
**Query Parameters:**
|
|
| Parameter | Type | Required | Default | Description |
|
|
|-----------|------|----------|---------|-------------|
|
|
| `hours` | integer | No | 24 | Number of hours to look back |
|
|
|
|
**Response:**
|
|
```json
|
|
[
|
|
{
|
|
"time": "2026-02-07T10:00:00.000Z",
|
|
"vehicleId": "1234",
|
|
"routeId": "125",
|
|
"tripId": "trip_789",
|
|
"latitude": 41.9981,
|
|
"longitude": 21.4254,
|
|
"speed": 15.3,
|
|
"bearing": 87.5
|
|
}
|
|
]
|
|
```
|
|
|
|
**Example:**
|
|
```bash
|
|
curl "http://localhost:3000/api/history/route/125/vehicles?hours=6"
|
|
```
|
|
|
|
**Use Cases:**
|
|
- Service frequency analysis
|
|
- Route coverage visualization
|
|
- Fleet utilization tracking
|
|
|
|
---
|
|
|
|
### Get Stop Arrival History
|
|
|
|
Retrieve historical arrival records for a specific stop.
|
|
|
|
**Endpoint:** `GET /api/history/stop/:stopId/arrivals`
|
|
|
|
**Path Parameters:**
|
|
| Parameter | Type | Required | Description |
|
|
|-----------|------|----------|-------------|
|
|
| `stopId` | string | Yes | GTFS stop ID |
|
|
|
|
**Query Parameters:**
|
|
| Parameter | Type | Required | Default | Description |
|
|
|-----------|------|----------|---------|-------------|
|
|
| `routeId` | string | No | (all) | Filter by specific route |
|
|
| `hours` | integer | No | 24 | Number of hours to look back |
|
|
|
|
**Response:**
|
|
```json
|
|
[
|
|
{
|
|
"time": "2026-02-07T10:15:00.000Z",
|
|
"stopId": "1563",
|
|
"routeId": "125",
|
|
"scheduledTime": "2026-02-07T10:15:00.000Z",
|
|
"predictedTime": "2026-02-07T10:17:30.000Z",
|
|
"delaySeconds": 150,
|
|
"isRealtime": true,
|
|
"headsign": "Karpos 2"
|
|
}
|
|
]
|
|
```
|
|
|
|
**Example:**
|
|
```bash
|
|
curl "http://localhost:3000/api/history/stop/1563/arrivals?routeId=125&hours=48"
|
|
```
|
|
|
|
---
|
|
|
|
## Statistics & Analytics Endpoints
|
|
|
|
### Get Route Delay Statistics
|
|
|
|
Get delay statistics and performance metrics for a route.
|
|
|
|
**Endpoint:** `GET /api/stats/route/:routeId/delays`
|
|
|
|
**Path Parameters:**
|
|
| Parameter | Type | Required | Description |
|
|
|-----------|------|----------|-------------|
|
|
| `routeId` | string | Yes | GTFS route ID |
|
|
|
|
**Query Parameters:**
|
|
| Parameter | Type | Required | Default | Description |
|
|
|-----------|------|----------|---------|-------------|
|
|
| `hours` | integer | No | 24 | Time window for analysis |
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"routeId": "125",
|
|
"periodHours": 24,
|
|
"statistics": {
|
|
"totalArrivals": 287,
|
|
"avgDelaySeconds": 62,
|
|
"medianDelaySeconds": 45,
|
|
"minDelaySeconds": -30,
|
|
"maxDelaySeconds": 420,
|
|
"stdDeviation": 78.5,
|
|
"onTimePercentage": 68.3,
|
|
"earlyPercentage": 8.7,
|
|
"latePercentage": 23.0,
|
|
"veryLatePercentage": 4.2
|
|
},
|
|
"thresholds": {
|
|
"onTime": "±5 minutes",
|
|
"veryLate": ">10 minutes"
|
|
}
|
|
}
|
|
```
|
|
|
|
**Example:**
|
|
```bash
|
|
curl "http://localhost:3000/api/stats/route/125/delays?hours=72"
|
|
```
|
|
|
|
**Definitions:**
|
|
- **On-time**: Within ±5 minutes of schedule
|
|
- **Early**: More than 5 minutes early
|
|
- **Late**: 5-10 minutes late
|
|
- **Very Late**: More than 10 minutes late
|
|
|
|
---
|
|
|
|
### Get Stop Delay Statistics
|
|
|
|
Get delay statistics for a specific stop.
|
|
|
|
**Endpoint:** `GET /api/stats/stop/:stopId/delays`
|
|
|
|
**Path Parameters:**
|
|
| Parameter | Type | Required | Description |
|
|
|-----------|------|----------|-------------|
|
|
| `stopId` | string | Yes | GTFS stop ID |
|
|
|
|
**Query Parameters:**
|
|
| Parameter | Type | Required | Default | Description |
|
|
|-----------|------|----------|---------|-------------|
|
|
| `hours` | integer | No | 24 | Time window for analysis |
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"stopId": "1563",
|
|
"periodHours": 24,
|
|
"statistics": {
|
|
"totalArrivals": 145,
|
|
"avgDelaySeconds": 72,
|
|
"medianDelaySeconds": 60,
|
|
"onTimePercentage": 62.1,
|
|
"routeBreakdown": [
|
|
{
|
|
"routeId": "125",
|
|
"routeName": "7",
|
|
"arrivals": 89,
|
|
"avgDelaySeconds": 65
|
|
},
|
|
{
|
|
"routeId": "128",
|
|
"routeName": "2",
|
|
"arrivals": 56,
|
|
"avgDelaySeconds": 82
|
|
}
|
|
]
|
|
}
|
|
}
|
|
```
|
|
|
|
**Example:**
|
|
```bash
|
|
curl "http://localhost:3000/api/stats/stop/1563/delays?hours=48"
|
|
```
|
|
|
|
**Use Cases:**
|
|
- Compare reliability across stops
|
|
- Identify problematic locations
|
|
- Plan transfer reliability
|
|
|
|
---
|
|
|
|
### Get Route Hourly Pattern
|
|
|
|
Analyze delay patterns by hour of day for a route.
|
|
|
|
**Endpoint:** `GET /api/stats/route/:routeId/hourly`
|
|
|
|
**Path Parameters:**
|
|
| Parameter | Type | Required | Description |
|
|
|-----------|------|----------|-------------|
|
|
| `routeId` | string | Yes | GTFS route ID |
|
|
|
|
**Query Parameters:**
|
|
| Parameter | Type | Required | Default | Description |
|
|
|-----------|------|----------|---------|-------------|
|
|
| `days` | integer | No | 7 | Number of days to analyze |
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"routeId": "125",
|
|
"periodDays": 7,
|
|
"hourlyPattern": [
|
|
{
|
|
"hour": 6,
|
|
"arrivals": 42,
|
|
"avgDelaySeconds": 15,
|
|
"onTimePercentage": 85.7
|
|
},
|
|
{
|
|
"hour": 7,
|
|
"arrivals": 89,
|
|
"avgDelaySeconds": 45,
|
|
"onTimePercentage": 71.9
|
|
},
|
|
{
|
|
"hour": 8,
|
|
"arrivals": 124,
|
|
"avgDelaySeconds": 125,
|
|
"onTimePercentage": 52.4
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
**Example:**
|
|
```bash
|
|
curl "http://localhost:3000/api/stats/route/125/hourly?days=14"
|
|
```
|
|
|
|
**Use Cases:**
|
|
- Identify rush hour patterns
|
|
- Compare morning vs evening reliability
|
|
- Optimize schedules based on actual performance
|
|
|
|
---
|
|
|
|
## Data Models
|
|
|
|
### GTFS Stop
|
|
```typescript
|
|
interface GtfsStop {
|
|
stop_id: string; // Unique stop identifier
|
|
stop_code: string; // Public-facing stop code
|
|
stop_name: string; // Stop name
|
|
stop_lat: number; // Latitude (WGS84)
|
|
stop_lon: number; // Longitude (WGS84)
|
|
}
|
|
```
|
|
|
|
### GTFS Route
|
|
```typescript
|
|
interface GtfsRoute {
|
|
route_id: string; // Unique route identifier
|
|
route_short_name: string; // Public route number (e.g., "7")
|
|
route_long_name: string; // Full route name
|
|
route_type?: string; // GTFS route type (0=Tram, 3=Bus, etc.)
|
|
}
|
|
```
|
|
|
|
### Vehicle Position
|
|
```typescript
|
|
interface VehiclePosition {
|
|
time: Date; // Timestamp (ISO 8601)
|
|
vehicle_id: string; // Vehicle identifier
|
|
route_id: string; // Route being served
|
|
trip_id?: string; // Current trip ID
|
|
latitude: number; // GPS latitude
|
|
longitude: number; // GPS longitude
|
|
speed?: number; // Speed in km/h
|
|
bearing?: number; // Direction (0-360°)
|
|
current_status: string; // IN_TRANSIT_TO, STOPPED_AT, UNKNOWN
|
|
}
|
|
```
|
|
|
|
### Arrival Record
|
|
```typescript
|
|
interface ArrivalRecord {
|
|
time: Date; // Record timestamp
|
|
stop_id: string; // Stop ID
|
|
route_id: string; // Route ID
|
|
scheduled_time: Date; // Scheduled arrival time
|
|
predicted_time?: Date; // Real-time predicted time
|
|
actual_time?: Date; // Actual arrival time (if observed)
|
|
delay_seconds: number; // Delay in seconds
|
|
is_realtime: boolean; // Based on real-time data
|
|
headsign?: string; // Trip headsign
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Error Handling
|
|
|
|
All endpoints return standard HTTP status codes:
|
|
|
|
| Status Code | Description |
|
|
|-------------|-------------|
|
|
| `200` | Success |
|
|
| `404` | Resource not found (e.g., invalid stop/route ID) |
|
|
| `500` | Server error |
|
|
|
|
**Error Response Format:**
|
|
```json
|
|
{
|
|
"error": "Description of the error",
|
|
"details": "Additional error details (when available)"
|
|
}
|
|
```
|
|
|
|
**Example Error:**
|
|
```bash
|
|
curl "http://localhost:3000/api/config?stopId=invalid"
|
|
```
|
|
|
|
Response (404):
|
|
```json
|
|
{
|
|
"error": "Stop invalid not found"
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Rate Limiting
|
|
|
|
Currently, there is no rate limiting implemented. For production deployments, consider:
|
|
|
|
- Implementing per-IP rate limits
|
|
- Using caching for frequently accessed endpoints
|
|
- Load balancing for high-traffic scenarios
|
|
|
|
**Recommended Polling Intervals:**
|
|
- Real-time arrivals: 10-30 seconds
|
|
- Vehicle positions: 10-30 seconds
|
|
- Historical data: As needed (not time-sensitive)
|
|
- Statistics: 5-60 minutes (depending on use case)
|
|
|
|
---
|
|
|
|
## GTFS Data Update
|
|
|
|
The GTFS static data (stops, routes, schedules) is loaded from the `gtfs/` directory on server startup.
|
|
|
|
**To update GTFS data:**
|
|
|
|
```bash
|
|
bun run setup-gtfs.ts
|
|
```
|
|
|
|
This downloads the latest GTFS feed and extracts it. Restart the server to load the new data.
|
|
|
|
---
|
|
|
|
## TimescaleDB Setup
|
|
|
|
Historical data and analytics require TimescaleDB. See the [README.md](README.md) for setup instructions.
|
|
|
|
**Quick start:**
|
|
```bash
|
|
cd infrastructure
|
|
docker compose up -d
|
|
```
|
|
|
|
The database automatically:
|
|
- Creates hypertables for time-series data
|
|
- Sets up 90-day data retention
|
|
- Builds continuous aggregates for hourly metrics
|
|
- Maintains indexes for fast queries
|
|
|
|
---
|
|
|
|
## Example Use Cases
|
|
|
|
### Building a Real-Time Tracker
|
|
|
|
```javascript
|
|
// 1. Get all stops
|
|
const stops = await fetch('/api/stops').then(r => r.json());
|
|
|
|
// 2. Get all routes
|
|
const routes = await fetch('/api/routes').then(r => r.json());
|
|
|
|
// 3. Poll for arrivals every 15 seconds
|
|
setInterval(async () => {
|
|
const arrivals = await fetch('/api/arrivals?stopId=1563&routeId=125')
|
|
.then(r => r.json());
|
|
updateUI(arrivals);
|
|
}, 15000);
|
|
|
|
// 4. Poll for vehicle positions
|
|
setInterval(async () => {
|
|
const vehicles = await fetch('/api/vehicles?routeId=125')
|
|
.then(r => r.json());
|
|
updateMap(vehicles);
|
|
}, 15000);
|
|
```
|
|
|
|
### Building Analytics Dashboard
|
|
|
|
```javascript
|
|
// Get delay statistics for route
|
|
const stats = await fetch('/api/stats/route/125/delays?hours=168')
|
|
.then(r => r.json());
|
|
|
|
// Get hourly patterns
|
|
const pattern = await fetch('/api/stats/route/125/hourly?days=30')
|
|
.then(r => r.json());
|
|
|
|
// Get stop performance comparison
|
|
const stopStats = await fetch('/api/stats/stop/1563/delays?hours=168')
|
|
.then(r => r.json());
|
|
|
|
// Display charts with the data
|
|
renderDelayChart(stats);
|
|
renderHourlyPattern(pattern);
|
|
renderStopComparison(stopStats);
|
|
```
|
|
|
|
---
|
|
|
|
## Additional Resources
|
|
|
|
- **OpenAPI Specification**: [openapi.yaml](openapi.yaml) - Machine-readable API spec
|
|
- **Upstream API Documentation**: [UPSTREAM-API-DOCUMENTATION.md](UPSTREAM-API-DOCUMENTATION.md) - ModeShift GTFS API docs
|
|
- **Swagger UI Demo**: https://editor.swagger.io/ (paste openapi.yaml content)
|
|
- **GTFS Specification**: https://gtfs.org/
|
|
- **GTFS-RT Reference**: https://gtfs.org/realtime/
|
|
- **TimescaleDB Documentation**: https://docs.timescale.com/
|
|
- **Project README**: [README.md](README.md)
|
|
|
|
---
|
|
|
|
## Support
|
|
|
|
For issues or questions:
|
|
1. Check the [README.md](README.md) for setup instructions
|
|
2. Review this documentation
|
|
3. Check the source code in [server.ts](server.ts) and [lib/gtfs.ts](lib/gtfs.ts)
|
|
|
|
---
|
|
|
|
**Last Updated:** February 7, 2026
|
|
**API Version:** 1.0.0
|