Skip to content

Instantly share code, notes, and snippets.

@willard1218
Last active March 1, 2018 12:16
Show Gist options
  • Save willard1218/958eb31fa49b2c15ca1fdbae75c5b40d to your computer and use it in GitHub Desktop.
Save willard1218/958eb31fa49b2c15ca1fdbae75c5b40d to your computer and use it in GitHub Desktop.
Protocol-Oriented Programming — Protocol Extension
@willard1218
Copy link
Author

willard1218 commented Feb 28, 2018

//: Playground - noun: a place where people can play

import UIKit

protocol Request : RequestHeader, RequestBody, ResponseBody {
    var baseURL: String {get}
    var path: String {get}
    var method: String {get}
}

fileprivate func sendURLRequest(request: URLRequest, success: @escaping(Data) -> (), failure: @escaping(String) -> ()) {
    let session = URLSession.shared
    
    session.dataTask(with: request) { (data, response, error) in
        if error != nil {
            failure(error!.localizedDescription)
            return
        }
        
        if let data = data {
            success(data)
            return
        }
        
        failure("data is nil")
        
        }.resume()
}


extension Request {
    var baseURL: String {
        return "http://api.xxx.com"
    }
    var body: Data? {
        return nil
    }
}

protocol RequestHeader {
    var headers: [String : String] { get }
}

protocol FormURLEncodedRequestHeader : RequestHeader {}

extension FormURLEncodedRequestHeader {
    var headers: [String : String] {
        return ["Content-Type" : "application/x-www-form-urlencoded; charset=UTF-8"]
    }
}

protocol JSONRequestHeader : RequestHeader {}

extension JSONRequestHeader {
    var headers: [String : String] {
        return ["Content-Type" : "application/json"]
    }
}

extension Request {
    func buildRequest() -> URLRequest {
        let urlString = "\(baseURL)/\(path)"
        let url = URL(string: urlString)
        var request = URLRequest(url: url!)
        
        for (key, value) in headers {
            print(value)
            request.setValue(value, forHTTPHeaderField: key)
        }
        
        request.httpMethod = method
        request.httpBody = body
        
        return request
    }
}


protocol RequestBody {
    func buildRequestBody() -> Data?
}

protocol IgnorableRequestBody : RequestBody {}

extension IgnorableRequestBody {
    func buildRequestBody() -> Data? {
        return nil
    }
}


protocol JSONRequestBody : RequestBody {
    var bodyDict : [String : Any] {get set}
}

extension JSONRequestBody {
    func buildRequestBody() -> Data? {
        do {
            let data = try JSONSerialization.data(withJSONObject: bodyDict, options: [])
            return data
        } catch let err {
            print(err)
        }
        
        return nil
    }
}

protocol JSONArrayRequestBody : RequestBody {
    var bodyDicts : [[String : Any]] {get set}
}

extension JSONArrayRequestBody {
    func buildRequestBody() -> Data? {
        do {
            let data = try JSONSerialization.data(withJSONObject: bodyDicts, options: [])
            return data
        } catch let err {
            print(err)
        }
        
        return nil
    }
}


protocol ResponseBody {
    var urlRequest : URLRequest {get}
}

extension ResponseBody where Self : Request {
    var urlRequest : URLRequest {
        print("ResponseBody urlRequest")
        return buildRequest()
    }
}

protocol IgnorableResponseBody : ResponseBody {}

extension IgnorableResponseBody {
    func sendRequest(success: @escaping() -> (),
                     failure: @escaping(String) -> ()) {
        sendURLRequest(request: urlRequest, success: { (result) in
            success()
        }, failure: failure)
        
    }
}

protocol JSONResponseBody : ResponseBody {}

extension JSONResponseBody {
    func sendRequest(success: @escaping([String: Any]) -> (),
                     failure: @escaping(String) -> ()) {
        sendURLRequest(request: urlRequest, success: { (data) in
            do {
                print("ffff")
                if let jsonDictionary = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as? [String: Any] {
                    success(jsonDictionary)
                }
            }
            catch _ {
                failure("jsonParseError")
            }
        }, failure: failure)
        
    }
}

protocol JSONModelResponseBody : ResponseBody {
    associatedtype ResponseBodyModel : Decodable
}

extension JSONModelResponseBody {
    func sendRequest(success: @escaping(ResponseBodyModel) -> (),
                     failure: @escaping(String) -> ()) {
        sendURLRequest(request: urlRequest, success: { (data) in
            let decoder = JSONDecoder()
            do {
                print(ResponseBodyModel.self)
                let model = try decoder.decode(ResponseBodyModel.self, from: data)
                success(model)
            }
            catch {
                print("decoder error")
            }
        }, failure: failure)
        
    }
}


//struct FetchAllUsersRequest : Request, JSONRequestHeader {
//    let path = "users"
//    let method = "get"
//}
//
//FetchAllUsersRequest().sendRequest(success: { (users) in
//    print(users)
//}) { (failure) in
//    print(failure)
//}
//
struct UpdateUserNameRequest : Request, JSONRequestHeader, JSONRequestBody, IgnorableResponseBody {
    var bodyDict: [String : Any]
    
    let path = "user"
    let method = "post"
}

struct UpdateUserNameRequest2 : Request, JSONRequestHeader, JSONRequestBody, JSONResponseBody {
    var bodyDict: [String : Any]
    
    let path = "user"
    let method = "post"
}

//UpdateUserNameRequest(bodyDict: ["name":"David", "id": 4]).sendRequest(success: {
//    print("success")
//}) { (failure) in
//    print(failure)
//}
//
//UpdateUserNameRequest2(bodyDict: ["name":"David", "id": 4]).sendRequest(success: { (dict) in
//
//}) { (failure) in
//    print(failure)
//}
//UpdateUserNameRequest(bodyDict: ["name":"David", "id": 4]).sendRequest(success: { (result) in
//    print(result)
//}) { (failure) in
//    print(failure)
//}
struct User : Decodable {
    var name: String
}

struct findUser : Request, JSONRequestHeader, IgnorableRequestBody, JSONModelResponseBody {
    typealias ResponseBodyModel = User
    
    let baseURL: String = "https://gist.githubusercontent.com/willard1218/5c96aae277c5c5d2f271b8ab1e6ca7c2/raw/b5ee5dcd40d875f791c47a043f810d363fa833e8"
    let path = "user.json"
    let method = "get"
}
print(324324)

findUser().sendRequest(success: { (user) in
    print(user)
    
}) { (fa) in
    
}
import XCPlayground

XCPSetExecutionShouldContinueIndefinitely(continueIndefinitely: true)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment