Skip to content

RISCfuture/SwiftNASR

Repository files navigation

SwiftNASR: FAA aeronautical data library for Swift

SwiftNASR is a Swift library that downloads and parses National Airspace System Resource (NASR) distributions from the FAA's Facility Aerodrome Data Distribution System (FADDS). These distributions contain comprehensive aeronautical data for the United States, covering the airports, navaids, airspace, routes, ATC facilities, and more, that make up the National Airspace System.

SwiftNASR can download NASR distributions directly from the FAA website, or load prior-downloaded distributions from disk or memory. It parses this data into classes and structs that are easy to use and take advantage of common Swift paradigms. These classes are all Codable and can be exported to file, and imported using the Coder of your choice.

The design goal of SwiftNASR is domain-restricted data as much as possible. Wherever possible, SwiftNASR avoids representing data as open-ended types such as strings. Instead, enums and other types with small domains are preferred. This obviously has maintainability implications -- namely, as the upstream data changes, SwiftNASR is more likely to generate parsing errors, and require more developer work to maintain future compatibility -- but it also results in a library that's more in harmony with the design goals of the Swift language itself (type safety, compile-time checks, etc.).

What records can I parse with this?

SwiftNASR is a work in progress. Here's what's currently ready:

  • Airports
  • ARTCCs
  • FSSes
  • Navaids
  • ARTCC boundary segments
  • Airways
  • AWOSes
  • Coded departure routes
  • FSS comm facilities
    • The FSS data includes comm facilities, but there is also a separate file for FSS comm facilities; haven't checked yet if they contain the same data
  • High altitude route fixes
  • Published holds
  • ILSes
  • Location identifiers
  • Miscellaneous activity areas
  • Military training routes
  • Enroute fixes
  • Preferred routes
  • Parachute jump activity areas
  • DPs and STARs
  • ATCTs and TRACONs
  • Weather reporting locations

Installation

SwiftNASR is a Swift Package Manager project. To use SwiftNASR, simply add this project to your Package.swift file. Example:

// [...]
dependencies: [
    .package(url: "https://github.com/RISCfuture/SwiftNASR.git", .branch("master")),
]
// [...]

Usage

The NASR class is used to load NASR distributions. If you have not already downloaded a NASR distribution, you can do so using the fromInternetToFile method, which will download the distribution to a file, so you can avoid having to re-download it later:

import SwiftNASR

let workingURL = URL.currentDirectory()
let distributionURL = workingURL.appendingPathComponent("distribution.zip")
let distribution = NASR.fromInternetToFile(distributionURL)!

If you have already downloaded the distribution, you can load it using fromLocalArchive:

let distribution = NASR.fromLocalArchive(distributionURL)

Once you have your distribution, use the NASR class to asynchronously load the data and parse it:

try await distribution.load()
try await distribution.parse(.airports, errorHandler: { error in
    // [...]
})

Note that larger datasets, such as airports, can take several moments to parse. It's recommended to serialize this data once parsed using an encoder (see below).

Once you've completed parsing the data you're interested in, you can access it from NASR.data:

let sanCarlos = distribution.data.airports!.first { $0.LID == "SQL" }!
print(sanCarlos.runways[0].length)

data is an object of type NASRData. Its fields, such as airports will only not be nil once parse has been called for that data type (as in the example above).

To avoid parsing a large dataset each time your application loads, I recommend encoding the NASRData object. Choose the encoder you wish to use; for example, JSONEncoder uses a straightforward and portable format. This class also provides JSONZipEncoder to cut down on space when needed.

You can encode the whole object, containing all the data you've loaded:

let encoder = JSONZipEncoder()
let data = try encoder.encode(NASRDataCodable(data: distribution.data))
try data.write(to: workingURL.appendingPathComponent("distribution.json.zip"))

or you can encode just the data you need; for example, filtering in only the airports that you care about, to improve space and time efficiency when loading and working with the data:

let validAirports = distribution.data.airports!.filter { airport in
    return airport.publicUse &&
        airport.runways.filter { $0.isPaved && $0.length > 3000 }.count > 0
}
let data = try encoder.encode(validAirports)

For more information on the data you have available to work with, see the class documentation for each of the record classes, such as Airport.

Customizing loader behavior

If you need to customize loader behavior (e.g., using your own URLSessionConfiguration), instantiate a loader yourself and pass it to the NASR initializer. The different NASR class constructors are simply syntactic sugar for different loader implementations. See the documentation for each Loader implementation for more information.

Documentation

Online API documentation and tutorials are available at https://riscfuture.github.io/SwiftNASR/documentation/swiftnasr/

DocC documentation is available, including tutorials and API documentation. For Xcode documentation, you can run

swift package generate-documentation --target SwiftNASR

to generate a docarchive at .build/plugins/Swift-DocC/outputs/SwiftNASR.doccarchive. You can open this docarchive file in Xcode for browseable API documentation. Or, within Xcode, open the SwiftNASR package in Xcode and choose Build Documentation from the Product menu.

Tests

Testing is done using Nimble and Quick. Simply run the SwiftNASRTests target to run tests.

A SwiftNASR_E2E target is also available to do an end-to-end test. This will download a distribution (or load one from file, if already downloaded) and load all data from the distribution, then write it out to a .json.zip file. The whole process takes some time, but if it completes successfully without error, that's a pretty good sign the code hasn't broken.