abekenza
abekenza

Reputation: 1090

How to get status code in AFNetworking

I have a method, for authorizing user. I need Basic authorization.

    NSString *url = [NSString stringWithFormat:@"%@/rest/api/person/auth", host];
    AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
    [manager setRequestSerializer:[AFHTTPRequestSerializer serializer]];
    [manager.requestSerializer setAuthorizationHeaderFieldWithUsername:_loginField.text password:_passwordField.text];
    [manager setResponseSerializer:[AFJSONResponseSerializer serializer]];
    [manager GET:url parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
        [self parseResponseForUser:responseObject];
    } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
        NSLog(@"Error %@ ",error);
    }];

The main problem here is determining error type. I may have error for authorization and error for network connection problem (host is not reachable). When login and password don't match criteria, failure block runs. For example, If I put wrong password and login I take this error message.:

Error Domain=NSCocoaErrorDomain Code=3840 "The operation couldn’t be completed. (Cocoa error 3840.)" (JSON text did not start with array or object and option to allow fragments not set.)

How should i catch error types?

Upvotes: 17

Views: 23318

Answers (9)

Penkey Suresh
Penkey Suresh

Reputation: 5974

Here is how to do it in Swift

((NSURLSessionDataTask, NSError) -> Void) = { (sessionDataTask :NSURLSessionDataTask, responseError : NSError) -> Void in
    let response  = sessionDataTask.response as! NSHTTPURLResponse
    switch (statusCode) {
      case 404:
        // do stuff
      case 401:
        // do stuff
      default:
        break;
    }
}

Upvotes: 1

solven
solven

Reputation: 71

Improved response of alok srivastava by using NSURLError enum:

failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSInteger statusCode = error.code;
if(statusCode == NSURLErrorTimedOut) {
  // request timed out
} else if (statusCode == NSURLErrorNotConnectedToInternet || statusCode || NSURLErrorCannotConnectToHost) {
  // no internet connectivity
}}];

Upvotes: 1

webstersx
webstersx

Reputation: 771

In AFNetworking 3.0+ and in the case of an error, you can access the status code in the failure block's error.userInfo object:

failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {

    NSHTTPURLResponse *response = error.userInfo[AFNetworkingOperationFailingURLResponseErrorKey];

    NSInteger statusCode = response.statusCode;

    // Do something with the status code
}];

Upvotes: 21

JohnVanDijk
JohnVanDijk

Reputation: 3581

Here's how I do it.

[self.httpClient GET:@"someAPI"
          parameters:parametersDictionary
             success:^(NSURLSessionDataTask *task, id responseObject) {
             } failure:^(NSURLSessionDataTask *task, NSError *error) {
               NSHTTPURLResponse *response = (NSHTTPURLResponse *)task.response;
               NSInteger statusCode = [response statusCode];
               switch (statusCode) {
                 case 404:
                   break;
                 default:
                   break;
               }
             }];

Upvotes: 6

alok srivastava
alok srivastava

Reputation: 761

you can give a try to get code from error and then show messages accordingly.

failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    NSInteger statusCode = error.code;
    if(statusCode == -1001) {
      // request timed out
    } else if (statusCode == -1009 || statusCode || -1004) {
      // no internet connectivity
    }
}];

similarly you can check for other code.

Upvotes: 7

abekenza
abekenza

Reputation: 1090

Finally found answer, may be it will be helpful for someone. I just needed to use:

NSInteger statusCode = operation.response.statusCode;

And i can catch it like:

    [manager GET:url parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
        NSLog(@"response:%@", responseObject);
        [self parseResponseForUser:responseObject];
    } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
        NSInteger statusCode = operation.response.statusCode;
        if(statusCode == 401) {
        } else if (statusCode == 404) {
        }
    }];

Upvotes: 31

CouchDeveloper
CouchDeveloper

Reputation: 19098

It happens frequently, that servers may send a response in a different content type than requested IF they are sending an error.

For example when sending a request with JSON as Content-Type and expecting a JSON response from the server, one would specify the following request headers:

Content-Type: application/json
Accept: application/json

When the request fails due to an authentication error, the server may send you a status code of 401 (Unauthorized) plus an optional response which contains relevant diagnostic information.

Strictly, web servers should respect the Accept header, but unfortunately, some don't and will send a "standard" error response in text/html for example. The details should be specified in the API, though.

Your implementation should handle that case gracefully. That is, your response handler must encode (or parse) the response data according the Content-Type of the response, say text/html or ignore it if suitable. More precisely, you always should query the HTTP status code AND the content type and then make an informed decision how you want to treat the response.

See Aron Brager's answer how to solve that issue with AFN.

Upvotes: 0

Aaron Brager
Aaron Brager

Reputation: 66244

It looks like your server might respond with HTML, or it might respond with JSON. But when you type:

[manager setResponseSerializer:[AFJSONResponseSerializer serializer]];

You're telling AFNetworking to expect JSON.

Instead, try telling it to handle a regular HTTP response if it's not JSON:

NSArray *serializers = @[[AFJSONResponseSerializer serializer], [AFHTTPResponseSerializer serializer]];
AFCompoundSerializer *compoundResponseSerializer = [AFCompoundSerializer compoundSerializerWithResponseSerializers:serializers];
[manager setResponseSerializer:compoundResponseSerializer];

Now, if the JSON serializer fails, the request will be passed to the AFHTTPResponseSerializer, which should call your failure block with the appropriate HTTP error code instead of the JSON parsing error.

Incidentally, AFHTTPResponseSerializer is subclass-able, so feel free to take a look at that option if you want more specific behavior.

Upvotes: 0

Dimentar
Dimentar

Reputation: 603

your Json must be:

{
    "access" : "1",
    "admin" : "0",
    "code" : "constantine2",

    ...

    "positions" : [
                {
            "departmentID" : "992c93ee-2fa7-4e53-be5f-4e32a45ba5e6",
            "departmentName" : "Dev-C++ resources page (libraries, sources, updates...)",
            ....
        }
    ],
    "userid" : "3b660c13-b856-41fa-a386-814a7b43bacc"
}

Upvotes: -1

Related Questions