matsuda
8/28/2016 - 11:16 PM

Alamofire + Himotoki

Alamofire + Himotoki

import Alamofire

///
/// MARK: - Session
///
public class Session {
    public static let sharedSession = Session()

    public let manager = Manager()

    public func sendRequest<T: RequestType where T.Response: ResponseType>(
        request: T,
        parameters: [String: AnyObject]?,
        completionHandler: Alamofire.Response<T.Response, Error> -> Void
        ) -> Request
    {
        let URL = request.baseURL.URLByAppendingPathComponent(request.path)
        return manager
            .request(
                request.method,
                URL,
                parameters: ParameterBuilder.toJSON(parameters),
                headers: request.headers
            )
            .validate()
            .responseObject(completionHandler)
    }

    public class func sendRequest<T: RequestType where T.Response: ResponseType>(
        request: T,
        parameters: [String: AnyObject]?,
        completionHandler: Alamofire.Response<T.Response, Error> -> Void
        ) -> Request
    {
        return sharedSession.sendRequest(request,
                                         parameters: parameters,
                                         completionHandler: completionHandler)
    }
}
import Alamofire
import Himotoki

public extension Request {
    public static func DecodableResponseSerializer<T: Decodable>()
        -> ResponseSerializer<T, Error>
    {
        return ResponseSerializer<T, Error> { request, response, data, error in
            guard error == nil else { return .Failure(.Network(error: error!)) }
            let JSONResponseSerializer = Request.JSONResponseSerializer(options: .AllowFragments)
            let result = JSONResponseSerializer.serializeResponse(request, response, data, error)
            switch result {
            case .Success(let value):
                do {
                    return .Success(try decodeValue(value))
                } catch {
                    return .Failure(.ObjectDecode(error: error))
                    // return .Failure(.ObjectSerialization(reason: "JSON could not be serialized into response object: \(value)"))
                }
            case .Failure(let error):
                return .Failure(.JSONSerialization(error: error))
            }
        }
    }

    func responseObject<T: Decodable>(
        completionHandler: Alamofire.Response<T, Error> -> Void)
        -> Self
    {
        return response(responseSerializer: Request.DecodableResponseSerializer(), completionHandler: completionHandler)
    }

    public static func ObjectResponseSerializer<T: ResponseType where T: Decodable>()
        -> ResponseSerializer<T, Error>
    {
        return ResponseSerializer<T, Error> { request, response, data, error in
            let Serializer: ResponseSerializer<T, Error> = Request.DecodableResponseSerializer()
            let result = Serializer.serializeResponse(request, response, data, error)
            switch result {
            case .Success(let value):
                if value.status.isSuccess {
                    return result
                } else {
                    return .Failure(.ResponseInvalid(status: value.status))
                }
            case .Failure:
                return result
            }
        }
    }

    public func responseObject<T: ResponseType where T: Decodable>(
        completionHandler: Alamofire.Response<T, Error> -> Void)
        -> Self
    {
        return response(responseSerializer: Request.ObjectResponseSerializer(), completionHandler: completionHandler)
    }
}
import Himotoki

///
/// MARK: - Status
///
public struct Status: Decodable {

    /// MARK: - StatusCode
    public enum StatusCode: String, Decodable {
        case success = "00"
        case failure = "10"
    }

    public let status: String
    public let messages: [String]?

    public static func decode(e: Extractor) throws -> Status {
        return try Status(status: e <| "status", messages: e <||? "messages")
    }

    var isSuccess: Bool {
        return StatusCode(rawValue: status) == .success
    }
}


///
/// MARK: - ResponseType
///
public protocol ResponseType {
    var status: Status { get }
}

public extension ResponseType {
}

///
/// MARK: - Response
///
public struct Response<Result: Decodable>: Decodable, ResponseType {
    public let status: Status
    public let results: Result?

    public static func decode(e: Extractor) throws -> Response<Result> {
        let status = try Status.decode(e)
        if !status.isSuccess {
            return Response(status: status, results: nil)
        }
        if let results = e.rawValue["results"] as? [String: AnyObject] where results.isEmpty {
            return Response(status: status, results: nil)
        }
        return try Response(status: status, results: e <|? "results")
    }
}
import Alamofire
import Himotoki

///
/// MARK: - RequestType
///
public protocol RequestType {
//public protocol RequestType: URLRequestConvertible {
    associatedtype Response: Decodable

    var baseURL: NSURL { get }
    var path: String { get }
    var method: Alamofire.Method { get }
    var headers: [String: String]? { get }
}

extension RequestType {
    public var baseURL: NSURL {
        return Configuration.baseURL
    }
    public var headers: [String: String]? {
        return nil
    }
    public var method: Alamofire.Method {
        return .POST
    }
    /*
    var URLRequest: NSMutableURLRequest {
        let URL = path.isEmpty ? baseURL : baseURL.URLByAppendingPathComponent(path)
        let mutableURLRequest = NSMutableURLRequest(URL: URL)
        mutableURLRequest.HTTPMethod = method.rawValue
        if let headers = headers {
            for (headerField, headerValue) in headers {
                mutableURLRequest.setValue(headerValue, forHTTPHeaderField: headerField)
            }
        }
        return mutableURLRequest
    }
    */
}
import Alamofire

public enum Error: ErrorType {
    case Network(error: NSError)
    case JSONSerialization(error: NSError)
    case ObjectDecode(error: ErrorType)
    case ResponseInvalid(status: Status)
    // case ObjectSerialization(reason: String)
}

extension Error {
    public func isCanceled() -> Bool {
        if case .Network(let nsError) = self where nsError.isCanceled() {
            return true
        }
        return false
    }
}


///
/// MARK: - NSError
///
extension NSError {
    public func isCanceled() -> Bool {
        return domain == NSURLErrorDomain
            && code == NSURLErrorCancelled
    }
}
import Foundation

public struct Configuration {
    public static var baseURL: NSURL {
        return NSURL(string: "\(scheme)://\(host)\(scriptName)")!
    }

    private static var scheme: String {
        return useSSL ? "https" : "http"
    }

    private static var useSSL: Bool {
        #if DEBUG
            return false
        #else
            return true
        #endif
    }

    private static var scriptName: String {
        return "/api"
    }

    public static var host: String {
        return "example.com"
    }
}