Skip to content

Instantly share code, notes, and snippets.

@Enriquecm
Last active May 5, 2022 04:15
Show Gist options
  • Save Enriquecm/bedf024d8a8f519eb1185fef14adcec3 to your computer and use it in GitHub Desktop.
Save Enriquecm/bedf024d8a8f519eb1185fef14adcec3 to your computer and use it in GitHub Desktop.
/* If you need to use **different decoders (JSON, URL, XML, etc)** with Alamofire,
the best and simplest way I found was using [XMLCoder][1].
- **Alamofire 5**
- **Swift 5**
-------------------
*/
[1]: https://github.com/MaxDesiatov/XMLCoder
// Sample: simple model
import Foundation
class ReportModel: Codable {
var connections: ConnectionModel?
var notifications: NotificationsModel?
enum CodingKeys: String, CodingKey {
case connections
case notifications
}
}
// Sample: Nested model
import Foundation
class ConnectionModel: Codable {
var connections: [ConnectionDetailModel]?
enum CodingKeys: String, CodingKey {
case connections
case nestedConnections
}
required init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let nested = try? container.nestedContainer(keyedBy: CodingKeys.self, forKey: .connections)
connections = try? nested?.decodeIfPresent([ConnectionDetailModel].self, forKey: .nestedConnections)
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
var nested = container.nestedContainer(keyedBy: CodingKeys.self, forKey: .connections)
try? nested.encodeIfPresent(connections, forKey: .nestedConnections)
}
}
class ConnectionDetailModel: Codable { }
// Sample: attributed and element
import Foundation
import XMLCoder
class NotificationsModel: Codable {
var total: Int?
var notifications: [NotificationModel]?
enum CodingKeys: String, CodingKey {
case total
case notifications
}
static func nodeDecoding(for key: CodingKey) -> XMLDecoder.NodeDecoding {
switch key {
case CodingKeys.total:
return .attribute
default:
return .element
}
}
}
class NotificationModel: Codable {}
import Alamofire
import Foundation
import XMLCoder
extension Service {
struct reports {
@discardableResult
static func xmlReport(name: String, completion: @escaping ((Result<ReportModel, NetworkError>) -> Void)) -> ServiceRequest {
let baseURL = Service.Environments.baseURL
var url = baseURL.appendingPathComponent("reports")
url.appendPathComponent(name)
// For example, the final URL is: https://mybaseurl.com/reports/{name}
// Custom headers if needed
var headers = HTTPHeaders.default
headers.add(HTTPHeader.accept("application/xml"))
return Service.default.request(url,
method: .get,
decoder: XMLDecoder(),
headers: headers,
completion: completion)
}
extension Service {
struct Environments {
static let baseURL = URL(string: "https://mybaseurl.com")!
}
}
import Alamofire
import Foundation
typealias NetworkError = Error // TODO: Create your own error
class Service {
private let session: Session
init(session: Session? = nil) {
self.session = session ?? Session()
}
func request<T: Codable>(_ url: URLConvertible,
method: HTTPMethod,
parameters: Parameters? = nil,
encoding: ParameterEncoding = URLEncoding.default,
decoder: DataDecoder = JSONDecoder(),
headers: HTTPHeaders? = .default,
completion: @escaping (Swift.Result<T, NetworkError>) -> Void) -> ServiceRequestProtocol {
let dataRequest = session.request(url,
method: method,
parameters: parameters,
encoding: encoding,
headers: headers)
dataRequest.validate().responseDecodable(of: T.self, decoder: decoder) { (response: DataResponse<T, AFError>) in
switch response.result {
case .success(let model):
completion(.success(model))
case .failure(let error):
completion(.failure(error))
}
}
return dataRequest
}
}
import Alamofire
import Foundation
protocol ServiceRequestProtocol {
@discardableResult func cancel() -> Self
@discardableResult func resume() -> Self
@discardableResult func suspend() -> Self
}
extension DataRequest: ServiceRequestProtocol { }
extension DownloadRequest: ServiceRequestProtocol { }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment