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"
}
}