Reputation: 53
I have an API that requires I post a complex JSON object. The API saves and responds with a primitive ID (or an error object). I am not able to map the primitive ID. Any ideas? The example below, for simplicity's sake, is not doing the POST object mapping, but some of my API calls will require that as well.
I saw suggestions to utilize RestKit to build the request, and pass it to AFNetworking, but this will not parse a possible error return object.
RKObjectMapping* map = [RKObjectMapping mappingForClass:[MyPrimitiveResponse class]];
[map addPropertyMapping:[RKAttributeMapping attributeMappingFromKeyPath:nil toKeyPath:@"success"]];
RKResponseDescriptor *errDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:[MyErrorResponse objectMap] method:RKRequestMethodGET pathPattern:nil keyPath:nil statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassServerError)];
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:map method:RKRequestMethodGET pathPattern:nil keyPath:nil statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
NSURL *URL = [NSURL URLWithString:apiUrl];
NSURLRequest *request = [NSURLRequest requestWithURL:URL];
RKObjectRequestOperation *objectRequestOperation = [[RKObjectRequestOperation alloc] initWithRequest:request responseDescriptors:@[ errDescriptor, responseDescriptor ]];
[objectRequestOperation setCompletionBlockWithSuccess:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
RKLogInfo(@"Load collection of Articles: %@", mappingResult.array);
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
RKLogError(@"Operation failed with error: %@", error);
}];
[objectRequestOperation start];
I get the following error in the debugger:
2013-10-29 10:23:15.196 TestParser[6988:70b] E app:MyHomeViewController.m:54 Operation failed with error: Error Domain=org.restkit.RestKit.ErrorDomain Code=-1017 "Loaded an unprocessable response (200) with content type 'application/json'" UserInfo=0x8daca20 {NSErrorFailingURLKey=....., NSUnderlyingError=0x8db4cd0 "The operation couldn’t be completed. (Cocoa error 3840.)", NSLocalizedDescription=Loaded an unprocessable response (200) with content type 'application/json'}
UPDATE:
This is my final bits of code to handle this situation. It may prove useful to others...
// Manually Map Request to JSON & send to server
NSDictionary *parameters = [RKObjectParameterization parametersWithObject:payload requestDescriptor:[payload.class requestDescriptor] error:&error];
NSMutableURLRequest* request = [self.apiManager requestWithObject:nil method:RKRequestMethodPOST path:url parameters:parameters];
RKHTTPRequestOperation *requestOperation = [[RKHTTPRequestOperation alloc] initWithRequest:request];
[requestOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
unichar firstChar = [operation.responseString characterAtIndex:0];
NSData *newData;
if (firstChar != '{' && firstChar != '[') {
// Force into JSON array so it can be parsed normally
newData = [[[@"[" stringByAppendingString:operation.responseString] stringByAppendingString:@"]"] dataUsingEncoding:NSUTF8StringEncoding];
} else {
newData = operation.responseData;
}
// Parse JSON response into native object, whether primitive NSNumber (integer or boolean) response or a full fledged JSON error object.
RKResponseDescriptor *errDescriptor = [MyErrorResponse responseDescriptor];
RKObjectResponseMapperOperation* mapper = [[RKObjectResponseMapperOperation alloc] initWithRequest:request response:operation.response data:newData responseDescriptors:@[errDescriptor, [payload.class responseDescriptor]]];
[mapper setDidFinishMappingBlock:^(RKMappingResult *mappingResult, NSError *error) {
if (mappingResult) { //Success
RKLogInfo(@"Load response: %@", mappingResult.firstObject);
} else {
RKLogError(@"Operation failed with error: %@", error);
}
}];
[mapper start];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
RKLogError(@"Operation failed with error: %@", error);
}];
[requestOperation start];
Upvotes: 0
Views: 1241
Reputation: 119041
I saw suggestions to utilize RestKit to build the request, and pass it to AFNetworking
Yes, do that.
but this will not parse a possible error return object
True, but you can use a mapping operation in RestKit to process that. Or, if the error response is relatively simple just use NSJSONSerialization
(or similar) to convert the response.
The 'primitive ID' should be mappable with a nil-keypath
mapping. But you may still have issues in mapping an error response if it isn't being mapped back into the source object used in the POST request.
Upvotes: 1