Skip to content

Commit

Permalink
Merge pull request #22 from ishkawa/swift-1.2
Browse files Browse the repository at this point in the history
0.7.0
  • Loading branch information
ishkawa committed Apr 17, 2015
2 parents f137030 + be47537 commit b4244ce
Show file tree
Hide file tree
Showing 20 changed files with 114 additions and 122 deletions.
2 changes: 1 addition & 1 deletion .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
url = https://github.com/LlamaKit/LlamaKit.git
[submodule "Carthage/Checkouts/Assertions"]
path = Carthage/Checkouts/Assertions
url = https://github.com/ikesyo/Assertions.git
url = https://github.com/antitypical/Assertions.git
[submodule "Carthage/Checkouts/OHHTTPStubs"]
path = Carthage/Checkouts/OHHTTPStubs
url = https://github.com/ishkawa/OHHTTPStubs.git
2 changes: 1 addition & 1 deletion APIKit.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,5 @@ Pod::Spec.new do |s|
LICENSE
}

s.dependency "LlamaKit", "~> 0.5.0"
s.dependency "LlamaKit", "~> 0.6.0"
end
48 changes: 18 additions & 30 deletions APIKit/API.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,17 @@ import LlamaKit

public let APIKitErrorDomain = "APIKitErrorDomain"

// use private, global scope variable until we can use stored class var in Swift 1.2
private let internalDefaultURLSession = NSURLSession(
configuration: NSURLSessionConfiguration.defaultSessionConfiguration(),
delegate: URLSessionDelegate(),
delegateQueue: nil
)

