Skip to content

Instantly share code, notes, and snippets.

@akirahrkw
Last active August 29, 2015 14:17
Show Gist options
  • Save akirahrkw/b688fd6dd7fa63a3204a to your computer and use it in GitHub Desktop.
Save akirahrkw/b688fd6dd7fa63a3204a to your computer and use it in GitHub Desktop.
simple JSON API library by swift using generics
// 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