Skip to content

Commit

Permalink
Merge pull request #32 from mapbox/1ec5-error-messages
Browse files Browse the repository at this point in the history
Provide details in returned error
  • Loading branch information
1ec5 committed May 31, 2016
2 parents 269b5d9 + 7d409c4 commit 03ed769
Showing 1 changed file with 48 additions and 1 deletion.
49 changes: 48 additions & 1 deletion MapboxStatic/Snapshot.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@
import UIKit
#endif

typealias JSONDictionary = [String: AnyObject]

/// Indicates that an error occurred in MapboxStatic.
public let MBStaticErrorDomain = "MBStaticErrorDomain"

/// The Mapbox access token specified in the main application bundle’s Info.plist.
let defaultAccessToken = NSBundle.mainBundle().objectForInfoDictionaryKey("MGLMapboxAccessToken") as? String

Expand Down Expand Up @@ -439,8 +444,18 @@ public class Snapshot: NSObject {
public func image(completionHandler handler: CompletionHandler) -> NSURLSessionDataTask {
let task = NSURLSession.sharedSession().dataTaskWithURL(URL) { (data, response, error) in
if let error = error {
var json: JSONDictionary = [:]
if let data = data {
do {
json = try NSJSONSerialization.JSONObjectWithData(data, options: []) as! JSONDictionary
} catch {
assert(false, "Invalid data")
}
}

let apiError = Snapshot.descriptiveError(json, response: response, underlyingError: error)
dispatch_async(dispatch_get_main_queue()) {
handler(image: nil, error: error)
handler(image: nil, error: apiError)
}
} else {
let image = Image(data: data!)
Expand All @@ -452,4 +467,36 @@ public class Snapshot: NSObject {
task.resume()
return task
}

/**
Returns an error that supplements the given underlying error with additional information from the an HTTP response’s body or headers.
*/
private static func descriptiveError(json: JSONDictionary, response: NSURLResponse?, underlyingError error: NSError?) -> NSError {
var userInfo = error?.userInfo ?? [:]
if let response = response as? NSHTTPURLResponse {
var failureReason: String? = nil
var recoverySuggestion: String? = nil
switch response.statusCode {
case 429:
if let timeInterval = response.allHeaderFields["x-rate-limit-interval"] as? NSTimeInterval, maximumCountOfRequests = response.allHeaderFields["x-rate-limit-limit"] as? UInt {
let intervalFormatter = NSDateComponentsFormatter()
intervalFormatter.unitsStyle = .Full
let formattedInterval = intervalFormatter.stringFromTimeInterval(timeInterval)
let formattedCount = NSNumberFormatter.localizedStringFromNumber(maximumCountOfRequests, numberStyle: .DecimalStyle)
failureReason = "More than \(formattedCount) requests have been made with this access token within a period of \(formattedInterval)."
}
if let rolloverTimestamp = response.allHeaderFields["x-rate-limit-reset"] as? Double {
let date = NSDate(timeIntervalSince1970: rolloverTimestamp)
let formattedDate = NSDateFormatter.localizedStringFromDate(date, dateStyle: .LongStyle, timeStyle: .FullStyle)
recoverySuggestion = "Wait until \(formattedDate) before retrying."
}
default:
failureReason = json["message"] as? String
}
userInfo[NSLocalizedFailureReasonErrorKey] = failureReason ?? userInfo[NSLocalizedFailureReasonErrorKey] ?? NSHTTPURLResponse.localizedStringForStatusCode(error?.code ?? -1)
userInfo[NSLocalizedRecoverySuggestionErrorKey] = recoverySuggestion ?? userInfo[NSLocalizedRecoverySuggestionErrorKey]
}
userInfo[NSUnderlyingErrorKey] = error
return NSError(domain: error?.domain ?? MBStaticErrorDomain, code: error?.code ?? -1, userInfo: userInfo)
}
}

0 comments on commit 03ed769

Please sign in to comment.