Alamofire request and error handling

Hi,

I'm looping over a list of strings and for each one of them I'm going to make an Alamofire request to an API endpoint.


func readStrings() {
     [...]
    for name in array {    
        getResults(artistName: artist)
    }
}

func getResults(name: String) {   
    let headers: HTTPHeaders = [
        //request headers
    ]
    let requestEndpoint = "ENDPOINT\(name)"
    
    AF.request(requestEndpoint, headers: headers).validate(statusCode: 200..<300).responseJSON  { 
      [weak self] response in
        //Parse the JSON
        //If the status code is outside that range, throw an error and break the loop.
    }

Problem is that when I get an error code, i.e. 409, I'd like my closure to throw, in order for my readStrings() function to break the loop and then display a message to the user.
I don't quite understand well why I can't throw inside that closure. I get this:

Invalid conversion from throwing function of type '(_) throws -> ()' to non-throwing function type '(AFDataResponse<Any>) -> Void' (aka '(DataResponse<Any, AFError>) -> ()')

Can you show the code where you get the error ?


How is AF.request defined ?

probably not as throws, hence the error.


So, you should change something like:

What is the type of response ? I call it ResponseType for clarity, but should use the real type


func getResults(name: String) throws {     // WHAT DO YOU RETURN from this func ?
 
    var errorToThrow : ResponseType? = nil
    let headers: HTTPHeaders = [
        //request headers
    ]
    let requestEndpoint = "ENDPOINT\(name)"
 
    AF.request(requestEndpoint, headers: headers).validate(statusCode: 200..<300).responseJSON  {
      [weak self] response in
        // Parse the JSON
        / /If the status code is outside that range, throw an error and break the loop.
        errorToThrow = response
    }

     if errorToThrow != nil { throw the error }

What do you return from this func ?

Nothing. The results from parsing the json are appended to an external .txt file

I could use your suggestion, but once the AF request is finished, line 16 if errorToThrow != nil { throw the error } is unreachable.


Can you show the code where you get the error ?

switch response.result {
                case .success:                    
                case .failure:
                    //Here I'd like to throw an error
      }

If it's .failure, I'd like to throw an error and then break the loop in my readStrings() func. But If I do so I get the error I've mentioned before. This is because the AF request, internally, doesn't throw, to my understanding.
I tried setting errorToThrow to a non nil value but then, as I said, line 16 is unreachable, probably because the AF request is async. Line 16 was reached some time before and errorToThrow was obviously still nill.

Accepted Answer

If it's .failure, I'd like to throw an error and then break the loop in my readStrings() func.

You know you are using async method, but you do not fully understand what happens.


Completion handlers for async calls are executed when the invoked communications are finished.

Which means,

first your `readString()` finishes, including all the loops in your for-in statement, each invokes a communication, and returns to the caller.

And then, when each communication is finished, the completion handler in your `getResults(name:)` is executed, one by one, but not in order.


So, when you throw an error in the completion handler, the loop in your readString() is already finished, there's no loop to break, throwing an error there does not make sense.


To get the right solution, you may need to define what sort of behavior you expect on such errors, you need to re-construct your mind accepting the async behavior described above.

Sorry I didn't consider the readString() as being already finished. Now I understand why I can't do what I had originally planned to do.
I'll take time to think about another solution.
Thank you.

Alamofire request and error handling
 
 
Q