├── .github └── workflows │ └── swift.yml ├── .gitignore ├── .swiftpm └── xcode │ ├── package.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist │ └── xcshareddata │ └── xcschemes │ └── ErgastAPI.xcscheme ├── LICENSE ├── Package.swift ├── README.md ├── Sources └── Formula1API │ ├── APIError.swift │ ├── Formula1API.swift │ ├── Helpers │ ├── Endpoint.swift │ ├── Extensions │ │ ├── Decodable+Extension.swift │ │ └── URLSession+Extension.swift │ ├── Path.swift │ └── Season.swift │ └── Models │ ├── Circuits.swift │ ├── Constructors.swift │ ├── DriverStandings.swift │ ├── Drivers.swift │ ├── FinishingStatus.swift │ ├── Laps.swift │ ├── PitStops.swift │ ├── QualifyingResults.swift │ ├── RaceResults.swift │ ├── RaceSchedule.swift │ └── Seasons.swift └── Tests ├── ErgastAPITests ├── EndpointTests.swift ├── ErgastAPITests.swift └── XCTestManifests.swift └── LinuxMain.swift /.github/workflows/swift.yml: -------------------------------------------------------------------------------- 1 | name: Swift 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | build: 11 | 12 | runs-on: macos-latest 13 | 14 | steps: 15 | - uses: actions/checkout@v2 16 | - name: Build 17 | run: swift build -v 18 | - name: Run tests 19 | run: swift test -v 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | /.build 3 | /Packages 4 | /*.xcodeproj 5 | xcuserdata/ 6 | -------------------------------------------------------------------------------- /.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.swiftpm/xcode/package.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.swiftpm/xcode/xcshareddata/xcschemes/ErgastAPI.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 38 | 39 | 44 | 45 | 47 | 53 | 54 | 55 | 56 | 57 | 67 | 68 | 74 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Giovanni Noa 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.2 2 | // The swift-tools-version declares the minimum version of Swift required to build this package. 3 | 4 | import PackageDescription 5 | 6 | let package = Package( 7 | name: "Formula1API", 8 | platforms: [ 9 | .macOS(.v10_15), 10 | .watchOS(.v6), 11 | .iOS(.v13) 12 | ], 13 | products: [ 14 | // Products define the executables and libraries produced by a package, and make them visible to other packages. 15 | .library( 16 | name: "Formula1API", 17 | targets: ["Formula1API"]), 18 | ], 19 | dependencies: [ 20 | // Dependencies declare other packages that this package depends on. 21 | // .package(url: /* package url */, from: "1.0.0"), 22 | ], 23 | targets: [ 24 | // Targets are the basic building blocks of a package. A target can define a module or a test suite. 25 | // Targets can depend on other targets in this package, and on products in packages which this package depends on. 26 | .target( 27 | name: "Formula1API", 28 | dependencies: []), 29 | ] 30 | ) 31 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # Formula 1 API 3 | 4 | > This Swift library provides endpoint access to Formula 1 data provided by the [Ergast API](https://ergast.com/mrd/). By using this library, you won't have to build the interactive layer yourself, and can just start consuming the data. 5 | 6 | ## Installing / Getting started 7 | 8 | > Formula 1 API supports Swift Package Manager. To use SwiftPM, you should use the most recent version of Xcode to add this project. 9 | 10 | Click `File` -> `Swift Packages` -> `Add Package Dependency`, enter Formula1API repo's [URL](https://github.com/gionoa/Formula1API.git). Or you can login Xcode with your GitHub account and just type Formula1API to search. 11 | 12 | ## Features 13 | 14 | Formula1API provides functions that allow you to access endpoints for data. 15 | 16 | Currently, you can fetch: 17 | * `Circuits (all, specified season)` 18 | * `Seasons` 19 | * `Constructors (all, specified season)` 20 | * `Race Schedule (specified season)` 21 | * `Race Results (specified season)` 22 | * `Qualifying Results (specified season)`, 23 | * `Pit Stops (specified season)`, 24 | * `Laps(specified season)` 25 | 26 | *More endpoints will be accessible as development progresses.* 27 | 28 | ## Usage 29 | 30 | Usage of this library within your app or package is simple. 31 | 32 | Access endpoints via the `Formula1API` object. 33 | 34 | Return closure example: 35 | ```swift 36 | Formula1API.constructors(for: .year(2022)) { result in 37 | switch result { 38 | case .success(let constructors): 39 | print(constructors) 40 | case .failure(let error): 41 | print(error) 42 | } 43 | } 44 | 45 | ``` 46 | 47 | Async-await example: 48 | ```swift 49 | do { 50 | let constructors = try await Formula1API.constructors(for: .year(2022)) 51 | } catch error { 52 | print(error) 53 | } 54 | ``` 55 | 56 | ## Licensing 57 | 58 | The code in this project is licensed under MIT license. 59 | -------------------------------------------------------------------------------- /Sources/Formula1API/APIError.swift: -------------------------------------------------------------------------------- 1 | // 2 | // APIError.swift 3 | // 4 | // 5 | // Created by Giovanni Noa on 4/28/20. 6 | // 7 | 8 | import Foundation 9 | 10 | // MARK: - Publisher Error 11 | /// Enum for passing errors during network interactions. 12 | public enum APIError: Error { 13 | /// A URL error. 14 | case url(String) 15 | 16 | /// A network error. 17 | case network(String) 18 | 19 | /// A parsing/decoding error. 20 | case parsing(String) 21 | 22 | /// An error for when error is nil, and data failed to be fetched, 23 | case data(String) 24 | } 25 | -------------------------------------------------------------------------------- /Sources/Formula1API/Formula1API.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Formula1API.swift 3 | // 4 | // 5 | // Created by Giovanni Noa on 4/28/20. 6 | // 7 | 8 | import Foundation 9 | 10 | /// Public interface of functions for fetching Formula 1 data from the Ergast REST API. 11 | public enum Formula1API { 12 | /// Fetches Formula 1 Circuits for a given year. 13 | /// - Parameters: 14 | /// - season: Season enum case, specified by an Int, which indicates to fetch data for a given year (1950-2020). 15 | /// - limit: Property to specify number of items to return per request. 16 | /// - offset: Property to indicate starting point of elements from API request. 17 | /// - completion: Asynchronous closure to inject functionality once the network interaction completes. 18 | public static func circuits(for season: Season, 19 | limit: String? = nil, 20 | offset: String? = nil, 21 | completion: @escaping (Result) -> Void) { 22 | 23 | URLSession.shared.fetch(.circuits, 24 | for: season, 25 | limit: limit, 26 | offset: offset) { result in 27 | completion(result) 28 | } 29 | } 30 | 31 | /// Asynchronously fetches Formula 1 Circuits for a given year. 32 | /// - Parameters: 33 | /// - season: Season enum case, specified by an Int, which indicates to fetch data for a given year (1950-2020). 34 | /// - limit: Property to specify number of items to return per request. 35 | /// - offset: Property to indicate starting point of elements from API request. 36 | /// - Returns: A model representing Circuits 37 | public static func circuits(for season: Season, limit: String? = nil, offset: String? = nil) async throws -> Circuits { 38 | try await URLSession.shared.fetch(.circuits, for: season, limit: limit, offset: offset) 39 | } 40 | 41 | /// Fetches Formula 1 Circuits for all seasons throughout history. 42 | /// - Parameters: 43 | /// - limit: Optional property to specify number of items to return per request. 44 | /// - offset: Optional property to indicate starting point of elements from API request. 45 | /// - completion: Asynchronous closure to inject functionality once the network interaction completes. 46 | public static func allCircuits(limit: String? = nil, 47 | offset: String? = nil, 48 | completion: @escaping (Result) -> Void) { 49 | 50 | URLSession.shared.fetch(.circuits, 51 | limit: limit, 52 | offset: offset) { result in 53 | completion(result) 54 | } 55 | } 56 | 57 | /// Asynchronously fetches Formula 1 Circuits for all seasons throughout history. 58 | /// - Parameters: 59 | /// - limit: Optional property to specify number of items to return per request. 60 | /// - offset: Optional property to indicate starting point of elements from API request. 61 | /// - Returns: A model representing Circuits 62 | public static func allCircuits(limit: String? = nil, offset: String? = nil) async throws -> Circuits { 63 | try await URLSession.shared.fetch(.circuits, limit: limit, offset: offset) 64 | } 65 | 66 | /// Fetches Formula 1 Drivers - either all, or for a given year. 67 | /// - Parameters: 68 | /// - season: Season enum case, specified by an Int, which indicates to fetch data for a given year (1950-2020). 69 | /// - limit: Property to specify number of items to return per request. 70 | /// - offset: Property to indicate starting point of elements from API request. 71 | /// - completion: Asynchronous closure to inject functionality once the network interaction completes. 72 | public static func drivers(for season: Season, 73 | limit: String? = nil, 74 | offset: String? = nil, 75 | completion: @escaping (Result) -> Void) { 76 | 77 | URLSession.shared.fetch(.drivers, 78 | for: season, 79 | limit: limit, 80 | offset: offset) { result in 81 | completion(result) 82 | } 83 | } 84 | 85 | /// Asynchronously fetches Formula 1 Drivers - either all, or for a given year. 86 | /// - Parameters: 87 | /// - season: Season enum case, specified by an Int, which indicates to fetch data for a given year (1950-2020). 88 | /// - limit: Property to specify number of items to return per request. 89 | /// - offset: Property to indicate starting point of elements from API request. 90 | /// - Returns: A model representing Drivers 91 | public static func drivers(for season: Season, limit: String? = nil, offset: String? = nil) async throws -> Drivers { 92 | try await URLSession.shared.fetch(.drivers, for: season, limit: limit, offset: offset) 93 | } 94 | 95 | /// Fetches Formula 1 Seasons throughout history. 96 | /// - Parameters: 97 | /// - limit: Optional property to specify number of items to return per request. 98 | /// - offset: Optional property to indicate starting point of elements from API request. 99 | /// - completion: Asynchronous closure to inject functionality once the network interaction completes. 100 | public static func seasons(limit: String? = nil, 101 | offset: String? = nil, 102 | completion: @escaping (Result) -> Void) { 103 | 104 | URLSession.shared.fetch(.seasons, 105 | limit: limit, 106 | offset: offset) { result in 107 | completion(result) 108 | } 109 | } 110 | 111 | /// Asynchronously fetches Formula 1 Seasons throughout history. 112 | /// - Parameters: 113 | /// - limit: Optional property to specify number of items to return per request. 114 | /// - offset: Optional property to indicate starting point of elements from API request. 115 | /// - Returns: A model representing Seasons 116 | public static func seasons(limit: String? = nil, offset: String? = nil) async throws -> Seasons { 117 | try await URLSession.shared.fetch(.seasons, limit: limit, offset: offset) 118 | } 119 | 120 | /// Fetches Formula 1 Constructors for all seasons throughout history. 121 | /// - Parameters: 122 | /// - limit: Optional property to specify number of items to return per request. 123 | /// - offset: Optional property to indicate starting point of elements from API request. 124 | /// - completion: Asynchronous closure to inject functionality once the network interaction completes. 125 | public static func allConstructors(limit: String? = nil, 126 | offset: String? = nil, 127 | completion: @escaping (Result) -> Void) { 128 | 129 | URLSession.shared.fetch(.constructors, 130 | limit: limit, 131 | offset: limit) { result in 132 | completion(result) 133 | } 134 | } 135 | 136 | /// Asynchronously fetches Formula 1 Constructors for all seasons throughout history. 137 | /// - Parameters: 138 | /// - limit: Optional property to specify number of items to return per request. 139 | /// - offset: Optional property to indicate starting point of elements from API request. 140 | /// - Returns: A model representing Constructors 141 | public static func allConstructors(limit: String? = nil, offset: String? = nil) async throws -> Constructors { 142 | try await URLSession.shared.fetch(.constructors, limit: limit, offset: limit) 143 | } 144 | 145 | /// Fetches Formula 1 Constructors for a given season. 146 | /// - Parameters: 147 | /// - season: Season enum case, specified by an Int, which indicates to fetch data for a given year (1950-2020). 148 | /// - limit: Optional property to specify number of items to return per request. 149 | /// - offset: Optional property to indicate starting point of elements from API request. 150 | /// - completion: Asynchronous closure to inject functionality once the network interaction completes. 151 | public static func constructors(for season: Season, 152 | limit: String? = nil, 153 | offset: String? = nil, 154 | completion: @escaping (Result) -> Void) { 155 | 156 | URLSession.shared.fetch(.constructors, 157 | for: season, 158 | limit: limit, 159 | offset: limit) { result in 160 | completion(result) 161 | } 162 | } 163 | 164 | /// Asynchronously fetches Formula 1 Constructors for all seasons throughout history. 165 | /// - Parameters: 166 | /// - season: Season enum case, specified by an Int, which indicates to fetch data for a given year (1950-2020). 167 | /// - limit: Optional property to specify number of items to return per request. 168 | /// - offset: Optional property to indicate starting point of elements from API request. 169 | /// - Returns: A model representing Constructors 170 | public static func constructors(for season: Season, limit: String? = nil, offset: String? = nil) async throws -> Constructors { 171 | try await URLSession.shared.fetch(.constructors, for: season, limit: limit, offset: limit) 172 | } 173 | 174 | /// Fetchs Formula 1 Driver standings for a given year 175 | /// - Parameters: 176 | /// - season: Season enum case, specified by an Int, which indicates to fetch data for a given year (1950-2020). 177 | /// - limit: Optional property to specify number of items to return per request. 178 | /// - offset: Optional property to indicate starting point of elements from API request. 179 | /// - completion: Asynchronous closure to inject functionality once the network interaction completes. 180 | public static func driverStandings(for season: Season, 181 | limit: String? = nil, 182 | offset: String? = nil, 183 | completion: @escaping (Result) -> Void) { 184 | 185 | URLSession.shared.fetch(.driverStandings, 186 | for: season, 187 | limit: limit, 188 | offset: limit) { result in 189 | completion(result) 190 | } 191 | } 192 | 193 | /// Asynchronously fetchs Formula 1 Driver standings for a given year 194 | /// - Parameters: 195 | /// - season: Season enum case, specified by an Int, which indicates to fetch data for a given year (1950-2020). 196 | /// - limit: Optional property to specify number of items to return per request. 197 | /// - offset: Optional property to indicate starting point of elements from API request. 198 | /// - Returns: a model object that represents the driver standings for the spocified year 199 | public static func driverStandings(for season: Season, limit: String? = nil, offset: String? = nil) async throws -> DriverStandings { 200 | try await URLSession.shared.fetch(.driverStandings, for: season, limit: limit, offset: limit) 201 | } 202 | 203 | /// Fetches Formula 1 Race Schedule for a given year. 204 | /// - Parameters: 205 | /// - season: Season enum case, specified by an Int, which indicates to fetch data for a given year (1950-2020). 206 | /// - limit: Optional property to specify number of items to return per request. 207 | /// - offset: Optional property to indicate starting point of elements from API request. 208 | /// - completion: Asynchronous closure to inject functionality once the network interaction completes. 209 | public static func raceSchedule(for season: Season, 210 | limit: String? = nil, 211 | offset: String? = nil, 212 | completion: @escaping (Result) -> Void) { 213 | 214 | URLSession.shared.fetch(.raceSchedule, 215 | for: season, 216 | limit: limit, 217 | offset: offset) { result in 218 | completion(result) 219 | } 220 | } 221 | 222 | /// Asynchronously fetches Formula 1 Race Schedule for a given year. 223 | /// - Parameters: 224 | /// - season: Season enum case, specified by an Int, which indicates to fetch data for a given year (1950-2020). 225 | /// - limit: Optional property to specify number of items to return per request. 226 | /// - offset: Optional property to indicate starting point of elements from API request. 227 | /// - Returns: A model representing a Race Schedule 228 | public static func raceSchedule(for season: Season, limit: String? = nil, offset: String? = nil) async throws -> RaceSchedule { 229 | try await URLSession.shared.fetch(.raceSchedule, for: season, limit: limit, offset: offset) 230 | } 231 | 232 | /// Fetches Formula 1 Race Results for a given year. 233 | /// - Parameters: 234 | /// - season: Season enum case, specified by an Int, which indicates to fetch data for a given year (1950-2020). 235 | /// - limit: Optional property to specify number of items to return per request. 236 | /// - offset: Optional property to indicate starting point of elements from API request. 237 | /// - completion: Asynchronous closure to inject functionality once the network interaction completes. 238 | public static func raceResults(for season: Season, 239 | limit: String? = nil, 240 | offset: String? = nil, 241 | completion: @escaping(Result) -> Void) { 242 | 243 | URLSession.shared.fetch(.raceResults, 244 | for: season, 245 | limit: limit, 246 | offset: offset) { result in 247 | completion(result) 248 | } 249 | } 250 | 251 | /// Asynchronously fetches Formula 1 Race Results for a given year. 252 | /// - Parameters: 253 | /// - season: Season enum case, specified by an Int, which indicates to fetch data for a given year (1950-2020). 254 | /// - limit: Optional property to specify number of items to return per request. 255 | /// - offset: Optional property to indicate starting point of elements from API request. 256 | /// - Returns: A model that represents a race result. 257 | public static func raceResults(for season: Season, limit: String? = nil, offset: String? = nil) async throws -> RaceResults { 258 | try await URLSession.shared.fetch(.raceResults, for: season, limit: limit, offset: offset) 259 | } 260 | 261 | /// Fetches Qualifying Results for a given year. 262 | /// - Parameters: 263 | /// - season: Season enum case, specified by an Int, which indicates to fetch data for a given year (1950-2020). 264 | /// - limit: Optional property to specify number of items to return per request. 265 | /// - offset: Optional property to indicate starting point of elements from API request. 266 | /// - completion: Asynchronous closure to inject functionality once the network interaction completes. 267 | public static func qualifyingResults(for season: Season, 268 | limit: String? = nil, 269 | offset: String? = nil, 270 | completion: @escaping (Result) -> Void) { 271 | 272 | URLSession.shared.fetch(.qualifyingResults, 273 | for: season, 274 | limit: limit, 275 | offset: offset) { result in 276 | completion(result) 277 | } 278 | } 279 | 280 | /// Fetches Qualifying Results for a given year. 281 | /// - Parameters: 282 | /// - season: Season enum case, specified by an Int, which indicates to fetch data for a given year (1950-2020). 283 | /// - limit: Optional property to specify number of items to return per request. 284 | /// - offset: Optional property to indicate starting point of elements from API request. 285 | /// - Returns: A model that represents a qualifying result. 286 | public static func qualifyingResults(for season: Season, limit: String? = nil, offset: String? = nil) async throws -> QualifyingResults { 287 | try await URLSession.shared.fetch(.qualifyingResults, for: season, limit: limit, offset: offset) 288 | } 289 | 290 | /// Fetches Pit Stops for a given year and round. 291 | /// - Parameters: 292 | /// - season: Season enum case, specified by an Int, which indicates to fetch data for a given year (1950-2020). 293 | /// - round: A race within the season. 294 | /// - limit: Property to specify number of items to return per request. 295 | /// - offset: Property to indicate starting point of elements from API request. 296 | /// - completion: Asynchronous closure to inject functionality once the network interaction completes. 297 | public static func pitStops(for season: Season, 298 | round: String, 299 | limit: String? = nil, 300 | offset: String? = nil, 301 | completion: @escaping (Result) -> Void) { 302 | 303 | URLSession.shared.fetch(.pitStops, 304 | for: season, 305 | round: round, 306 | limit: limit, 307 | offset: offset) { result in 308 | completion(result) 309 | } 310 | } 311 | 312 | /// Asynchronously fetches Pit Stops for a given year and round. 313 | /// - Parameters: 314 | /// - season: Season enum case, specified by an Int, which indicates to fetch data for a given year (1950-2020). 315 | /// - round: A race within the season. 316 | /// - limit: Property to specify number of items to return per request. 317 | /// - offset: Property to indicate starting point of elements from API request. 318 | /// - Returns: A model representing pit stops. 319 | public static func pitStops(for season: Season, round: String, limit: String? = nil, offset: String? = nil) async throws -> PitStops { 320 | try await URLSession.shared.fetch(.pitStops, for: season, round: round, limit: limit, offset: offset) 321 | } 322 | 323 | /// Fetches lap times for a lap within a race. 324 | /// - Parameters: 325 | /// - season: Season enum case, specified by an Int, which indicates to fetch data for a given year (1950-2020). 326 | /// - round: A race within the season. 327 | /// - lap: Lap of given race. 328 | /// - limit: Property to specify number of items to return per request. 329 | /// - offset: Property to indicate starting point of elements from API request. 330 | /// - completion: Asynchronous closure to inject functionality once the network interaction completes. 331 | public static func laps(for season: Season, 332 | round: String, 333 | lap: String? = nil, 334 | limit: String? = nil, 335 | offset: String? = nil, 336 | completion: @escaping (Result) -> Void) { 337 | 338 | URLSession.shared.fetch(.lapTimes(lap), 339 | for: season, 340 | round: round, 341 | limit: limit, 342 | offset: offset) { result in 343 | completion(result) 344 | } 345 | } 346 | 347 | /// Asynnchronouslt fetches lap times for a lap within a race. 348 | /// - Parameters: 349 | /// - season: Season enum case, specified by an Int, which indicates to fetch data for a given year (1950-2020). 350 | /// - round: A race within the season. 351 | /// - lap: Lap of given race. 352 | /// - limit: Property to specify number of items to return per request. 353 | /// - offset: Property to indicate starting point of elements from API request. 354 | /// - Returns: A model that represents laps. 355 | public static func laps(for season: Season, round: String, lap: String? = nil, limit: String? = nil, offset: String? = nil) async throws -> Laps { 356 | try await URLSession.shared.fetch(.lapTimes(lap), for: season, round: round, limit: limit, offset: offset) 357 | } 358 | 359 | /// Fetches finishing status for given season. 360 | /// - Parameters: 361 | /// - season: Season enum case, specified by an Int, which indicates to fetch data for a given year (1950-2020). 362 | /// - round: A race within the season. 363 | /// - limit: Property to specify number of items to return per request. 364 | /// - offset: Property to indicate starting point of elements from API request. 365 | /// - completion: Asynchronous closure to inject functionality once the network interaction completes. 366 | public static func finishingStatus(for season: Season, 367 | round: String? = nil, 368 | limit: String? = nil, 369 | offset: String? = nil, 370 | completion: @escaping (Result) -> Void) { 371 | 372 | URLSession.shared.fetch(.finishingStatus, 373 | for: season, 374 | limit: limit, 375 | offset: offset) { result in 376 | completion(result) 377 | } 378 | } 379 | 380 | /// Asynchronously fetches finishing status for given season. 381 | /// - Parameters: 382 | /// - season: Season enum case, specified by an Int, which indicates to fetch data for a given year (1950-2020). 383 | /// - round: A race within the season. 384 | /// - limit: Property to specify number of items to return per request. 385 | /// - offset: Property to indicate starting point of elements from API request. 386 | /// - Returns: A model that representes a finishing status. 387 | public static func finishingStatus( 388 | for season: Season, 389 | round: String? = nil, 390 | limit: String? = nil, 391 | offset: String? = nil 392 | ) async throws -> FinishingStatus { 393 | try await URLSession.shared.fetch(.finishingStatus, for: season, limit: limit, offset: offset) 394 | } 395 | } 396 | -------------------------------------------------------------------------------- /Sources/Formula1API/Helpers/Endpoint.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Endpoint.swift 3 | // 4 | // 5 | // Created by Giovanni Noa on 4/28/20. 6 | // 7 | 8 | import Foundation 9 | 10 | 11 | /// Internal struct for query items used in Ergast URLs. 12 | private enum ErgastQueryItems { 13 | /// Limit indicator, to specify to the API how many items to return at a time per request. 14 | case limit(String?) 15 | 16 | /// Offset indicator, to specify to the API the starting point of elements. 17 | case offset(String?) 18 | } 19 | 20 | /// Indicates URL components for the Ergast REST API. 21 | private enum ErgastEndpoint { 22 | /// URL scheme. 23 | static let scheme = "https" 24 | 25 | /// URL host. 26 | static let host = "ergast.com" 27 | } 28 | 29 | /// Generates a URL for a given Path enum case. 30 | internal struct Endpoint { 31 | /// URL for Ergast API. 32 | private let urlPath: String 33 | 34 | /// Indicates number of items to return per request. 35 | private var limit: String? 36 | 37 | /// Indicates the starting point of elements from API request. 38 | private var offset: String? 39 | 40 | /// Initializer for an Endpoint object. 41 | /// - Parameters: 42 | /// - path: Specify a path, mapping to a specific endpoint of the Ergast REST API. 43 | /// - season: Season enum case, specified by an Int, which indicates to fetch data for a given year (1950-2020). All historical seasons will be fetched if nil. 44 | /// - limit: Optional property to specify number of items to return per request. 45 | /// - offset: Optional property to indicate starting point of elements from API request. 46 | init(with path: Path, 47 | for season: Season?, 48 | round: String?, 49 | lap: String?, 50 | limit: String?, 51 | offset: String?) { 52 | 53 | urlPath = path.urlPath(for: season, round: round, lap: lap) 54 | 55 | self.limit = limit 56 | self.offset = offset 57 | } 58 | } 59 | 60 | // MARK: - Endpoint URL Builder 61 | extension Endpoint { 62 | /// URL for the given path. 63 | var url: URL { 64 | var components = URLComponents() 65 | components.scheme = ErgastEndpoint.scheme 66 | components.host = ErgastEndpoint.host 67 | components.path = urlPath 68 | 69 | var queryItems: [URLQueryItem] = .init() 70 | 71 | if let limit = limit { 72 | let item = URLQueryItem(name: "limit", value: limit) 73 | queryItems.append(item) 74 | } 75 | 76 | if let offset = offset { 77 | let item = URLQueryItem(name: "offset", value: offset) 78 | queryItems.append(item) 79 | } 80 | 81 | components.queryItems = queryItems 82 | 83 | guard let validURL = components.url else { fatalError("Could not construct URL.") } 84 | 85 | return validURL 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /Sources/Formula1API/Helpers/Extensions/Decodable+Extension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Decodable+Extension.swift 3 | // 4 | // 5 | // Created by Giovanni Noa on 5/8/20. 6 | // 7 | 8 | import Foundation 9 | 10 | extension Decodable { 11 | static func decode(from: Data, 12 | using decoder: JSONDecoder = JSONDecoder()) throws -> Self { 13 | return try decoder.decode(self, from: from) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Sources/Formula1API/Helpers/Extensions/URLSession+Extension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // URLSession+Extension.swift 3 | // 4 | // 5 | // Created by Giovanni Noa on 4/28/20. 6 | // 7 | 8 | import Foundation 9 | 10 | // MARK: - URLSession 11 | extension URLSession { 12 | /// Callback-based networking data task. Called by the internal fetch function. 13 | /// - Parameters: 14 | /// - url: URL to reach. 15 | /// - session: URLSession instance. 16 | /// - completion: Asynchronous closure to inject functionality once the network interaction completes. 17 | private func dataTask(_ url: URL, 18 | _ session: URLSession, 19 | completion: @escaping ((Result) -> Void)) { 20 | session.dataTask(with: url) { data, response, error in 21 | guard let data = data, error == nil else { 22 | if let error = error { 23 | completion(.failure(.network(error.localizedDescription))) 24 | } else { 25 | completion(.failure(.data("Failed to generate data."))) 26 | } 27 | return 28 | } 29 | completion(.success(data)) 30 | } 31 | .resume() 32 | } 33 | 34 | /// Callback-based networking fetch function. Calls the data task function and decodes the JSON response. 35 | /// - Parameters: 36 | /// - subPath: Path enum case to indicate which endpoint you wish to fetch from. 37 | /// - season: Season enum case, specified by an Int, which indicates to fetch data for a given year (1950-2020). Fetches data for all historical seasons of given endpoint if nil. 38 | /// - session: URLSession instance (URLSession.shared singleton by default) 39 | /// - decodingType: Decodable-conforming object to be used for serializing JSON response. 40 | /// - completion: Asynchronous closure to inject functionality once the network interaction finishes fetching. 41 | internal func fetch(_ subPath: Path, 42 | for season: Season? = nil, 43 | round: String? = nil, 44 | lap: String? = nil, 45 | limit: String? = nil, 46 | offset: String? = nil, 47 | session: URLSession = URLSession.shared, 48 | completion: @escaping ((Result) -> Void)) { 49 | let endpoint = Endpoint(with: subPath, 50 | for: season, 51 | round: round, 52 | lap: lap, 53 | limit: limit, 54 | offset: offset) 55 | let url = endpoint.url 56 | 57 | session.dataTask(url, session) { result in 58 | switch result { 59 | case .success(let data): 60 | do { 61 | let decode = try subPath.decodingType.decode(from: data) 62 | 63 | completion(.success(decode as! T)) 64 | } catch (let error) { 65 | print(error) 66 | completion(.failure(.network(error.localizedDescription))) 67 | } 68 | case .failure(let error): 69 | print(error) 70 | completion(.failure(error)) 71 | } 72 | } 73 | } 74 | 75 | /// Async/await networking fetch function. 76 | /// 77 | /// Calls the data task function and decodes the JSON response. 78 | /// 79 | /// - Parameters: 80 | /// - subPath: Path enum case to indicate which endpoint you wish to fetch from. 81 | /// - season: Season enum case, specified by an Int, which indicates to fetch data for a given year (1950-2020). Fetches data for all historical seasons of given endpoint if nil. 82 | /// - round: A race within the season. 83 | /// - lap: Lap of given race. 84 | /// - limit: Property to specify number of items to return per request. 85 | /// - offset: Property to indicate starting point of elements from API request. 86 | /// - session: URLSession instance (URLSession.shared singleton by default) 87 | /// - Returns: A model represeting the decodeable model that is specified by the `subPath` parameter. 88 | internal func fetch( 89 | _ subPath: Path, 90 | for season: Season? = nil, 91 | round: String? = nil, 92 | lap: String? = nil, 93 | limit: String? = nil, 94 | offset: String? = nil, 95 | session: URLSession = URLSession.shared 96 | ) async throws -> T { 97 | try await withCheckedThrowingContinuation { [weak self] continuation in 98 | self?.fetch( 99 | subPath, 100 | for: season, 101 | round: round, 102 | lap: lap, 103 | limit: limit, 104 | offset: offset, 105 | session: session 106 | ) { result in 107 | continuation.resume(with: result) 108 | } 109 | } 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /Sources/Formula1API/Helpers/Path.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Path.swift 3 | // 4 | // 5 | // Created by Giovanni Noa on 4/29/20. 6 | // 7 | 8 | // MARK: - Path 9 | /// Enum containing the sub-path for specifying an endpoint within the Ergast API. 10 | enum Path { 11 | private static let basePath = "/api/f1" 12 | 13 | /// Circuits (all, specific season) 14 | case circuits 15 | 16 | /// Constructors(all, specific season) 17 | case constructors 18 | 19 | /// Constructor Standings (all, specific season) 20 | case constructorStandings 21 | 22 | /// Drivers (all, specific season). 23 | case drivers 24 | 25 | /// Driver Standings. 26 | case driverStandings 27 | 28 | /// Finishing Status 29 | case finishingStatus 30 | 31 | /// Lap Times. 32 | case lapTimes(String?) 33 | 34 | /// Pit Stops. 35 | case pitStops 36 | 37 | /// Race Schedule. 38 | case raceSchedule 39 | 40 | /// Race Results. 41 | case raceResults 42 | 43 | /// Race Standings (all, specific season). 44 | case raceStandings 45 | 46 | /// Seasons throughout history. 47 | case seasons 48 | 49 | /// Qualifying Results for a given year. 50 | case qualifyingResults 51 | } 52 | 53 | extension Path { 54 | /// Function that generates the path for an endpoint within the Ergast API. 55 | /// - Parameter season: Season enum case, specified by an Int, which indicates to fetch data for a given year (1950-2020). Data for historical seasons will be fetched if nil. 56 | /// - Returns: String to be added to the Endpoint path. 57 | private func subPath(for season: Season? = nil, 58 | round: String? = nil) -> String { 59 | 60 | let year = season?.query ?? "" 61 | let race = round ?? "" 62 | 63 | switch self { 64 | case .circuits: 65 | return "\(year)/circuits.json" 66 | 67 | case .constructors: 68 | return "\(year)/constructors.json" 69 | 70 | case .constructorStandings: 71 | return "\(year)/constructorStandings.json" 72 | 73 | case .drivers: 74 | return "\(year)/drivers.json" 75 | 76 | case .driverStandings: 77 | return "\(year)/driverStandings.json" 78 | 79 | case .finishingStatus: 80 | if race != "" { 81 | return "\(year)/\(race)/status.json" 82 | } 83 | 84 | return "\(year)/status.json" 85 | 86 | case .lapTimes(let lap): 87 | if let lap = lap { 88 | return "\(year)/\(race)/laps/\(lap).json" 89 | } 90 | 91 | return "\(year)/\(race)/laps.json" 92 | 93 | case .pitStops: 94 | return "\(year)/\(race)/pitstops.json" 95 | 96 | case .raceSchedule: 97 | return "\(year).json" 98 | 99 | case .raceResults: 100 | return "\(year)/results.json" 101 | 102 | case .raceStandings: 103 | return "\(year)/results.json" 104 | 105 | case .seasons: 106 | return "/seasons.json" 107 | 108 | case .qualifyingResults: 109 | return "\(year)/qualifying.json" 110 | } 111 | } 112 | 113 | /// Constructs a path. 114 | /// - Parameter season: Season enum case, specified by an Int, which indicates to fetch data for a given year (1950-2020). All historical seasons will be fetched if nil. 115 | /// - Returns: String representing a URL path. 116 | func urlPath(for season: Season?, 117 | round: String?, 118 | lap: String?) -> String { 119 | return Path.basePath + subPath(for: season, 120 | round: round) 121 | } 122 | 123 | /// Returns a Decodable type for a given endpoint. 124 | var decodingType: Decodable.Type { 125 | switch self { 126 | case .circuits: return Circuits.self 127 | case .constructors: return Constructors.self 128 | case .drivers: return Drivers.self 129 | case .driverStandings: return DriverStandings.self 130 | case .finishingStatus: return FinishingStatus.self 131 | case .lapTimes(_): return Laps.self 132 | case .seasons: return Seasons.self 133 | case .pitStops: return PitStops.self 134 | case .raceResults: return RaceResults.self 135 | case .raceSchedule: return RaceSchedule.self 136 | case .qualifyingResults: return QualifyingResults.self 137 | default: fatalError("Must provide Decodable type for enum case") 138 | } 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /Sources/Formula1API/Helpers/Season.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Season.swift 3 | // 4 | // 5 | // Created by Giovanni Noa on 5/4/20. 6 | // 7 | 8 | import Foundation 9 | 10 | // MARK: - Season 11 | /// Season enum to indicate whether a networking function is to fetch all historical data, or data for a single season. 12 | public enum Season { 13 | /// A year, representing a specific season (1950-2021). 14 | case year(Int) 15 | 16 | /// All historical data endpoint (1950-2021). 17 | case all 18 | } 19 | 20 | extension Season { 21 | /// Function to be used by the Path endpoint builder. 22 | /// - Returns: String that will be part of the resultant URL. 23 | var query: String? { 24 | switch self { 25 | case .year(let year): 26 | return "/\(year)" 27 | case .all: 28 | return "" 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Sources/Formula1API/Models/Circuits.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Circuits.swift 3 | // 4 | // 5 | // Created by Giovanni Noa on 5/5/20. 6 | // 7 | 8 | /// Codable struct, used for serializing JSON from the Circuits endpoint. 9 | public struct Circuits: Codable { 10 | public let data: CircuitData 11 | 12 | private enum CodingKeys: String, CodingKey { 13 | case data = "MRData" 14 | } 15 | } 16 | 17 | public extension Circuits { 18 | var currentCircuits: [Circuit] { self.data.circuitTable.circuits } 19 | } 20 | 21 | public struct CircuitData: Codable { 22 | public let url: String 23 | public let limit: String 24 | public let offset: String 25 | public let total: String 26 | public let circuitTable: CircuitTable 27 | 28 | private enum CodingKeys: String, CodingKey { 29 | case url 30 | case limit 31 | case offset 32 | case total 33 | case circuitTable = "CircuitTable" 34 | } 35 | } 36 | 37 | public struct CircuitTable: Codable { 38 | public let season: String? 39 | public let circuits: [Circuit] 40 | 41 | private enum CodingKeys: String, CodingKey { 42 | case circuits = "Circuits" 43 | case season 44 | } 45 | } 46 | 47 | public struct Circuit: Codable { 48 | public let circuitID: String 49 | public let circuitName: String 50 | public let location: Location 51 | 52 | private enum CodingKeys: String, CodingKey { 53 | case circuitID = "circuitId" 54 | case circuitName 55 | case location = "Location" 56 | } 57 | } 58 | 59 | public struct Location: Codable { 60 | public let lat: String 61 | public let long: String 62 | public let locality: String 63 | public let country: String 64 | } 65 | -------------------------------------------------------------------------------- /Sources/Formula1API/Models/Constructors.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Constructors.swift 3 | // 4 | // 5 | // Created by Giovanni Noa on 5/9/20. 6 | // 7 | 8 | import Foundation 9 | 10 | /// Codable struct, used for serializing JSON from the Constructors endpoint. 11 | public struct Constructors: Codable { 12 | public let data: ConstructorsData 13 | 14 | private enum CodingKeys: String, CodingKey { 15 | case data = "MRData" 16 | } 17 | } 18 | 19 | public struct ConstructorsData: Codable { 20 | public let xmlns: String 21 | public let series: String 22 | public let url: String 23 | public let limit: String 24 | public let offset: String 25 | public let total: String 26 | public let constructorTable: ConstructorTable 27 | 28 | private enum CodingKeys: String, CodingKey { 29 | case xmlns 30 | case series 31 | case url 32 | case limit 33 | case offset 34 | case total 35 | case constructorTable = "ConstructorTable" 36 | } 37 | } 38 | 39 | public struct ConstructorTable: Codable { 40 | public let season: String? 41 | public let constructors: [Constructor] 42 | 43 | private enum CodingKeys: String, CodingKey { 44 | case season 45 | case constructors = "Constructors" 46 | } 47 | } 48 | 49 | public struct Constructor: Codable { 50 | public let constructorID: String 51 | public let url: String 52 | public let name: String 53 | public let nationality: String 54 | 55 | private enum CodingKeys: String, CodingKey { 56 | case constructorID = "constructorId" 57 | case url 58 | case name 59 | case nationality 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /Sources/Formula1API/Models/DriverStandings.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DriverStandings.swift 3 | // 4 | // 5 | // Created by Giovanni Noa on 6/12/20. 6 | // 7 | 8 | import Foundation 9 | 10 | /// Codable struct, used for serializing JSON from the DriverStandings endpoint. 11 | public struct DriverStandings: Codable { 12 | public let data: DriverStandingsData 13 | 14 | private enum CodingKeys: String, CodingKey { 15 | case data = "MRData" 16 | } 17 | } 18 | 19 | public struct DriverStandingsData: Codable { 20 | public let series: String 21 | public let url: String 22 | public let limit: String 23 | public let offset: String 24 | public let total: String 25 | public let standingsTable: StandingsTable 26 | 27 | private enum CodingKeys: String, CodingKey { 28 | case series 29 | case url 30 | case limit 31 | case offset 32 | case total 33 | case standingsTable = "StandingsTable" 34 | } 35 | } 36 | 37 | public struct StandingsTable: Codable { 38 | public let season: String? 39 | public let standingsLists: [StandingsList] 40 | 41 | private enum CodingKeys: String, CodingKey { 42 | case season 43 | case standingsLists = "StandingsLists" 44 | } 45 | } 46 | 47 | public struct StandingsList: Codable { 48 | public let season, round: String 49 | public let driverStandings: [DriverStanding] 50 | 51 | private enum CodingKeys: String, CodingKey { 52 | case season 53 | case round 54 | case driverStandings = "DriverStandings" 55 | } 56 | } 57 | 58 | public struct DriverStanding: Codable { 59 | public let position: String 60 | public let positionText: String 61 | public let points: String 62 | public let wins: String 63 | public let driver: Driver 64 | public let constructors: [Constructor] 65 | 66 | private enum CodingKeys: String, CodingKey { 67 | case position 68 | case positionText 69 | case points 70 | case wins 71 | case driver = "Driver" 72 | case constructors = "Constructors" 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /Sources/Formula1API/Models/Drivers.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DriverInfo.swift 3 | // 4 | // 5 | // Created by Giovanni Noa on 6/12/20. 6 | // 7 | 8 | import Foundation 9 | 10 | /// Codable struct, used for serializing JSON from the Drivers endpoint. 11 | public struct Drivers: Codable { 12 | public let data: DriversData 13 | 14 | private enum CodingKeys: String, CodingKey { 15 | case data = "MRData" 16 | } 17 | } 18 | 19 | public struct DriversData: Codable { 20 | public let series: String 21 | public let url: String 22 | public let limit: String 23 | public let offset: String 24 | public let total: String 25 | public let driverTable: DriverTable 26 | 27 | private enum CodingKeys: String, CodingKey { 28 | case series 29 | case url 30 | case limit 31 | case offset 32 | case total 33 | case driverTable = "DriverTable" 34 | } 35 | } 36 | 37 | public struct DriverTable: Codable { 38 | public let season: String? 39 | public let drivers: [Driver] 40 | 41 | private enum CodingKeys: String, CodingKey { 42 | case season 43 | case drivers = "Drivers" 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Sources/Formula1API/Models/FinishingStatus.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FinishingStatus.swift 3 | // 4 | // 5 | // Created by Giovanni Noa on 6/12/20. 6 | // 7 | 8 | import Foundation 9 | 10 | /// Codable struct, used for serializing JSON from the FinishingStatus endpoint. 11 | public struct FinishingStatus: Codable { 12 | public let data: FinishingStatusData 13 | 14 | private enum CodingKeys: String, CodingKey { 15 | case data = "MRData" 16 | } 17 | } 18 | 19 | public struct FinishingStatusData: Codable { 20 | public let series: String 21 | public let url: String 22 | public let limit: String 23 | public let offset: String 24 | public let total: String 25 | public let statusTable: StatusTable 26 | 27 | private enum CodingKeys: String, CodingKey { 28 | case series 29 | case url 30 | case limit 31 | case offset 32 | case total 33 | case statusTable = "StatusTable" 34 | } 35 | } 36 | 37 | public struct StatusTable: Codable { 38 | public let season: String 39 | public let status: [Status] 40 | 41 | private enum CodingKeys: String, CodingKey { 42 | case season 43 | case status = "Status" 44 | } 45 | } 46 | 47 | public struct Status: Codable { 48 | public let statusID: String 49 | public let count: String 50 | public let status: String 51 | 52 | private enum CodingKeys: String, CodingKey { 53 | case statusID = "statusId" 54 | case count 55 | case status 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Sources/Formula1API/Models/Laps.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Lap.swift 3 | // 4 | // 5 | // Created by Giovanni Noa on 6/11/20. 6 | // 7 | 8 | import Foundation 9 | 10 | /// Codable struct, used for serializing JSON from the Laps endpoint. 11 | public struct Laps: Codable { 12 | public let data: LapsData 13 | 14 | private enum CodingKeys: String, CodingKey { 15 | case data = "MRData" 16 | } 17 | } 18 | 19 | public struct LapsData: Codable { 20 | public let series: String 21 | public let url: String 22 | public let limit: String 23 | public let offset: String 24 | public let total: String 25 | public let raceTable: RaceTable 26 | 27 | private enum CodingKeys: String, CodingKey { 28 | case series 29 | case url 30 | case limit 31 | case offset 32 | case total 33 | case raceTable = "RaceTable" 34 | } 35 | } 36 | 37 | public struct LapElement: Codable { 38 | public let number: String 39 | public let timings: [Timing] 40 | 41 | private enum CodingKeys: String, CodingKey { 42 | case number 43 | case timings = "Timings" 44 | } 45 | } 46 | 47 | public struct Timing: Codable { 48 | public let driverID: String 49 | public let position: String 50 | public let time: String 51 | 52 | private enum CodingKeys: String, CodingKey { 53 | case driverID = "driverId" 54 | case position 55 | case time 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Sources/Formula1API/Models/PitStops.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PitStops.swift 3 | // 4 | // 5 | // Created by Giovanni Noa on 6/10/20. 6 | // 7 | 8 | import Foundation 9 | 10 | /// Codable struct, used for serializing JSON from the PitStops endpoint. 11 | public struct PitStops: Codable { 12 | public let data: PitStopsData 13 | 14 | private enum CodingKeys: String, CodingKey { 15 | case data = "MRData" 16 | } 17 | } 18 | 19 | public struct PitStopsData: Codable { 20 | public let series: String 21 | public let url: String 22 | public let limit: String 23 | public let offset: String 24 | public let total: String 25 | public let raceTable: RaceTable 26 | 27 | private enum CodingKeys: String, CodingKey { 28 | case series 29 | case url 30 | case limit 31 | case offset 32 | case total 33 | case raceTable = "RaceTable" 34 | } 35 | } 36 | 37 | public struct PitStop: Codable { 38 | public let driverID: String 39 | public let lap: String 40 | public let stop: String 41 | public let time: String 42 | public let duration: String 43 | 44 | private enum CodingKeys: String, CodingKey { 45 | case driverID = "driverId" 46 | case lap 47 | case stop 48 | case time 49 | case duration 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Sources/Formula1API/Models/QualifyingResults.swift: -------------------------------------------------------------------------------- 1 | // 2 | // QualifyingResults.swift 3 | // 4 | // 5 | // Created by Giovanni Noa on 6/3/20. 6 | // 7 | 8 | import Foundation 9 | 10 | /// Codable struct, used for serializing JSON from the QualifyingResults endpoint. 11 | public struct QualifyingResults: Codable { 12 | public let data: QualifyingResultsData 13 | 14 | enum CodingKeys: String, CodingKey { 15 | case data = "MRData" 16 | } 17 | } 18 | 19 | public struct QualifyingResultsData: Codable { 20 | public let series: String 21 | public let url: String 22 | public let limit: String 23 | public let offset: String 24 | public let total: String 25 | public let raceTable: RaceTable 26 | 27 | private enum CodingKeys: String, CodingKey { 28 | case series 29 | case url 30 | case limit 31 | case offset 32 | case total 33 | case raceTable = "RaceTable" 34 | } 35 | } 36 | 37 | public struct QualifyingResult: Codable { 38 | public let number: String 39 | public let position: String 40 | public let driver: Driver 41 | public let constructor: Constructor 42 | public let q1: String 43 | public let q2: String? 44 | public let q3: String? 45 | 46 | private enum CodingKeys: String, CodingKey { 47 | case number 48 | case position 49 | case driver = "Driver" 50 | case constructor = "Constructor" 51 | case q1 = "Q1" 52 | case q2 = "Q2" 53 | case q3 = "Q3" 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Sources/Formula1API/Models/RaceResults.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RaceResults.swift 3 | // 4 | // 5 | // Created by Giovanni Noa on 5/11/20. 6 | // 7 | 8 | import Foundation 9 | 10 | /// Codable struct, used for serializing JSON from the RaceResults endpoint. 11 | public struct RaceResults: Codable { 12 | public let data: RaceResultsData 13 | 14 | private enum CodingKeys: String, CodingKey { 15 | case data = "MRData" 16 | } 17 | } 18 | 19 | public struct RaceResultsData: Codable { 20 | public let series: String 21 | public let url: String 22 | public let limit: String 23 | public let offset: String 24 | public let total: String 25 | public let raceTable: RaceTable 26 | 27 | private enum CodingKeys: String, CodingKey { 28 | case series 29 | case url 30 | case limit 31 | case offset 32 | case total 33 | case raceTable = "RaceTable" 34 | } 35 | } 36 | 37 | public struct RaceResult: Codable { 38 | public let number: String 39 | public let position: String 40 | public let positionText: String 41 | public let points: String 42 | public let driver: Driver 43 | public let constructor: Constructor 44 | public let grid, laps, status: String 45 | public let time: ResultTime? 46 | public let fastestLap: FastestLap 47 | 48 | private enum CodingKeys: String, CodingKey { 49 | case number 50 | case position 51 | case positionText 52 | case points 53 | case driver = "Driver" 54 | case constructor = "Constructor" 55 | case grid, laps, status 56 | case time = "Time" 57 | case fastestLap = "FastestLap" 58 | } 59 | } 60 | 61 | public struct Driver: Codable { 62 | public let driverID: String 63 | public let permanentNumber: String? 64 | public let code: String? 65 | public let url: String 66 | public let givenName: String 67 | public let familyName: String 68 | public let dateOfBirth: String 69 | public let nationality: String 70 | 71 | private enum CodingKeys: String, CodingKey { 72 | case driverID = "driverId" 73 | case permanentNumber 74 | case code 75 | case url 76 | case givenName 77 | case familyName 78 | case dateOfBirth 79 | case nationality 80 | } 81 | } 82 | 83 | public struct FastestLap: Codable { 84 | public let rank: String 85 | public let lap: String 86 | public let time: FastestLapTime 87 | public let averageSpeed: AverageSpeed 88 | 89 | private enum CodingKeys: String, CodingKey { 90 | case rank 91 | case lap 92 | case time = "Time" 93 | case averageSpeed = "AverageSpeed" 94 | } 95 | } 96 | 97 | public struct AverageSpeed: Codable { 98 | public let units: Units 99 | public let speed: String 100 | } 101 | 102 | public enum Units: String, Codable { 103 | case kph = "kph" 104 | } 105 | 106 | public struct FastestLapTime: Codable { 107 | public let time: String 108 | } 109 | 110 | public struct ResultTime: Codable { 111 | public let millis: String 112 | public let time: String 113 | } 114 | -------------------------------------------------------------------------------- /Sources/Formula1API/Models/RaceSchedule.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RaceSchedule.swift 3 | // 4 | // 5 | // Created by Giovanni Noa on 5/10/20. 6 | // 7 | 8 | import Foundation 9 | 10 | /// Codable struct, used for serializing JSON from the RaceSchedule endpoint. 11 | public struct RaceSchedule: Codable { 12 | public let data: RaceScheduleData 13 | 14 | private enum CodingKeys: String, CodingKey { 15 | case data = "MRData" 16 | } 17 | } 18 | 19 | public struct RaceScheduleData: Codable { 20 | public let series: String 21 | public let url: String 22 | public let limit: String 23 | public let offset: String 24 | public let total: String 25 | public let raceTable: RaceTable 26 | 27 | private enum CodingKeys: String, CodingKey { 28 | case series 29 | case url 30 | case limit 31 | case offset 32 | case total 33 | case raceTable = "RaceTable" 34 | } 35 | } 36 | 37 | public struct RaceTable: Codable { 38 | public let season: String 39 | public let round: String? 40 | public let races: [Race] 41 | 42 | private enum CodingKeys: String, CodingKey { 43 | case season 44 | case round 45 | case races = "Races" 46 | } 47 | } 48 | 49 | public struct Race: Codable { 50 | public let season: String 51 | public let round: String 52 | public let url: String 53 | public let raceName: String 54 | public let circuit: Circuit 55 | public let date: String 56 | public let time: String 57 | public let qualifyingResults: [QualifyingResult]? 58 | public let pitStops: [PitStop]? 59 | public let laps: [LapElement]? 60 | 61 | 62 | private enum CodingKeys: String, CodingKey { 63 | case season 64 | case round 65 | case url 66 | case raceName 67 | case circuit = "Circuit" 68 | case date 69 | case time 70 | case qualifyingResults = "QualifyingResults" 71 | case pitStops = "PitStops" 72 | case laps = "Laps" 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /Sources/Formula1API/Models/Seasons.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Seasons.swift 3 | // 4 | // 5 | // Created by Giovanni Noa on 5/7/20. 6 | // 7 | 8 | /// Codable struct, used for serializing JSON from the Seasons endpoint. 9 | public struct Seasons: Codable { 10 | public let data: SeasonData 11 | 12 | private enum CodingKeys: String, CodingKey { 13 | case data = "MRData" 14 | } 15 | } 16 | 17 | public struct SeasonData: Codable { 18 | public let series: String 19 | public let url: String 20 | public let limit: String 21 | public let offset: String 22 | public let total: String 23 | public let seasonTable: SeasonTable 24 | 25 | private enum CodingKeys: String, CodingKey { 26 | case series 27 | case url 28 | case limit 29 | case offset 30 | case total 31 | case seasonTable = "SeasonTable" 32 | } 33 | } 34 | 35 | public struct SeasonTable: Codable { 36 | public let seasons: [F1Season] 37 | 38 | private enum CodingKeys: String, CodingKey { 39 | case seasons = "Seasons" 40 | } 41 | } 42 | 43 | public struct F1Season: Codable { 44 | public let season: String 45 | public let url: String 46 | } 47 | -------------------------------------------------------------------------------- /Tests/ErgastAPITests/EndpointTests.swift: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Tests/ErgastAPITests/ErgastAPITests.swift: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Tests/ErgastAPITests/XCTestManifests.swift: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Tests/LinuxMain.swift: -------------------------------------------------------------------------------- 1 | 2 | --------------------------------------------------------------------------------