Commit 4222277c authored by Mauro E. Bender's avatar Mauro E. Bender

Close #11 - Update code to Swift 3

parent 577a5f81
......@@ -27,9 +27,9 @@ TODO: Add long description of the pod here.
s.author = { 'Mauro E. Bender' => 'mauro@theamalgama.com' }
s.source = { :git => 'https://git.theamalgama.com/ios/api.git', :tag => s.version.to_s }
s.ios.deployment_target = '8.0'
s.ios.deployment_target = '9.0'
s.source_files = 'Api/Classes/**/*'
s.dependency 'Alamofire', '~> 3.4'
s.dependency 'Alamofire', '~> 4.0.0'
end
......@@ -8,70 +8,70 @@
import Alamofire
public typealias ApiMethod = Alamofire.Method
public typealias ApiMethod = Alamofire.HTTPMethod
public class Api {
let baseURL: NSURL
open class Api {
let baseURL: URL
let apiPath: String
var apiURL: NSURL { return baseURL.URLByAppendingPathComponent( apiPath ) }
var apiURL: URL { return baseURL.appendingPathComponent( apiPath ) }
public init( baseURL: NSURL, apiPath: String ) {
public init( baseURL: URL, apiPath: String ) {
self.baseURL = baseURL
self.apiPath = apiPath
}
// RESOURCE
public func resource( path: String ) -> Resource {
open func resource( _ path: String ) -> Resource {
return Resource( api: self, path: path )
}
// REQUESTS
public func request( method: ApiMethod, path: String,
parameters: [String: AnyObject]? = nil, encoding: ParameterEncoding = .URL,
headers: [String: String]? = nil, completion: Response<AnyObject, NSError> -> Void )
open func request( _ method: ApiMethod, path: String,
parameters: [String: AnyObject]? = nil, encoding: ParameterEncoding = URLEncoding.default,
headers: [String: String]? = nil, completion: @escaping (DataResponse<Any>) -> Void )
{
Alamofire.request( method, urlForPath( path ).absoluteString, parameters: parameters,
Alamofire.request( urlForPath( path ).absoluteString, method: method, parameters: parameters,
encoding: encoding, headers: headers ).responseJSON( completionHandler: completion )
}
public func get( path: String, parameters: [String: AnyObject]? = nil, encoding: ParameterEncoding = .URL,
headers: [String: String]? = nil, completion: Response<AnyObject, NSError> -> Void )
open func get( _ path: String, parameters: [String: AnyObject]? = nil, encoding: ParameterEncoding = URLEncoding.default,
headers: [String: String]? = nil, completion: @escaping (DataResponse<Any>) -> Void )
{
return request( .GET, path: path, parameters: parameters, encoding: encoding,
return request( .get, path: path, parameters: parameters, encoding: encoding,
headers: headers, completion: completion)
}
public func post( path: String, parameters: [String: AnyObject]? = nil, encoding: ParameterEncoding = .URL,
headers: [String: String]? = nil, completion: Response<AnyObject, NSError> -> Void )
open func post( _ path: String, parameters: [String: AnyObject]? = nil, encoding: ParameterEncoding = URLEncoding.default,
headers: [String: String]? = nil, completion: @escaping (DataResponse<Any>) -> Void )
{
return request( .POST, path: path, parameters: parameters, encoding: encoding,
return request( .post, path: path, parameters: parameters, encoding: encoding,
headers: headers, completion: completion)
}
public func put( path: String, parameters: [String: AnyObject]? = nil, encoding: ParameterEncoding = .URL,
headers: [String: String]? = nil, completion: Response<AnyObject, NSError> -> Void )
open func put( _ path: String, parameters: [String: AnyObject]? = nil, encoding: ParameterEncoding = URLEncoding.default,
headers: [String: String]? = nil, completion: @escaping (DataResponse<Any>) -> Void )
{
return request( .PUT, path: path, parameters: parameters, encoding: encoding,
return request( .put, path: path, parameters: parameters, encoding: encoding,
headers: headers, completion: completion)
}
public func patch( path: String, parameters: [String: AnyObject]? = nil, encoding: ParameterEncoding = .URL,
headers: [String: String]? = nil, completion: Response<AnyObject, NSError> -> Void )
open func patch( _ path: String, parameters: [String: AnyObject]? = nil, encoding: ParameterEncoding = URLEncoding.default,
headers: [String: String]? = nil, completion: @escaping (DataResponse<Any>) -> Void )
{
return request( .PATCH, path: path, parameters: parameters, encoding: encoding,
return request( .patch, path: path, parameters: parameters, encoding: encoding,
headers: headers, completion: completion)
}
public func delete( path: String, parameters: [String: AnyObject]? = nil, encoding: ParameterEncoding = .URL,
headers: [String: String]? = nil, completion: Response<AnyObject, NSError> -> Void )
open func delete( _ path: String, parameters: [String: AnyObject]? = nil, encoding: ParameterEncoding = URLEncoding.default,
headers: [String: String]? = nil, completion: @escaping (DataResponse<Any>) -> Void )
{
return request( .DELETE, path: path, parameters: parameters, encoding: encoding,
return request( .delete, path: path, parameters: parameters, encoding: encoding,
headers: headers, completion: completion)
}
func urlForPath( path: String ) -> NSURL {
return apiURL.URLByAppendingPathComponent( path )
func urlForPath( _ path: String ) -> URL {
return apiURL.appendingPathComponent( path )
}
}
......@@ -80,4 +80,4 @@ extension Api: Equatable {}
public func ==(lhs: Api, rhs: Api) -> Bool {
return lhs.baseURL == rhs.baseURL && lhs.apiPath == rhs.apiPath
}
\ No newline at end of file
}
......@@ -8,22 +8,30 @@
import Alamofire
public enum ApiError: ErrorType {
case Network( error: NSError, response: NSURLResponse )
case JSONSerialization(error: NSError)
case Unknown( error: NSError )
public enum ApiError: Error {
case network( error: Error, response: DataResponse<Any> )
case invalidURL(url: URLConvertible)
case jsonSerialization(error: AFError)
case unknown( error: Error )
}
public extension ApiError {
init( response: Response<AnyObject, NSError> ) {
init( response: DataResponse<Any> ) {
let error = response.result.error!
if let statusCode = response.response?.statusCode where !(200...299).contains( statusCode ) {
self = .Network( error: error, response: response.response! )
} else if error.code == -6006 {
self = .JSONSerialization( error: error )
if let statusCode = response.response?.statusCode , !(200...299).contains( statusCode ) {
self = .network( error: error, response: response )
} else if let error = error as? AFError {
switch error {
case .responseSerializationFailed(_):
self = .jsonSerialization( error: error )
case .invalidURL(let url):
self = .invalidURL(url: url)
default:
self = .unknown(error: error)
}
} else {
self = .Unknown( error: error )
self = .unknown(error: error)
}
}
}
\ No newline at end of file
}
......@@ -9,15 +9,15 @@
import Alamofire
public enum ApiResult<Value> {
case Success(Value)
case Failure(ApiError)
case success(Value)
case failure(ApiError)
/// Returns `true` if the result is a success, `false` otherwise.
public var isSuccess: Bool {
switch self {
case .Success:
case .success:
return true
case .Failure:
case .failure:
return false
}
}
......@@ -30,9 +30,9 @@ public enum ApiResult<Value> {
/// Returns the associated value if the result is a success, `nil` otherwise.
public var value: Value? {
switch self {
case .Success(let value):
case .success(let value):
return value
case .Failure:
case .failure:
return nil
}
}
......@@ -40,24 +40,24 @@ public enum ApiResult<Value> {
/// Returns the associated error value if the result is a failure, `nil` otherwise.
public var error: ApiError? {
switch self {
case .Success:
case .success:
return nil
case .Failure(let error):
case .failure(let error):
return error
}
}
}
public enum EmptyResult {
case Success
case Failure(ApiError)
case success
case failure(ApiError)
/// Returns `true` if the result is a success, `false` otherwise.
public var isSuccess: Bool {
switch self {
case .Success:
case .success:
return true
case .Failure:
case .failure:
return false
}
}
......@@ -70,9 +70,9 @@ public enum EmptyResult {
/// Returns the associated error value if the result is a failure, `nil` otherwise.
public var error: ApiError? {
switch self {
case .Success:
case .success:
return nil
case .Failure(let error):
case .failure(let error):
return error
}
}
......@@ -85,9 +85,9 @@ extension ApiResult: CustomStringConvertible {
/// success or failure.
public var description: String {
switch self {
case .Success:
case .success:
return "SUCCESS"
case .Failure:
case .failure:
return "FAILURE"
}
}
......@@ -98,9 +98,9 @@ extension ApiResult: CustomDebugStringConvertible {
/// success or failure in addition to the value or error.
public var debugDescription: String {
switch self {
case .Success(let value):
case .success(let value):
return "SUCCESS: \(value)"
case .Failure(let error):
case .failure(let error):
return "FAILURE: \(error)"
}
}
......@@ -109,63 +109,70 @@ extension ApiResult: CustomDebugStringConvertible {
// MARK: Factories
// FIXME: Encapsulate
public func itemResult<T: JSONSerializable>( response: Response<AnyObject, NSError>,
func resultJSON (_ responseData: Any?, keyPath: String?) -> Any? {
guard let keyPath = keyPath else { return responseData }
guard let responseData = responseData as? [String: Any] else { return nil }
return responseData[ keyPath ];
}
public func itemResult<T: JSONSerializable>( _ response: DataResponse<Any>,
keyPath: String? ) -> ApiResult< T? >
{
switch(response.result) {
case .Success(let JSON):
if let itemJSON = (keyPath != nil ? JSON[ keyPath! ] : JSON) as? [String : AnyObject] {
return .Success( T( fromJSON: itemJSON ) )
case .success(let JSON):
if let itemJSON = resultJSON(JSON, keyPath: keyPath) as? [String : AnyObject] {
return .success( T( fromJSON: itemJSON ) )
} else {
return .Success( nil )
return .success( nil )
}
case .Failure(let error):
return .Failure( ApiError( response: response ) )
case .failure(_):
return .failure( ApiError( response: response ) )
}
}
public func emptyResult( response: Response<AnyObject, NSError> ) -> EmptyResult {
public func emptyResult( _ response: DataResponse<Any> ) -> EmptyResult {
switch(response.result) {
case .Success:
return .Success
case .Failure(let error):
return .Failure( ApiError( response: response ) )
case .success:
return .success
case .failure(_):
return .failure( ApiError( response: response ) )
}
}
public func listResult<T: JSONSerializable>( response: Response<AnyObject, NSError>,
public func listResult<T: JSONSerializable>( _ response: DataResponse<Any>,
keyPath: String? ) -> ApiResult< [T]? >
{
switch(response.result) {
case .Success(let JSON):
if let listJSON = (keyPath != nil ? JSON[ keyPath! ] : JSON) as? [[String : AnyObject]] {
case .success(let JSON):
if let listJSON = resultJSON(JSON, keyPath: keyPath) as? [[String : AnyObject]] {
let list = listJSON.map { T( fromJSON: $0 ) }
return .Success( list )
return .success( list )
} else {
return .Success( nil )
return .success( nil )
}
case .Failure(let error):
return .Failure( ApiError( response: response ) )
case .failure(_):
return .failure( ApiError( response: response ) )
}
}
public func paginatedListResult<T: JSONSerializable>( response: Response<AnyObject, NSError>,
public func paginatedListResult<T: JSONSerializable>( _ response: DataResponse<Any>,
keyPath: String?, paginationKeyPath: String? ) -> ApiResult< ([T], Pagination)? >
{
switch(response.result) {
case .Success(let JSON):
if let listJSON = (keyPath != nil ? JSON[ keyPath! ] : JSON) as? [[String : AnyObject]],
let paginationJSON = (paginationKeyPath != nil ? JSON[ paginationKeyPath! ] : JSON) as? [String : AnyObject]
case .success(let JSON):
if let listJSON = resultJSON(JSON, keyPath: keyPath) as? [[String : AnyObject]],
let paginationJSON = resultJSON(JSON, keyPath: paginationKeyPath) as? [String : AnyObject]
{
let list = listJSON.map { T( fromJSON: $0 ) }
let pagination = Pagination( fromJSON: paginationJSON )
return .Success( (list, pagination) )
return .success( (list, pagination) )
} else {
return .Success( nil )
return .success( nil )
}
case .Failure(let error):
return .Failure( ApiError( response: response ) )
case .failure(_):
return .failure( ApiError( response: response ) )
}
}
......@@ -13,11 +13,11 @@ public protocol JSONSerializable {
func toJSON() -> [ String: AnyObject ]
}
public class Resource {
public let api: Api
public let path: String
public var responseKeyPath: String? = "response"
public var paginationKeyPath: String? = "pagination"
open class Resource {
open let api: Api
open let path: String
open var responseKeyPath: String? = "response"
open var paginationKeyPath: String? = "pagination"
init( api: Api, path: String ) {
self.api = api
......@@ -27,71 +27,71 @@ public class Resource {
// MARK: REQUESTS
extension Resource {
public func request( method: ApiMethod, path: String? = nil,
parameters: [String: AnyObject]? = nil, encoding: ParameterEncoding = .URL,
headers: [String: String]? = nil, completion: Response<AnyObject, NSError> -> Void )
public func request( _ method: ApiMethod, path: String? = nil,
parameters: [String: AnyObject]? = nil, encoding: ParameterEncoding = URLEncoding.default,
headers: [String: String]? = nil, completion: @escaping (DataResponse<Any>) -> Void )
{
let requestPath = path != nil ? "\(self.path)/\(path!)" : self.path
api.request( method, path: requestPath, parameters: parameters, encoding: encoding,
headers: headers, completion: completion )
}
public func get( path: String? = nil, parameters: [String: AnyObject]? = nil, encoding: ParameterEncoding = .URL,
headers: [String: String]? = nil, completion: Response<AnyObject, NSError> -> Void )
public func get( _ path: String? = nil, parameters: [String: AnyObject]? = nil, encoding: ParameterEncoding = URLEncoding.default,
headers: [String: String]? = nil, completion: @escaping (DataResponse<Any>) -> Void )
{
return request( .GET, path: path, parameters: parameters, encoding: encoding,
return request( .get, path: path, parameters: parameters, encoding: encoding,
headers: headers, completion: completion)
}
public func post( path: String? = nil, parameters: [String: AnyObject]? = nil, encoding: ParameterEncoding = .URL,
headers: [String: String]? = nil, completion: Response<AnyObject, NSError> -> Void )
public func post( _ path: String? = nil, parameters: [String: AnyObject]? = nil, encoding: ParameterEncoding = URLEncoding.default,
headers: [String: String]? = nil, completion: @escaping (DataResponse<Any>) -> Void )
{
return request( .POST, path: path, parameters: parameters, encoding: encoding,
return request( .post, path: path, parameters: parameters, encoding: encoding,
headers: headers, completion: completion)
}
public func put( path: String? = nil, parameters: [String: AnyObject]? = nil, encoding: ParameterEncoding = .URL,
headers: [String: String]? = nil, completion: Response<AnyObject, NSError> -> Void )
public func put( _ path: String? = nil, parameters: [String: AnyObject]? = nil, encoding: ParameterEncoding = URLEncoding.default,
headers: [String: String]? = nil, completion: @escaping (DataResponse<Any>) -> Void )
{
return request( .PUT, path: path, parameters: parameters, encoding: encoding,
return request( .put, path: path, parameters: parameters, encoding: encoding,
headers: headers, completion: completion)
}
public func patch( path: String? = nil, parameters: [String: AnyObject]? = nil, encoding: ParameterEncoding = .URL,
headers: [String: String]? = nil, completion: Response<AnyObject, NSError> -> Void )
public func patch( _ path: String? = nil, parameters: [String: AnyObject]? = nil, encoding: ParameterEncoding = URLEncoding.default,
headers: [String: String]? = nil, completion: @escaping (DataResponse<Any>) -> Void )
{
return request( .PATCH, path: path, parameters: parameters, encoding: encoding,
return request( .patch, path: path, parameters: parameters, encoding: encoding,
headers: headers, completion: completion)
}
public func delete( path: String? = nil, parameters: [String: AnyObject]? = nil, encoding: ParameterEncoding = .URL,
headers: [String: String]? = nil, completion: Response<AnyObject, NSError> -> Void )
public func delete( _ path: String? = nil, parameters: [String: AnyObject]? = nil, encoding: ParameterEncoding = URLEncoding.default,
headers: [String: String]? = nil, completion: @escaping (DataResponse<Any>) -> Void )
{
return request( .DELETE, path: path, parameters: parameters, encoding: encoding,
return request( .delete, path: path, parameters: parameters, encoding: encoding,
headers: headers, completion: completion)
}
}
// MARK: CRUD
extension Resource {
public func item<T: JSONSerializable>( id: AnyObject, parameters: [ String: String ]? = nil,
headers: [ String: String]? = nil, completion: ( ( ApiResult< T? > ) -> Void ) )
public func item<T: JSONSerializable>( _ id: Any, parameters: [ String: AnyObject ]? = nil,
headers: [ String: String]? = nil, completion: @escaping ( ( ApiResult< T? > ) -> Void ) )
{
get( "\(id)", parameters: parameters, headers: headers ) { response in
completion( itemResult( response, keyPath: self.responseKeyPath ) )
}
}
public func list<T: JSONSerializable>( parameters: [ String: String ]? = nil,
headers: [ String: String]? = nil, completion: ( ( ApiResult< [T]? > ) -> Void ) )
public func list<T: JSONSerializable>( _ parameters: [ String: AnyObject ]? = nil,
headers: [ String: String]? = nil, completion: @escaping ( ( ApiResult< [T]? > ) -> Void ) )
{
get( parameters: parameters, headers: headers ) { response in
completion( listResult( response, keyPath: self.responseKeyPath ) )
}
}
public func paginate<T: JSONSerializable>( parameters: [ String: String ]? = nil, headers: [ String: String]? = nil,
completion: ( ( ApiResult< ([T], Pagination)? > ) -> Void ) )
public func paginate<T: JSONSerializable>( _ parameters: [ String: AnyObject ]? = nil, headers: [ String: String]? = nil,
completion: @escaping ( ( ApiResult< ([T], Pagination)? > ) -> Void ) )
{
get( parameters: parameters, headers: headers ) { response in
completion( paginatedListResult( response,
......@@ -99,9 +99,9 @@ extension Resource {
}
}
public func create<T: JSONSerializable>( item: T, parameters: [ String: String ]? = nil,
headers: [ String: String]? = nil, encoding: ParameterEncoding = .JSON,
completion: ( ( ApiResult< T? > ) -> Void ) )
public func create<T: JSONSerializable>( _ item: T, parameters: [ String: AnyObject ]? = nil,
headers: [ String: String]? = nil, encoding: ParameterEncoding = JSONEncoding.default,
completion: @escaping ( ( ApiResult< T? > ) -> Void ) )
{
var requestParameters = item.toJSON()
if parameters != nil { requestParameters += parameters! }
......@@ -111,9 +111,9 @@ extension Resource {
}
}
public func edit<T: JSONSerializable>( id: AnyObject, item: T, parameters: [ String: String ]? = nil,
headers: [ String: String]? = nil, encoding: ParameterEncoding = .JSON,
completion: ( ( ApiResult< T? > ) -> Void ) )
public func edit<T: JSONSerializable>( _ id: Any, item: T, parameters: [ String: AnyObject ]? = nil,
headers: [ String: String]? = nil, encoding: ParameterEncoding = JSONEncoding.default,
completion: @escaping ( ( ApiResult< T? > ) -> Void ) )
{
var requestParameters = item.toJSON()
if parameters != nil { requestParameters += parameters! }
......@@ -123,8 +123,8 @@ extension Resource {
}
}
public func destroy( id: AnyObject, parameters: [ String: String ]? = nil,
headers: [ String: String]? = nil, completion: ( ( EmptyResult ) -> Void ) )
public func destroy( _ id: Any, parameters: [ String: AnyObject ]? = nil,
headers: [ String: String]? = nil, completion: @escaping ( ( EmptyResult ) -> Void ) )
{
delete( "\(id)", parameters: parameters, headers: headers ) { response in
completion( emptyResult( response ) )
......@@ -134,21 +134,21 @@ extension Resource {
// MARK: NESTED RESOURCES
extension Resource {
public func member( memberID: AnyObject ) -> Resource {
public func member( _ memberID: Any ) -> Resource {
let memberPath = resourceMemberPath( memberID )
return Resource( api: api, path: memberPath )
}
public func resource( resourcePath: String ) -> Resource {
public func resource( _ resourcePath: String ) -> Resource {
let nestedPath = nestedResourcePath( resourcePath )
return Resource( api: api, path: nestedPath )
}
func resourceMemberPath( memberId: AnyObject ) -> String {
func resourceMemberPath( _ memberId: Any ) -> String {
return "\(path)/\(memberId)"
}
func nestedResourcePath( nestedResourcePath: String ) -> String {
func nestedResourcePath( _ nestedResourcePath: String ) -> String {
return "\(path)/\(nestedResourcePath)"
}
}
......@@ -8,8 +8,8 @@
import Foundation
func += <K, V> (inout left: [K:V], right: [K:V]) {
func += <K, V> (left: inout [K:V], right: [K:V]) {
for (k, v) in right {
left.updateValue(v, forKey: k)
}
}
\ No newline at end of file
}
......@@ -219,14 +219,16 @@
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 0720;
LastUpgradeCheck = 0720;
LastUpgradeCheck = 0800;
ORGANIZATIONNAME = CocoaPods;
TargetAttributes = {
607FACCF1AFB9204008FA782 = {
CreatedOnToolsVersion = 6.3.1;
LastSwiftMigration = 0800;
};
607FACE41AFB9204008FA782 = {
CreatedOnToolsVersion = 6.3.1;
LastSwiftMigration = 0800;
TestTargetID = 607FACCF1AFB9204008FA782;
};
};
......@@ -427,8 +429,10 @@
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
......@@ -451,7 +455,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.3;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
......@@ -472,8 +476,10 @@
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_SUSPICIOUS_MOVE = YES;