public class API {
// configurations
public class func baseURL() -> NSURL {
fatalError("API.baseURL() must be overrided in subclasses.")
public class var baseURL: NSURL {
fatalError("API.baseURL must be overrided in subclasses.")
}

public class func requestBodyBuilder() -> RequestBodyBuilder {
public class var requestBodyBuilder: RequestBodyBuilder {
return .JSON(writingOptions: nil)
}

public class func responseBodyParser() -> ResponseBodyParser {
public class var responseBodyParser: ResponseBodyParser {
return .JSON(readingOptions: nil)
}

Expand All @@ -35,17 +28,23 @@ public class API {
return [Int](200..<300)
}

private static let internalDefaultURLSession = NSURLSession(
configuration: NSURLSessionConfiguration.defaultSessionConfiguration(),
delegate: URLSessionDelegate(),
delegateQueue: nil
)

// build NSURLRequest
public class func URLRequest(method: Method, _ path: String, _ parameters: [String: AnyObject] = [:]) -> NSURLRequest? {
if let components = NSURLComponents(URL: baseURL(), resolvingAgainstBaseURL: true) {
if let components = NSURLComponents(URL: baseURL, resolvingAgainstBaseURL: true) {
let request = NSMutableURLRequest()

switch method {
case .GET, .HEAD, .DELETE:
components.query = URLEncodedSerialization.stringFromObject(parameters, encoding: NSUTF8StringEncoding)

default:
switch requestBodyBuilder().buildBodyFromObject(parameters) {
switch requestBodyBuilder.buildBodyFromObject(parameters) {
case .Success(let box):
request.HTTPBody = box.unbox

Expand All @@ -57,27 +56,17 @@ public class API {
components.path = (components.path ?? "").stringByAppendingPathComponent(path)
request.URL = components.URL
request.HTTPMethod = method.rawValue
request.setValue(requestBodyBuilder().contentTypeHeader, forHTTPHeaderField: "Content-Type")
request.setValue(responseBodyParser().acceptHeader, forHTTPHeaderField: "Accept")
request.setValue(requestBodyBuilder.contentTypeHeader, forHTTPHeaderField: "Content-Type")
request.setValue(responseBodyParser.acceptHeader, forHTTPHeaderField: "Accept")

return request
} else {
return nil
}
}

// In Swift 1.1, we could not omit `URLSession` argument of `func send(request:URLSession(=default):handler(=default):)`
// with trailing closure, so we provide following 2 methods
// - `func sendRequest(request:handler(=default):)`
// - `func sendRequest(request:URLSession:handler(=default):)`.
// In Swift 1.2, we can omit default arguments with trailing closure, so they should be replaced with
// - `func sendRequest(request:URLSession(=default):handler(=default):)`
public class func sendRequest<T: Request>(request: T, handler: (Result<T.Response, NSError>) -> Void = {r in}) -> NSURLSessionDataTask? {
return sendRequest(request, URLSession: defaultURLSession, handler: handler)
}

// send request and build response object
public class func sendRequest<T: Request>(request: T, URLSession: NSURLSession, handler: (Result<T.Response, NSError>) -> Void = {r in}) -> NSURLSessionDataTask? {
public class func sendRequest<T: Request>(request: T, URLSession: NSURLSession = defaultURLSession, handler: (Result<T.Response, NSError>) -> Void = {r in}) -> NSURLSessionDataTask? {
let mainQueue = dispatch_get_main_queue()

if let URLRequest = request.URLRequest {
Expand All @@ -93,7 +82,7 @@ public class API {
let statusCode = (URLResponse as? NSHTTPURLResponse)?.statusCode ?? 0
if !contains(self.acceptableStatusCodes, statusCode) {
let error: NSError = {
switch self.responseBodyParser().parseData(data) {
switch self.responseBodyParser.parseData(data) {
case .Success(let box): return self.responseErrorFromObject(box.unbox)
case .Failure(let box): return box.unbox
}
Expand All @@ -103,7 +92,7 @@ public class API {
return
}

let mappedResponse: Result<T.Response, NSError> = self.responseBodyParser().parseData(data).flatMap { rawResponse in
let mappedResponse: Result<T.Response, NSError> = self.responseBodyParser.parseData(data).flatMap { rawResponse in
if let response = T.responseFromObject(rawResponse) {
return success(response)
} else {
Expand Down Expand Up @@ -192,7 +181,7 @@ private var dataTaskResponseBufferKey = 0
private var dataTaskCompletionHandlerKey = 0

private extension NSURLSessionDataTask {
// `var request: Request?` is not available in both of Swift 1.1 and 1.2
// `var request: Request?` is not available in Swift 1.2
// ("protocol can only be used as a generic constraint")
private var request: Box<Any>? {
get {
Expand Down Expand Up @@ -248,4 +237,3 @@ extension NSURLSessionDownloadTask {
}
}
}

2 changes: 1 addition & 1 deletion APIKit/Request.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ public protocol Request {

var URLRequest: NSURLRequest? { get }

class func responseFromObject(object: AnyObject) -> Response?
static func responseFromObject(object: AnyObject) -> Response?
}
8 changes: 4 additions & 4 deletions APIKit/RequestBodyBuilder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,14 @@ public enum RequestBodyBuilder {
return failure(error)
}

return try { error in
return try({ error in
return NSJSONSerialization.dataWithJSONObject(object, options: writingOptions, error: error)
}
})

case .URL(let encoding):
return try { error in
return try({ error in
return URLEncodedSerialization.dataFromObject(object, encoding: encoding, error: error)
}
})

case .Custom(let (_, buildBodyFromObject)):
return buildBodyFromObject(object)
Expand Down
8 changes: 4 additions & 4 deletions APIKit/ResponseBodyParser.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,14 @@ public enum ResponseBodyParser {
public func parseData(data: NSData) -> Result<AnyObject, NSError> {
switch self {
case .JSON(let readingOptions):
return try { error in
return try({ error in
return NSJSONSerialization.JSONObjectWithData(data, options: readingOptions, error: error)
}
})

case .URL(let encoding):
return try { error in
return try({ error in
return URLEncodedSerialization.objectFromData(data, encoding: encoding, error: error)
}
})

case .Custom(let (accept, parseData)):
return parseData(data)
Expand Down
8 changes: 4 additions & 4 deletions APIKit/URLEncodedSerialization.swift
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import Foundation

private func escape(string: String) -> String {
return CFURLCreateStringByAddingPercentEscapes(nil, string, nil, "!*'();:@&=+$,/?%#[]", CFStringBuiltInEncodings.UTF8.rawValue)
return CFURLCreateStringByAddingPercentEscapes(nil, string, nil, "!*'();:@&=+$,/?%#[]", CFStringBuiltInEncodings.UTF8.rawValue) as String
}

private func unescape(string: String) -> String {
return CFURLCreateStringByReplacingPercentEscapes(nil, string, nil)
return CFURLCreateStringByReplacingPercentEscapes(nil, string, nil) as String
}

public class URLEncodedSerialization {
Expand All @@ -15,8 +15,8 @@ public class URLEncodedSerialization {
if let string = NSString(data: data, encoding: encoding) as? String {
dictionary = [String: AnyObject]()

for pair in split(string, { $0 == "&" }) {
let contents = split(pair, { $0 == "=" })
for pair in string.componentsSeparatedByString("&") {
let contents = pair.componentsSeparatedByString("=")

if contents.count == 2 {
dictionary?[contents[0]] = unescape(contents[1])
Expand Down
6 changes: 3 additions & 3 deletions APIKitTests/APITests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@ import OHHTTPStubs

class APITests: XCTestCase {
class MockAPI: API {
override class func baseURL() -> NSURL {
override class var baseURL: NSURL {
return NSURL(string: "https://api.github.com")!
}

override class func requestBodyBuilder() -> RequestBodyBuilder {
override class var requestBodyBuilder: RequestBodyBuilder {
return .JSON(writingOptions: nil)
}

override class func responseBodyParser() -> ResponseBodyParser {
override class var responseBodyParser: ResponseBodyParser {
return .JSON(readingOptions: nil)
}

Expand Down
18 changes: 9 additions & 9 deletions APIKitTests/RequestBodyBuilderTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ class RequestBodyBuilderTests: XCTestCase {

switch builder.buildBodyFromObject(object) {
case .Success(let box):
let dictionary = NSJSONSerialization.JSONObjectWithData(box.unbox, options: nil, error: nil) as [String: Int]
assertEqual(dictionary["foo"], 1)
assertEqual(dictionary["bar"], 2)
assertEqual(dictionary["baz"], 3)
let dictionary = NSJSONSerialization.JSONObjectWithData(box.unbox, options: nil, error: nil) as? [String: Int]
assertEqual(dictionary?["foo"], 1)
assertEqual(dictionary?["bar"], 2)
assertEqual(dictionary?["baz"], 3)

case .Failure:
XCTFail()
Expand Down Expand Up @@ -52,18 +52,18 @@ class RequestBodyBuilderTests: XCTestCase {

switch builder.buildBodyFromObject(object) {
case .Success(let box):
let dictionary = URLEncodedSerialization.objectFromData(box.unbox, encoding: NSUTF8StringEncoding, error: nil) as [String: String]
assertEqual(dictionary["foo"], "1")
assertEqual(dictionary["bar"], "2")
assertEqual(dictionary["baz"], "3")
let dictionary = URLEncodedSerialization.objectFromData(box.unbox, encoding: NSUTF8StringEncoding, error: nil) as? [String: String]
assertEqual(dictionary?["foo"], "1")
assertEqual(dictionary?["bar"], "2")
assertEqual(dictionary?["baz"], "3")

case .Failure:
XCTFail()
}
}

func testCustomHeader() {
let builder = RequestBodyBuilder.Custom(contentTypeHeader: "foo", buildBodyFromObject: { o in success(o as NSData) })
let builder = RequestBodyBuilder.Custom(contentTypeHeader: "foo", buildBodyFromObject: { o in success(o as! NSData) })
assertEqual(builder.contentTypeHeader, "foo")
}

Expand Down
18 changes: 9 additions & 9 deletions APIKitTests/ResponseBodyParserTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ class ResponseBodyParserTests: XCTestCase {

switch parser.parseData(data) {
case .Success(let box):
let dictionary = box.unbox as [String: Int]
assertEqual(dictionary["foo"], 1)
assertEqual(dictionary["bar"], 2)
assertEqual(dictionary["baz"], 3)
let dictionary = box.unbox as? [String: Int]
assertEqual(dictionary?["foo"], 1)
assertEqual(dictionary?["bar"], 2)
assertEqual(dictionary?["baz"], 3)

case .Failure:
XCTFail()
Expand Down Expand Up @@ -55,10 +55,10 @@ class ResponseBodyParserTests: XCTestCase {

switch parser.parseData(data) {
case .Success(let box):
let dictionary = box.unbox as [String: String]
assertEqual(dictionary["foo"], "1")
assertEqual(dictionary["bar"], "2")
assertEqual(dictionary["baz"], "3")
let dictionary = box.unbox as? [String: String]
assertEqual(dictionary?["foo"], "1")
assertEqual(dictionary?["bar"], "2")
assertEqual(dictionary?["baz"], "3")

case .Failure:
XCTFail()
Expand All @@ -79,7 +79,7 @@ class ResponseBodyParserTests: XCTestCase {

switch parser.parseData(data) {
case .Success(let box):
let dictionary = box.unbox as [String: Int]
let dictionary = box.unbox as? [String: Int]
assertEqual(dictionary, expectedDictionary)

case .Failure:
Expand Down
2 changes: 1 addition & 1 deletion Cartfile
Original file line number Diff line number Diff line change
@@ -1 +1 @@
github "LlamaKit/LlamaKit" ~> 0.5.0
github "LlamaKit/LlamaKit" ~> 0.6.0
2 changes: 1 addition & 1 deletion Cartfile.private
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
github "ikesyo/Assertions" "swift-1.1"
github "antitypical/Assertions" "master"
github "ishkawa/OHHTTPStubs" "master"
4 changes: 2 additions & 2 deletions Cartfile.resolved
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
github "ikesyo/Assertions" "fec437ce6857259ac8bda3eb255c5782aa798734"
github "LlamaKit/LlamaKit" "v0.5.0"
github "antitypical/Assertions" "19bac03828dcb2f9b9ecb7f829e09bb3900886e5"
github "LlamaKit/LlamaKit" "v0.6.0"
github "ishkawa/OHHTTPStubs" "825806534aa2bdc6ebba5e26cd304de2ced67395"
2 changes: 1 addition & 1 deletion Carthage/Checkouts/Assertions
2 changes: 1 addition & 1 deletion Carthage/Checkouts/LlamaKit
8 changes: 4 additions & 4 deletions DemoApp/GitHub.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,19 @@ import APIKit
import LlamaKit

class GitHub: API {
override class func baseURL() -> NSURL {
override class var baseURL: NSURL {
return NSURL(string: "https://api.github.com")!
}

override class func requestBodyBuilder() -> RequestBodyBuilder {
override class var requestBodyBuilder: RequestBodyBuilder {
return .JSON(writingOptions: nil)
}

override class func responseBodyParser() -> ResponseBodyParser {
override class var responseBodyParser: ResponseBodyParser {
return .JSON(readingOptions: nil)
}

class Request {
class Endpoint {
// https://developer.github.com/v3/search/#search-repositories
class SearchRepositories: APIKit.Request {
enum Sort: String {
Expand Down
Loading

0 comments on commit b4244ce

Please sign in to comment.