Last active
August 29, 2015 14:17
-
-
Save akirahrkw/b688fd6dd7fa63a3204a to your computer and use it in GitHub Desktop.
simple JSON API library by swift using generics
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Playground - noun: a place where people can play | |
import UIKit | |
import XCPlayground | |
//// extension | |
extension String { | |
func urlEncode() -> String! { | |
let str = self.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLQueryAllowedCharacterSet()) | |
return (str != nil) ? str : "" | |
} | |
} | |
extension Dictionary { | |
func urlEncodedString() -> String { | |
var params = [String]() | |
for (key, value) in self { | |
let v = "\(value)".urlEncode() | |
params.append("\(key)=\(v)") | |
} | |
return "&".join(params) | |
} | |
mutating func urlMapping(url: String) -> String { | |
var mappedUrl = url | |
for (key, value) in self { | |
let found = url.stringByReplacingOccurrencesOfString(":\(key)", withString: "\(value)", options: nil, range: nil) | |
if found != url { | |
mappedUrl = found | |
self.removeValueForKey(key) | |
} | |
} | |
return mappedUrl | |
} | |
} | |
//// JSON API | |
public enum HttpMethod : String { | |
case GET = "GET" | |
case POST = "POST" | |
case PUT = "PUT" | |
case DELETE = "DELETE" | |
} | |
public protocol JsonCache { | |
func fetch<T>(url: APIRequest<T>, params: [String: AnyObject]?) -> T? | |
func save<T>(url: APIRequest<T>, params: [String: AnyObject]?, object: T) | |
func remove<T>(url: APIRequest<T>, params: [String: AnyObject]?) -> T? | |
} | |
public class APIRequest<T> { | |
var method: HttpMethod | |
var url: String | |
var mapper: (Dictionary<String, AnyObject>) -> T | |
var completionHandler: ((T) -> ())? | |
var errorHandler: ((Dictionary<String, AnyObject>, NSError) -> ())? | |
init(url: String, method: HttpMethod, jsonMapper: (Dictionary<String, AnyObject>) -> T, completionHandler: (T) -> ()){ | |
self.url = url | |
self.method = method | |
self.mapper = jsonMapper | |
self.completionHandler = completionHandler | |
} | |
} | |
public class JsonAPI { | |
class func call<T>(request: APIRequest<T>, params: [String: AnyObject]?, cache: JsonCache?) -> T? { | |
var url = request.url | |
var mutableParams = params | |
if mutableParams != nil { | |
url = mutableParams!.urlMapping(url) | |
if request.method == .GET || request.method == .DELETE { | |
url = url + "?" + mutableParams!.urlEncodedString() | |
} | |
} | |
var req = NSMutableURLRequest(URL: NSURL(string: url)!, cachePolicy: .UseProtocolCachePolicy, timeoutInterval: 30.0) | |
req.HTTPMethod = request.method.rawValue | |
req.setValue("application/json", forHTTPHeaderField: "Content-Type") | |
if(request.method == .POST || request.method == .PUT) { | |
req.HTTPBody = mutableParams?.urlEncodedString().dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: true) | |
} | |
var session = NSURLSession.sharedSession() | |
var closure = { (data:NSData!, response:NSURLResponse!, error:NSError!) -> () in | |
var serializeError: NSError?; | |
let obj = NSJSONSerialization.JSONObjectWithData(data, options: .MutableLeaves, error: nil) as! Dictionary<String, AnyObject> | |
if error == nil { | |
if serializeError == nil { | |
let object: T = request.mapper(obj) | |
let httpRes = response as! NSHTTPURLResponse | |
if httpRes.statusCode >= 200 && httpRes.statusCode < 300 { | |
cache?.save(request, params: params, object: object) | |
request.completionHandler?(object) | |
} else { | |
// Http status error | |
request.errorHandler?(obj, error) | |
} | |
} else { | |
// NSJSONSerialization error | |
request.errorHandler?(obj, serializeError!) | |
} | |
} else { | |
// Request error | |
request.errorHandler?(obj, error) | |
} | |
} | |
var task = session.dataTaskWithRequest(req, completionHandler: closure) | |
task.resume() | |
var cached: T? = cache?.fetch(request, params: params) | |
return cached | |
} | |
class func call<T>(request: APIRequest<T>, params: [String: AnyObject]?) -> T? { | |
return self.call(request, params: params, cache: nil) | |
} | |
} | |
////// sample | |
public class Media { | |
var id: Int? | |
var caption: String? | |
} | |
var mapper = { (json: Dictionary<String, AnyObject>) -> [Media] in | |
var result = [Media]() | |
var list = json["data"] as! NSArray | |
var array = list as NSArray | |
for dic in array { | |
let obj = Media() | |
obj.id = dic["id"] as? Int | |
obj.caption = dic["caption"] as? String | |
result.append(obj) | |
} | |
return result | |
} | |
var handler = { (array: [Media]) -> () in | |
for val in array { | |
println(val) | |
} | |
} | |
var params = [String: AnyObject]() | |
params["id"] = 12 | |
params["title"] = "test" | |
var url = "http://eli.lvh.me:8000/api/media" | |
var request = APIRequest<[Media]>(url: url, method: .GET, jsonMapper: mapper, completionHandler: handler) | |
var cached = JsonAPI.call(request, params: params) | |
println(cached) | |
XCPSetExecutionShouldContinueIndefinitely() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment