Marc O. Alfonso
Marc O. Alfonso

Reputation: 53

Mapping a primitive json response with RestKit v0.21

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

Answers (1)

Wain
Wain

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

Related Questions