I am writing an iOS app that interacts with a service to update a user's profile. In order to update a user's name, the iOS app PUTs a request with a body of the following format:
{"name" : {"first" : "FIRSTNAMEGOESHERE", "lastName":"LASTNAMEGOESHERE"}}
In the case where the request body is valid (i.e. both a first and last name are provided), the service returns a 204 (No Content) status code and an empty response body.
In the case where the request body is invalid (e.g. first name is missing, etc.), the service will return a status code of 400 and a response body in the following format:
{"code":"ERRORCODEHERE"}
The iOS app is using RestKit and I have been unable to figure out how to get it to both properly handle the success and failure case. If I use this:
- (void)updateUserName
{
RKObjectManager *objectManager = [RKObjectManager managerWithBaseURL:[[NSURL alloc] initWithString:@"http://someqaserver:8080"]];
[objectManager setRequestSerializationMIMEType:RKMIMETypeJSON];
RKObjectMapping *userMapping = [RKObjectMapping requestMapping];
[userMapping addAttributeMappingsFromDictionary:@{@"firstName" : @"first", @"lastName" : @"last"}];
RKRequestDescriptor *requestDescriptor = [RKRequestDescriptor requestDescriptorWithMapping:userMapping objectClass:[OurUser class] rootKeyPath:@"name"];
[objectManager addRequestDescriptor:requestDescriptor];
[objectManager putObject:[OurUser getCurrentUser]
path:@"/mobile/profile/name"
parameters:nil
success:^(RKObjectRequestOperation *operation, RKMappingResult *result)
{
NSLog(@"Success!");
}
failure:^(RKObjectRequestOperation *operation, NSError *error)
{
NSLog(@"Fail!");
}];
}
This obviously does not work for the error case, but it does successfully execute the success block in the case where a 204 is returned from the server.
If I add the following code before calling putObject, the error handling works, but now the valid 204 case is deemed a failure:
RKObjectMapping *errorMapping = [RKObjectMapping mappingForClass:[ServiceError class]];
[errorMapping addAttributeMappingsFromDictionary:@{@"code" : @"errorCode"}];
RKResponseDescriptor *errorDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:errorMapping pathPattern:nil keyPath:nil statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassClientError)];
[objectManager addResponseDescriptor:errorDescriptor];
This seems to happen since the accepted HTTP status codes are now set to those of the response descriptors provided and 204 is not one of them (or maybe it's something else?)
How can I get it so that: 1.) if a 204 is returned, it's seen as a success 2.) if a 4XX is returned, it's seen as a failure and the error code is properly mapped to my ServiceError object?
Thanks in advance for any help you can provide.
The problem was solved by also adding a response descriptor to handle the 204:
RKResponseDescriptor *successResponseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:[RKObjectMapping mappingForClass:nil]
method:RKRequestMethodPUT
pathPattern:nil
keyPath:nil
statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
[manager addResponseDescriptor:successResponseDescriptor];
code 204 is not an error, any 2xx status is deemed a success. 204 means 'no content', which is a perfectly valid response. If you expect restkit to treat it as an error, make sure you throw a 3xx, 4xx or a 5xx error. In your case you are using a RKStatusCodeClassClientErrorm which would suggest you should throw a 4xx error.
See wikipedia for a complete list of error codes
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With