Swiftpack.co - Package - emma-k-alexandra/WMATA.swift

WMATA.swift

WMATA.swift is a lightweight Swift interface to the Washington Metropolitan Area Transit Authority API.

Note on WMATA.swift & coming package

In the future, WMATA.swift will be splitting into a few libraries. Currently, WMATA.swift provides a lot of high level functionality on top of the response from the WMATA. In order to better maintain this functionality and support it fully, I am planning on keeping WMATA.swift as a high level, WMATA focused framework, and introducing a new package. This new package will handle basic API interactions and will be a better choice for those looking for lower level interactions with the API. There won't be any feature regression on WMATA.swift, simply making the package simpler to maintain for me.

Note on GTFS

I released a GTFS and GTFS-RT package for Swift and soon this package will be using that package for interaction with GTFS-RT feeds.

Contents

Requirements

  • Swift 5.1+

Installation

Swift Package Manager

dependencies: [
    .package(url: "https://github.com/emma-k-alexandra/WMATA.swift.git", from: "8.1.0")
]

Usage

Getting Started

import WMATA

MetroRail(key: apiKey).nextTrains(at: .A01) { result in
    switch result {
    case .success(let predictions):
        print(predictions)

    case .failure(let error):
        print(error)

    }

}

Design

WMATA.swift breaks the WMATA API into MetroRail and MetroBus via the MetroRail and MetroBus.

Using MetroRail

lines

WMATA Documentation
Returns basic information on all MetroRail lines.

 MetroRail(key: apiKey).lines { result in
    switch result {
    case .success(let lines):
        print(lines)

    case .failure(let error):
        print(error)

    }

}

entrances

WMATA Documentation
Station entrances within a latlong pair and radius (in meters). Omit all parameters to receive all entrances.

MetroRail(key: apiKey).entrances(at: RadiusAtCoordinates(radius: 1000, coordinates: Coordinates(latitude: 38.8817596, longitude: -77.0166426))) { result in
    switch result {
    case .success(let entrances):
        print(entrances)

    case .failure(let error):
        print(error)

    }

}

stations

WMATA Documentation
Stations along a Line (optional)

MetroRail(key: apiKey).stations(for: .BL) { result in
    switch result {
    case .success(let stations):
        print(stations)

    case .failure(let error):
        print(error)

    }

}

station

WMATA Documentation
Distance, fare information and estimated travel time between two stations. Omit both station codes for all possible trips.

MetroRail(key: apiKey).station(.A01, to: .A02) { result in 
    switch result {
    case .success(let travelInfo):
        print(travelInfo)

    case .failure(let error):
        print(error)

    }

}

positions

WMATA Documentation
Uniquely identifiable trains in service and what track circuits they currently occupy

MetroRail(key: apiKey).positions { result in
    switch result {
    case .success(let positions):
        print(positions)

    case .failure(let error):
        print(error)

    }

}

routes

WMATA Documentation
Ordered list of track circuits, arranged by line and track number

MetroRail(key: apiKey).routes { result in 
    switch result {
    case .success(let routes):
        print(routes)

    case .failure(let error):
        print(error)

    }

}

circuits

WMATA Documentation
List of all track circuits - also see TrainPositionsFAQ

MetroRail(key: apiKey).circuits { result in 
    switch result {
    case .success(let circuits):
        print(circuits)

    case .failure(let error):
        print(error)

    }

}

elevatorAndEscalatorIncidents

WMATA Documentation
Reported elevator and escalator incidents

MetroRail(key: apiKey).elevatorAndEscalatorIncidents(at: .A01) { result in
    switch result {
    case .success(let incidents):
        print(incidents)

    case .failure(let error):
        print(error)

    }

}

incidents

WMATA Documentation
Reported MetroRail incidents at a particular station (optional)

MetroRail(key: apiKey).incidents(at: .A01) { result in
    switch result {
    case .success(let incidents):
        print(incidents)

    case .failure(let error):
        print(error)
    }

}

stations

WMATA Documentation
Stations along a Line

 MetroRail(key: apiKey).stations(for: .BL) { result in 
    switch result {
    case .success(let stations):
        print(stations)

    case .failure(let error):
        print(error)

    }

}

