I'm using RestKit 0.2 version in my project. I have a situation where I need to map the response to an already saved it's parent entity.
My Parent Class is Conversation & conversation can have many messages.
First I'm saving the all the conversations in Coredata under Conversation entity.
Then I called this url for get all the messages related to a specific conversations.
http://myUrl/conversations/bdc34e2a-fa1f-4dbe-83b4-3296ff657e93/messages
bdc34e2a-fa1f-4dbe-83b4-3296ff657e93 is my conversation id
Here is my json response.
[
{
"id":"5f67f6f5-934d-403e-ac64-19dbd4defeda",
"sent_at":"2016-06-08T12:24:28+0000",
"read_at":null,
"sender":{ },
"content":"test message",
"attachment":{ }
},
{
"id":"c4d18b33-4c54-4e7e-a964-a5cedc087122",
"sent_at":"2016-06-08T09:59:41+0000",
"read_at":null,
"sender":{ },
"content":"abc test message",
"attachment":{ }
},
My Json response does not have the conversation property, but I need to map all my messages under the relevant conversation.
RKEntityMapping *messageMapping = [RKEntityMapping mappingForEntityForName:[Message entityName] inManagedObjectStore:[[DataStoreManager sharedManager] managedObjectStore]];
[messageMapping addAttributeMappingsFromDictionary:@{
@"id":@"identifier",
@"sent_at": @"date",
@"content": @"message",
}];
messageMapping.identificationAttributes = @[@"identifier"];
I have many to one relationship for messages to conversation.
[messageMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:nil toKeyPath:@"conversation" withMapping:**conversationMapping**]];
But how can I create conversationMapping ?
Edited - Trying with routing & meta data
As @Wain suggested , I'm trying to use restkit routing
// conversation mapping
RKEntityMapping *conversationMapping = [RKEntityMapping mappingForEntityForName:[Conversation entityName] inManagedObjectStore:[[BADataStoreManager sharedManager] managedObjectStore]];
[conversationMapping addAttributeMappingsFromDictionary:@{
@"@metadata.routing.parameters.identifier": @"identifier"
}];
conversationMapping.identificationAttributes = @[@"identifier"];
[messageMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:nil toKeyPath:@"messages" withMapping:conversationMapping]];
here is my response descriptor
RKResponseDescriptor *conversationDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:[EntityMappingProvider messagesResponseMapping] method:RKRequestMethodAny pathPattern:@"/conversations/:identifier/messages" keyPath:nil statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
[[DataStoreManager sharedManager].router.routeSet addRoute:[RKRoute routeWithName:@"conversations" pathPattern:@"/conversations/:identifier/messages" method:RKRequestMethodGET]];
[[DataStoreManager sharedManager] addResponseDescriptor:conversationDescriptor];
[[DataStoreManager sharedManager] getObjectsAtPathForRouteNamed:@"conversations" object:conversation parameters:nil
success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
RKLogInfo(@"response %@",mappingResult);
}
failure:^(RKObjectRequestOperation *operation, NSError *error) {
RKLogInfo(@"error response %@", error.localizedDescription );
}];
object:conversation will be sent when user select one conversation from the conversation list.
But still conversation are not correctly mapped to the messages.
& I can call this method only once, then I'm getting the following error .
reason: 'Cannot add a route with the same name as an existing route.'
but it should be usable to all the conversations , whenever user selects a conversation this method will be called.
Solution
I have used response descriptors to map conversations & users before mapping messages in the conversations. So when I used the response descriptor for the messages in the conversations, it was mapped to previously defined descriptors.
So I had to use pathPattern & specify the response descriptors , then it mapped correctly , as @Wain explained , I have initialized all the response descriptors once & use getObjectsAtPathForRouteNamed several times.
Finally here is my conversation mapping & it's response descriptor
// conversation mapping
RKEntityMapping *conversationMapping = [RKEntityMapping mappingForEntityForName:[Conversation entityName] inManagedObjectStore:[[BADataStoreManager sharedManager] managedObjectStore]];
[conversationMapping addAttributeMappingsFromDictionary:@{
@"@metadata.routing.parameters.identifier": @"identifier"
}];
conversationMapping.identificationAttributes = @[@"identifier"];
[messageMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:nil toKeyPath:@"messages" withMapping:conversationMapping]];
// Response descriptor
RKResponseDescriptor *conversationDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:[EntityMappingProvider messagesResponseMapping] method:RKRequestMethodAny pathPattern:@"/conversations/:identifier/messages" keyPath:nil statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
[[DataStoreManager sharedManager].router.routeSet addRoute:[RKRoute routeWithName:@"conversations" pathPattern:@"/conversations/:identifier/messages" method:RKRequestMethodGET]];
[[DataStoreManager sharedManager] addResponseDescriptor:conversationDescriptor];
[[DataStoreManager sharedManager] getObjectsAtPathForRouteNamed:@"conversations" object:conversation parameters:nil
success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
RKLogInfo(@"response %@",mappingResult);
}
failure:^(RKObjectRequestOperation *operation, NSError *error) {
RKLogInfo(@"error response %@", error.localizedDescription );
}];