Nick Kohrn
Nick Kohrn

Reputation: 6049

How Can I Handle All Potential Network Errors Appropriately?

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

Answers (1)

Josh Brown
Josh Brown

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

Related Questions