Reputation: 1623
I have used many hours on how to solve this issue. Im using Restkit 0.9.3 with Object Mapping 2.0. All data is in JSON. I can make GET, POST, PUT and DELETE operations correctly, it's the response body I dont catch and map corretly..
So my problem is that my restful api is returning errors when something goes wrong. I want to map those errors with restkit, fx this error is returned:
{
"code": "401",
"message": "Unauthorized"
}
How do I map this JSON correctly? I have tried lots of things and could use some guidance - or please give an example of this.
Upvotes: 14
Views: 7339
Reputation: 5542
Using Restkit v0.2x you can map all JSON attributes you want to the already existing RKErrorMessage.userInfo
Dictionary property in this [Swift] way:
let errorMapping = RKObjectMapping(forClass: RKErrorMessage.self);
errorMapping.addPropertyMapping(RKAttributeMapping(fromKeyPath: nil, toKeyPath: "userInfo"));
let errorResponseDescriptor = RKResponseDescriptor(
mapping: errorMapping,
method: RKRequestMethod.Any,
pathPattern: nil,
keyPath: "error", //or nil, according to your json response
statusCodes: RKStatusCodeIndexSetForClass(UInt(RKStatusCodeClassClientError)))
);
So, you can map an error JSON response like this one:
{
"error": {
"message": "Error message",
"cause": "...",
"code": "my_error_code",
"url": "..."
...
}
}
And retrieve the RKErrorMessage
with all attributes, in a failure
closure, as follows:
failure: { (operation, error) -> Void in
if let errorMessage = error.userInfo?[RKObjectMapperErrorObjectsKey]?.firstObject as? RKErrorMessage{
let message = errorMessage.userInfo["message"] as! String;
let code = errorMessage.userInfo["code"] as! String;
...
}
}
I hope this can be helpful to someone!
Upvotes: 5
Reputation: 7908
For RestKit v0.20
assuming your HTTP body is:
{"error": "..."}
you create an the mapping and descriptor:
RKObjectMapping *errorMapping = [RKObjectMapping mappingForClass:[RKErrorMessage class]];
[errorMapping addPropertyMapping: [RKAttributeMapping attributeMappingFromKeyPath:@"error" toKeyPath:@"errorMessage"]];
RKResponseDescriptor *errorResponseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:errorMapping pathPattern:nil keyPath:nil statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassClientError)];
[objectManager addResponseDescriptor:errorResponseDescriptor];
and then you can access it from your failure block:
failure:^(RKObjectRequestOperation *operation, NSError *error) {
NSLog(@"errorMessage: %@", [[error userInfo] objectForKey:RKObjectMapperErrorObjectsKey]);
}
This uses the built-in RKErrorMessage
class, though you can create your own custom class with additional fields.
Upvotes: 29
Reputation: 10054
For version 0.10.0 this response error can be mapped as follows:
RKObjectMapping *errorMapping = [RKObjectMapping mappingForClass:[RKErrorMessage class]];
[errorMapping mapKeyPath:@"message" toAttribute:@"errorMessage"];
[[[RKObjectManager sharedManager] mappingProvider] setErrorMapping:errorMapping];
Requests that return an error will call the following delegate method:
- (void)objectLoader:(RKObjectLoader *)objectLoader didFailWithError:(NSError *)error {
NSArray *errorMessages = [[error userInfo] objectForKey:RKObjectMapperErrorObjectsKey];
RKErrorMessage *errorMessage = [errorMessages objectAtIndex:0]; // First and only object in your case.
NSString *message = [errorMessage errorMessage];
NSInteger code = [[objectLoader response] statusCode];
NSLog(@"ERROR: [%d] %@", code, message); // => ERROR: [401] Unauthorized
}
Upvotes: 10
Reputation: 319
if an object is returned your delegate should call this method:
- (void)objectLoader:(RKObjectLoader*)objectLoader didLoadObjects:(NSArray*)objects {}
in this method you should call an instance of your "error" class and map 'code' and 'message' as necessary.
An easier way to handle errors though would be to use:
- (void)objectLoader:(RKObjectLoader*)objectLoader didFailWithError:(NSError*)error {
if(objectLoader.response.statusCode == 401)
{ ...
And show the necessary error message in that method.
Upvotes: 0