nextTrains

WMATA Documentation
Next train arrivals for this station.

MetroRail(key: apiKey).nextTrains(at: .A01) { result in
    switch result {
    case .success(let predictions):
        print(predictions)

    case .failure(let error):
        print(error)

    }

}

information

WMATA Documentation
Location and address information for this station.

MetroRail(key: apiKey).information(for: .A01) { result in
    switch result {
    case .success(let information):
        print(information)

    case .failure(let error):
        print(error)

    }

}

parkingInformation

WMATA Documentation
Parking information for this station.

MetroRail(key: apiKey).parkingInformation(for: .A01) { result in
    switch result {
    case .success(let parkingInfo):
        print(parkingInfo)

    case .failure(let error):
        print(error)

    }

}

path

WMATA Documentation
Returns a set of ordered stations and distances between stations on the same line

MetroRail(key: apiKey).path(from: .A01 to: .A02) { result in
    switch result {
    case .success(let path):
        print(path)

    case .failure(let error):
        print(error)

    }

}

timings

WMATA Documentation
Opening times and scheduled first and last trains for this station

MetroRail(key: apiKey).timings(for: .A01) { result in
    switch result {
    case .success(let timings):
        print(timings)

    case .failure(let error):
        print(error)

    }

}

Using Station

The Station enum provides a lot of additional information for stations that you can use without having to make network requests.

name

let name = Station.A01.name // "Metro Center"

name provides an easy way to get a human readable and presentable string of the station's name.

lines

let lines = Station.A01.lines // [.BL, .OR, .SV, .RD]

lines provides the Lines a station is on without making a network request.

openingTime(:)

let openingTime = Station.A01.openingTime() // ("2020-01-12 08:14:00 +0000")

openingTime provides the opening time of a station without making a network request. Note: This is only accurate generally, not on event days. For guaranteed accurate information use the timings method on a Station or MetroRail.

Using MetroBus

positions

WMATA Documentation
Bus positions along a route (optional), at a latlong and within a radius (in meters)

MetroBus(key: apiKey).positions(on: ._10A, at: RadiusAtCoordinates(radius: 1000, coordinates: Coordinates(latitude: 38.8817596, longitude: -77.0166426))) { result in
    switch result {
    case .success(let positions):
        print(positions)

    case .failure(let error):
        print(error)

    }

}

routes

WMATA Documentation
All bus routes

MetroBus(key: apiKey).routes { result in
    switch result {
    case .success(let routes):
        print(routes)

    case .failure(let error):
        print(error)

    }

}

searchStops

WMATA Documentation
Stops near a given latlong and within a given radius. Omit all parameters to receive all stops.

MetroBus(key: apiKey).searchStops(at: RadiusAtCoordinates(radius: 1000, coordinates: Coordinates(latitude: 38.8817596, longitude: -77.0166426))) { result in
    switch result {
    case .success(let stops):
        print(stops)

    case .failure(let error):
        print(error)

    }

}

incidents

WMATA Documentation
MetroBus incidents along an optional route.

MetroBus(key: apiKey).incidents(on: ._10A) { result in
    switch result {
    case .success(let incidents):
        print(incidents)

    case .failure(let error):
        print(error)

    }

}

positions

WMATA Documentation
Bus positions along this route, within an optional latlong and radius (in meters).

MetroBus(key: apiKey).positions(at: ._10A, at: RadiusAtCoordinates(radius: 1000, coordinates: Coordinates(latitude: 38.8817596, longitude: -77.0166426))) { result in
    switch result {
    case .success(let positions):
        print(positions)

    case .failure(let error):
        print(error)

    }

}

pathDetails

WMATA Documentation
Ordered latlong points along this Route for a given date. Omit for today.

MetroBus(key: apiKey).pathDetails(for: ._10A) { result in
    switch result {
    case .success(let path):
        print(path)

    case .failure(let error):
        print(error)

    }

}

schedule

WMATA Documentation
Scheduled stops for this Route

MetroBus(key: apiKey).schedule(for: ._10A) { result in
    switch result {
    case .success(let schedule):
        print(schedule)

    case .failure(let error):
        print(error)

    }

}

nextBuses

