Reputation: 6049
I have a networking manager class that does all of the communication with our service's backend. I am intently trying to provide users with a nice experience when the network requests potentially fail.
Right now, the networking manager class makes a request to authenticate with the backend:
internal func authenticate(withEmailAddress emailAddress: String, andPassword password: String, withCompletion completion: @escaping (Result<Data>) -> Void) {
// ...Create the request...
task = session.dataTask(with: request, completionHandler: { (data: Data?, response: URLResponse?, error: Error?) -> Void in
if let requestError = error as? NSError {
// ...Handle CFNetworkErrors (-1001, etc.)...
}
if let httpResponse = response as? HTTPURLResponse {
// ...Handle the response codes (200, 400, 401, 500)...
} else {
// ...Handle the response not being of type `HTTPURLResponse`...
}
})
// ...Start the task...
}
I have another class that manages the return of either a Data
or Error
to the completion handler, which is based on the response's status code or request's error.
After looking at a list of HTTP status codes and a list of CFNetworkErrors, I can see that there are a lot of possibilities for handling such errors. I realize that not all of the CFNetworkErrors
are appropriate in my case, but I would still be left with a long list of errors to handle.
Is there a direction that I should take for handling the possible errors other than switching on the requestError.code
?
If I were to handle all of the CFNetworkErrors
, then I would end up with a very long logic block that checks the code like this:
switch code {
case -1005: // ...Handle error...
case -1001: // ...Handle error...
case 1: // ...Handle error...
case 200: // ...Handle error...
// ...Handle the rest of the errors...
default: // ...Handle error...
}
I would also end up with a very long block to handle all of the appropriate response status codes like this:
switch response.statusCode {
case 200: // ...Do something with data...
case 400: // ...Handle missing user credentials...
case 401: // ...Handle incorrect credentials...
case 500: // ...Handle internal server error...
// ...Handle the rest of the status codes...
default: // ...Handle default error...
}
Can you give me some guidance on what some good practices may be when trying to handle all of the networking errors that may be encountered?
Upvotes: 2
Views: 371
Reputation: 53143
First of all, I think it would be extremely difficult to specifically handle all possible networking errors. There are a bunch, as you already know, so it would be much easier to make it a bit more generic to handle groups of statuses. You might use the range operator in your case statements like this:
switch response.statusCode {
case 200...299: // ...Do something with data...
case 300...399: // ...Handle redirect...
case 400...499: // ...Handle client error...
case 500...599: // ...Handle server error...
default: // ...Handle default error...
}
You can even add specific cases in there that you want to handle -- for example, you might want to handle 401 Unauthorized in a very specific way, perhaps informing the user -- so you could just add that to your switch statement as its own case and call the code you want to inform the user of the issue.
Upvotes: 3