Networker is a complex API management solution built on Alamofire (https://github.com/Alamofire/Alamofire). The motivation was to create a scalable API manager focused on simplicity and the ability to cover all possible scenarios when building API infrastructure into a project.
- Console logger for requests and responses
- Single file endpoints declaration
- Combine flow
Copy link and add it into:
XCode -> Swift Packages -> Add Package Dependecy
If you have Package.swift, simple copy:
dependencies: [
.package(url: "https://github.com/ace4seven/Networker", from: "0.0.1")
],
By default console logger is set in the INFO. To change the log level, just write the following code.
NetworkerConfiguration.logLevel = .info
- Info - Prints request url with response status and error when occurs.
- Error - Prints only when error occurs.
- Verbose - Prints everything including request body and response object
It is recommended to group all endpoints into a single enum file, which implements EndpointType protocol and define required attributes.
protocol EndpointType {
var path: String { get }
var method: HTTPMethod { get }
var parameters: Encodable? { get }
var headers: HTTPHeaders? { get }
func baseUrl() throws -> URL
}
- Path represent the second part of baseURL string
- Method - GET, POST, UPDATE, DELETE, PATCH ... [https://www.rfc-editor.org/rfc/rfc7231#section-4.3]
- Parameters cover body or URL query parameters, depends on HTTPMethod
- Headers for HTTP headers
enum Endpoint: EndpointType {
case swapiPlanets
var path: String {
switch self {
case .swapiPlanets: return "planets"
}
}
var method: HTTPMethod {
switch self {
case .swapiPlanets: return .get
}
}
func baseUrl() throws -> URL {
switch self {
case .swapiPlanets: return try "https://swapi.dev/api/".asURL()
}
}
}
The class is a wrapper for the Alamofire session object with a powerful call method, which transforms endpoint type into AnyPublisher containing Output as a Decodable object and Error object. Async await is also supported.
private let networker = Networker<Endpoint>()
func getPlantets() -> AnyPublisher<PlanetsDto, Error> {
networker
.call(endpoint: .swapiPlanets)
}
private let networker = Networker<Endpoint>()
func getPlantets() async -> Result<PlanetsDto, Error> {
await networker
.call(endpoint: .swapiPlanets)
}
Info Error is Alamofire error - AFError
API Resul is a enum which control lifecycle of the request progress.
ApiResult.created - idle state
ApiResult.loading - loading state, called immediately after a request is called
ApiResult.loaded - loaded state containing response object (200..<400 response codes)
ApiResult.error - error state containing AFError object (400+ response codes)
func getPlantets() -> AnyPublisher<ApiResult<PlanetsDto, Error>, Never> {
networker
.call(endpoint: .swapiPlanets)
.mapToApiResult()
}
All errors received from networker.call are NetworkerError enum type.
public enum NetworkerError: Error {
case afError(AFError, Data?)
case noInternet
}
There are two possible cases:
afError - Alamofire error with custom Payload data, if presented
noInternet - In case application is in offline mode
To cast Error in to the NetworkerError you can use provided extensions:
public extension Error {
var payloadData: Data? {
toNetworkerError()?.payloadData
}
func toNetworkerError() -> NetworkerError? {
self as? NetworkerError
}
}