Skip to content

Instantly share code, notes, and snippets.

@cruinh
Last active October 12, 2017 16:19
Show Gist options
  • Save cruinh/8956eda709f5323e6a91153918fa7182 to your computer and use it in GitHub Desktop.
Save cruinh/8956eda709f5323e6a91153918fa7182 to your computer and use it in GitHub Desktop.
Generic Codable Parsing
func parseResponse(data: Data?, response:URLResponse?, completion:(_ decodedResponse: Codable)->() ) {
//Handle the first matching response
if let decodedResponse = Decoder<User>.decode(data, response) { completion(decodedResponse) ; return }
if let decodedResponse = Decoder<Place>.decode(data, response) { completion(decodedResponse) ; return }
if let decodedResponse = Decoder<Thing>.decode(data, response) { completion(decodedResponse) ; return }
}
struct User: Codable, EndpointData {
static var endpoint : String { return "/user" }
static var detailEndpoint : Bool { return false } //this would be true if the struct was meant for an endpoint like /user/12345
var username : String
}
struct Place : Codable, EndpointData {
static var endpoint : String { return "/place" }
static var detailEndpoint : Bool { return false }
var address: String
}
struct Thing : Codable, EndpointData {
static var endpoint : String { return "/thing" }
static var detailEndpoint : Bool { return false }
var weight: Float
}
protocol EndpointData : Codable {
static var endpoint : String {get}
static var detailEndpoint : Bool {get}
static func matches(response: URLResponse) -> Bool
}
extension EndpointData {
static func matches(response: URLResponse) -> Bool {
guard let url : URL = response.url else { return false }
let urlString = url.absoluteString
if detailEndpoint == false {
return urlString.hasSuffix(endpoint)
} else {
return urlString.contains(endpoint)
}
return false
}
}
struct Decoder<T:EndpointData> {
static func decode(_ data: Data?, _ response: URLResponse?) -> T? {
guard let data = data,
let response = response,
T.matches(response: response) else { return nil }
let jsonDecoder = JSONDecoder()
do {
let result = try jsonDecoder.decode(T.self, from: data) as? T
return result
} catch {
return nil
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment