I have recently used URLSession.shared.dataTask(with:completionHandler:), and it got me wondering:
- Why are status codes like 400/500 not presented in the Error? object of the completionHandler?
- Is there a list of errors that have the possibility of ending up in the Error? object of the completionHandler? The 'An error object indicating why the request failed' is quite broad and I am interested in a list of what actually ends up in there.
Thanks!
Craz1k0ek
Why are status codes like 400/500 not presented in the
object of theError?
?completionHandler
The
URLSession
API draws a strict line between:
Transport errors, that is, errors getting your request too the server or getting the response back
Server-side errors, that is, the HTTP status code in the response from the server
The main reason for this is that the interpretation of server errors can be server specific, and that makes things hard for a generic HTTP client, like
URLSession
, that has to work with all servers.
If this setup is inconvenient to you, it’s quite straightforward to add your own wrapper to make things easier. For example, pasted in below is an extension on
URLSession
that treats anything except 200...299 as an error.
Note This code uses the Swift 5
Result
type, and thus requires Xcode 10.2 beta. If you need Swift 4 compatibility, you can use your own
Result
type (or the one from your favourite third-party library).
Is there a list of errors that have the possibility of ending up in the
object of theError?
The An error object indicating why the request failed is quite broad and I am interested in a list of what actually ends up in there.completionHandler?
Most of the common errors are listed in
<Foundation/NSURLError.h>
. These include file system errors, DNS errors, TCP errors, TLS errors, and HTTP protocol errors. It’s also common to find extra information in the error’s user dictionary, and specifically an underlying error accessed via
NSUnderlyingErrorKey
.
It’s absolutely fine to look at these errors for debugging purposes, and to include all the details in logs, but I’d caution you about showing them directly to the user. While all the errors include a localised description, in many cases that description is not going to be helpful. For example, you have to be a TCP expert to understand what this means:
let e = NSError(domain: NSPOSIXErrorDomain, code: Int(ECONNRESET), userInfo: nil) as Error
print(e.localizedDescription)
// -> The operation couldn’t be completed. Connection reset by peer
Share and Enjoy
—
Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware
let myEmail = "eskimo" + "1" + "@apple.com"
extension URLSession {
enum HTTPError: Error {
case transportError(Error)
case serverSideError(Int)
}
typealias DataTaskResult = Result<(HTTPURLResponse, Data), Error>
func dataTask(with request: URLRequest, completionHandler: @escaping (DataTaskResult) -> Void) -> URLSessionDataTask {
return self.dataTask(with: request) { (data, response, error) in
if let error = error {
completionHandler(Result.failure(HTTPError.transportError(error)))
return
}
let response = response as! HTTPURLResponse
let status = response.statusCode
guard (200...299).contains(status) else {
completionHandler(Result.failure(HTTPError.serverSideError(status)))
return
}
completionHandler(Result.success((response, data!)))
}
}
}