Pilot is a very simple HTTP network layer written in Swift, supports both modern concurency in Swift with async/await
as well as Combine framework. It's inspired by Moya and Alamofire.
-
Start by creating your routes to the API:
enum FlightRoute { case getFlights case getFlight(String) case addFlight case updateFlight case deleteFlight(String) }
-
Extend your routes conforming to the
Route
protocol:extension FlightRoute: Route { var baseURL: URL { URL(string: "/api/flights")! } var path: String { switch self { case let .getFlight(id), let .deleteFlight(id): return "/\(id)" default: return "" } } var httpMethod: HttpMethod { switch self { case .getFlights, .getFlight: return .get case .addFlight: return .post case .updateFlight: return .put case .deleteFlight: return .delete } } var httpHeaders: HttpHeaders { .empty } var parameters: Parameters? { switch self { case .getFlights: return ["size": "20"] default: return nil } } var parameterEncoding: ParameterEncoding? { switch self { case .getFlights: return .url case .addFlight, .updateFlight: return .json default: return nil } }
-
Let the Pilot fly your routes:
let network = Pilot<FlightRoute>()
// Inside an asynchronous function do { let response = try await network.request(.getFlights) // do something useful } catch { // handle error }
To get the Decodable
model out of the response indicates the type of model and optionally provides your custom JSONDecoder
(Pilot uses the default one, which means with all default decoding strategies):
do {
let flights = try await network.request(.getFlights, target: [Flight].self, decoder: jsonDecoder)
// do something useful
} catch {
// handle error
}
network.request(.getFlights, target: [Flight].self, decoder: jsonDecoder)
.sink(receiveCompletion: { completion in
// ...
}, receiveValue: { flights in
// ...
})
.store(in: &cancellables)
If the API you're consuming supports JSON error, it can be returned as the associated value of PilotError.designated
:
do {
let flights = try await network.request(.getFlights, target: [Flight].self, failure: FlightApiError.self decoder: jsonDecoder)
// do something useful
} catch {
if case let .designated(apiError) = error as? PilotError {
// handle your designated `FlightApiError`
}
}
Just make sure your FlightApiError
conform to DesignatedError
(which is a typealias of Error & Decodable
)
network.request(.getFlights, target: [Flight].self, failure: FlightApiError.self, decoder: jsonDecoder)
.sink(receiveCompletion: { completion in
if case .failure(error) = completion, case let .designated(apiError) = error {
// The `apiError` is type of `FlightApiError`
}
}, receiveValue: { flights in
// ...
})
.store(in: &cancellables)
You can add Pilot to an Xcode project as a package dependency.
If you want to use Pilot in a SwiftPM project, it's as simple as adding it to a dependencies clause in your Package.swift
:
dependencies: [
.package(url: "https://github.com/Thieurom/Pilot", from: "0.5.0")
]