WMATA Documentation
Next bus arrivals at this Stop

MetroBus(key: apiKey).nextBuses(for: Stop(id: "1001195")) { result in
    switch result {
    case .success(let predictions):
        print(predictions)

    case .failure(let error):
        print(error)

    }

}

schedule

WMATA Documentation
Buses scheduled to arrival at this Stop at a given date. Omit for today.

MetroBus(key: apiKey).schedule(for: Stop(id: "1001195")) { result in
    switch result {
    case .success(let schedule):
        print(schedule)

    case .failure(let error):
        print(error)

    }

}

Background Requests & WMATADelegate

Background requests can be made using aWMATADelegate on MetroRail or MetroBus. First, create a class implementing WMATADelegate:

import WMATA

class Delegate: WMATADelegate {

}

Then implement the received method for whichever method you plan on calling on the MetroBus or MetroRail object this delegate belongs to. For example, if yoy plan on calling lines on MetroRail, implement received(linesResponse: on your delegate.

class Delegate: WMATADelegate {
    func received(linesResponse result: Result<LinesResponse, WMATAError>) {
        switch result {
        case .success(let lines):
            print(lines)

        case .failure(let error):
            print(error)

        }

    }

}

Finally, create a MetroBus or MetroRail instance with an instance of your delegate and make requests!

let delegate = Delegate()
let metroRail = MetroRail(key: apiKey, delegate: delegate)

metroRail.lines()

Dependencies

Testing

Currently, afaik Xcode doesn't provide a way to run tests in succession rather than in parallel. So, as of v5, tests musts be run manually & individually. No fun, I know. Working on a solution for future versions.

Contact

Feel free to email questions and comments to emma@emma.sh

Contributing

Todo:

  • ☐ Last Train times (API doesn't provide full information here)
  • ☐ Documentation of response structs a la wmata
  • ☐ Figure out README structure
  • ☐ Provide more documentation for methods on Station, Line, Route and Stop
  • ☐ Figure out how to serialize tests
  • ☐ Automated builds
  • ☐ Possible support for CocoaPods/Carthage?

License

WMATA.swift is released under the MIT license. See LICENSE for details.

Github

link
Stars: 4

Dependencies

Used By

Total: 0

Releases

Use GTFS package - 2020-02-08 16:26:32

GTFS-RT Feeds Support - 2020-01-26 21:14:36

Documentation - 2020-01-21 20:15:21

Station Opening Times w/o network calls - 2020-01-12 16:55:01

Compatibility Improvements - 2020-01-06 22:15:58

Bug Fixes - 2019-12-10 17:44:29

Make WMATAURLSessionDataDelegate public - 2019-12-10 17:38:06

For background sessions

Revert v6.0.1 - 2019-11-30 16:39:15

All methods on WMATADelegate are now optional - 2019-11-30 16:00:57

Allow background requests via WMATADelegate - 2019-11-29 00:34:04

MetroRail and MetroBus have been imbued with the ability to make background requests via WMATADelegate

Allow nextTrains queries for multiple stations at once - 2019-11-10 20:35:55

Get Lines that each Station is on - 2019-11-10 19:51:45

New name variable for Station and Line objects - 2019-11-10 13:38:39

Bug Fixes - 2019-11-08 01:52:25

Handle empty quoted stations and lines

Bug Fixes - 2019-11-08 01:28:52

Make some initializers public

Everything is Codable! - 2019-11-08 01:15:52

Make responses from the WMATA API Codable, not just Decodable

Deserialize Everything! - 2019-11-01 21:21:25

Stop, Route, Station and Line are now Codable and are deserialized from codes in responses. Add super simple WMATADate struct for calling MetroBus APIs with Dates Deserialize dates into Dates when appropriate Lots of bug fixes

Empower Station, Line, Route and Stop - 2019-10-11 18:02:25

Giving these types more superpowers to enable quicker access to data.

Simplicity is Key - 2019-10-07 01:06:45

Use Rail and Bus clients rather than Rail, Line, Station & Bus, Route, Stop. That was an awful idea wasn't it?

Use Result - 2019-10-06 21:47:18

When fetching from WMATA API, Result<T, E> is now used rather than whatever we had before.