Restkit post with nested objects - ios

Hi I'm new to using restkit and I'm confused on how to post nested objects. I am trying to post the following json:
{
"user": {
"id": "77777-795C-4374-9A29-5C12FF8031F7",
"firstname:": "joe",
"lastname": "bob"
},
"device": {
"token": "phPS2sxbRRvoBbdE8e1VT8nFIJ4R8aJ6rdoCJ8iP1luWm3gUJDMnRHBs1SarfosTsIeYMMxwraLCY35B4whaFIISdosHzqa96vkZANHFy5rusHcrnUQuFgJHnsnqOsgxgOPd8QbrZAAxIlmqCt0an5pH69PWZAXcOVuzFilo310oeNW04qWZCWb8GWYMkODcMuUZANCAAFfvZB4ZAyokBADz"
}
}
I am using Restkit version 0.20.3
This is what my mapping looks like:
RKObjectMapping *userMapping = [RKObjectMapping requestMapping];
[userMapping addAttributeMappingsFromDictionary:#{
#"id": #"id",
#"firstname": #"firstname",
#"lastname": #"lastname"
}];
RKObjectMapping *deviceMapping = [RKObjectMapping requestMapping];
[facebookMapping addAttributeMappingsFromDictionary:#{
#"token": #"token"
}];
RKObjectMapping *authMapping = [RKObjectMapping requestMapping];
[authMapping addPropertyMapping:[RKRelationshipMapping
relationshipMappingFromKeyPath:#"user"
toKeyPath:#"user"
withMapping:userMapping]];
[authMapping addPropertyMapping:[RKRelationshipMapping
relationshipMappingFromKeyPath:#"device"
toKeyPath:#"device"
withMapping:deviceMapping]];
RKRequestDescriptor *authDescriptor = [RKRequestDescriptor requestDescriptorWithMapping:authMapping objectClass:[AuthCredentials class] rootKeyPath:nil method:RKRequestMethodPOST];
[manager addRequestDescriptor:authDescriptor];
User *user = [[User alloc] init];
user.id = #"77777-795C-4374-9A29-5C12FF8031F7";
user.firstname = #"joe";
user.lastname = #"bob";
Device *device = [[Device alloc] init];
device.token = #"phPS2sxbRRvoBbdE8e1VT8nFIJ4R8aJ6rdoCJ8iP1luWm3gUJDMnRHBs1SarfosTsIeYMMxwraLCY35B4whaFIISdosHzqa96vkZANHFy5rusHcrnUQuFgJHnsnqOsgxgOPd8QbrZAAxIlmqCt0an5pH69PWZAXcOVuzFilo310oeNW04qWZCWb8GWYMkODcMuUZANCAAFfvZB4ZAyokBADz";
AuthCredentials *cred = [[AuthCredentials alloc] init];
cred.user = user;
cred.device = device;
[manager postObject:cred path:#"/testpost" parameters:nil
success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult)
{
}
failure:^(RKObjectRequestOperation *operation, NSError *error)
{
}];
My error message is the following:
Error Domain=org.restkit.RestKit.ErrorDomain Code=1001 "No mappable object representations were found at the key paths searched." UserInfo=0x9427070 {DetailedErrors=(
), NSLocalizedFailureReason=The mapping operation was unable to find any nested object representations at the key paths searched:
The representation inputted to the mapper was found to contain nested object representations at the following key paths: error
This likely indicates that you have misconfigured the key paths for your mappings., NSLocalizedDescription=No mappable object representations were found at the key paths searched., keyPath=null}

Related

restkit mapping nested array is empty (nested restkit request with json response)

Am i doing something weired here ?
my categories get downloaded and mapped,
product also get downloaded and mapped as logging is saying,
but my products are empty under each category,
thnx!
{
"productsCategories" : [
{
"product" : [
{
"price" : 3.99,
"title" : "Product A"
},
{
"price" : 3.99,
"title" : "ProductB "
}
],
"categoryTitle" : “a category“
}
]
}
RKObjectMapping *productCategoryMapping = [RKObjectMapping mappingForClass:[ProductCategory class]];
[productCategoryMapping addAttributeMappingsFromDictionary:#{
#"categoryTitle": #"tit"
}];
RKObjectMapping* productMapping = [RKObjectMapping mappingForClass:[Product class] ];
[productMapping addAttributeMappingsFromDictionary:#{
#"title": #"tit",
#"price": #"prc"
}];
[productCategoryMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:#"product"
toKeyPath:#"product"
withMapping:productMapping]];
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:productCategoryMapping method:RKRequestMethodPOST pathPattern:#"productByCategory" keyPath:#"productsCategories" statusCodes:[NSIndexSet indexSetWithIndex:200]];
NSURL *url=[NSURL URLWithString:#"http://www.example.com/REST/v2/"];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
RKObjectManager *manager = [RKObjectManager managerWithBaseURL:url];
[manager addResponseDescriptor:responseDescriptor];
NSMutableDictionary *mutableParameters = [NSMutableDictionary dictionary];
[mutableParameters setValue:#"1" forKey:#"id"];
[manager addResponseDescriptor:[RKResponseDescriptor responseDescriptorWithMapping:productCategoryMapping method:RKRequestMethodPOST pathPattern:#"productByCategory" keyPath:#"productsCategories" statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)]];
[manager postObject:request path:#"productByCategory" parameters:mutableParameters success:^(RKObjectRequestOperation *operation, RKMappingResult *result){
self.productCategoryArr=result.array;
[self.tblDetails reloadData];
}failure:^(RKObjectRequestOperation *operation, NSError *error) {
RKLogError(#"Operation failed with error: %#", error);
self.productCategoryArr=nil;
}];
the logging says objects are being mapped for each products but I only get
ProductCategory: 0x7bf53510
ProductCategory: 0x7be57f00
arrays and 0 objects in each
Assuming your ProductCategory class has
NSArray *Product
NSString * tit
Create a top level RKObjectMapping like,
RKObjectMapping * ProductCategoryResponseMapping = [RKObjectMapping mappingForClass: [ProductCategoryResponse class]];
[ProductCategoryResponseMapping addAttributeMappingsFromDictionary:#{
#"productsCategories": #"productsCategories"
}];
And create new class ProductCategoryResponse which should have
NSArray * productsCategories
Use ProductCategoryResponseMapping for Response descriptor.
Now your response will have array of productsCategories, each having array of Products and String tit.

RestKit only saving last item in array of response

I'm sending out a request to get an object with an nested array of data. However, RestKit is only saving the last item in the nested array of data.
For example, here's the JSON response the server is delivering
{
"nutrition_day": {
"id": "5342e9e13138610012420100",
"start_on": "2014-04-07",
"meal_goals": [
{
"id": "5342e9e13138610012410100",
"name": "Breakfast",
"food_entries": [
{
"id": "535429513663320008210000",
"consumed_on": "2014-04-20",
"food_id": 33801,
"serving_id": 29457,
}
]
},
{
"id": "5342e9e13138610012430100",
"name": "Morning Snack",
"food_entries": []
}
]
}
}
However, using the code below, when I attempt to access nutrition_data.meal_goals, I am left with only the last item in the array "Morning Snack" and am not getting "Breakfast"
Mapping:
+ (void)mapping
{
RKObjectMapping *requestMapping = [RKObjectMapping requestMapping];
RKEntityMapping *responseMapping = [RKEntityMapping mappingForEntityForName:#"NutritionDay" inManagedObjectStore:[[RKObjectManager sharedManager] managedObjectStore]];
[requestMapping addAttributeMappingsFromArray:#[#"date"]];
[responseMapping addAttributeMappingsFromArray:#[#"start_on", #"protein_target"]];
[responseMapping setIdentificationAttributes:#[#"start_on"]];
[responseMapping addRelationshipMappingWithSourceKeyPath:#"meal_goals" mapping:[MealGoal responseMapping]];
RKRequestDescriptor *requestDescriptor = [RKRequestDescriptor requestDescriptorWithMapping:requestMapping
objectClass:[NutritionDay class]
rootKeyPath:#"nutrition_day"
method:RKRequestMethodGET];
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:responseMapping
method:RKRequestMethodAny
pathPattern:#"nutrition/days/:date"
keyPath:#"nutrition_day"
statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
[[RKObjectManager sharedManager] addRequestDescriptor:requestDescriptor];
[[RKObjectManager sharedManager] addResponseDescriptor:responseDescriptor];
}
Request:
[[RKObjectManager sharedManager] getObjectsAtPath:#"nutrition/days/2014-12-12" parameters:nil success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
NutritionDay *nut = ((NutritionDay *)mappingResult.firstObject);
NSLog(#"%lu", (long)nut.meal_goals.count); // this always returns 1 when it should be 2
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
NSLog(#"fail");
}];
Is there something I need to do so that RestKit recognizes the entire array of the relationship and saves it?
I would suggest that you should include the id in your mapping and use that as the identification attribute.
meal_goals should be a to-many relationship (with inverse).
Your log should be:
NSLog(#"%lu", (long)nut.meal_goals.count);
Other than those things, the code you show looks correct. Log the entire mapping result to verify the contents.

Retrived null in POST JSON RestKit

I have used RestKit and made a mapping with a managed object. I then use the postObject method but I have a problem when retrieved the body as it maps to null.
RKObjectManager *objectManager = [RKObjectManager managerWithBaseURL:baseURL];
// Serialize to JSON
objectManager.requestSerializationMIMEType = RKMIMETypeJSON;
[RKObjectManager setSharedManager:objectManager];
RKEntityMapping *searchInfoMapping = [RKEntityMapping mappingForEntityForName:NSStringFromClass([Search class]) inManagedObjectStore: objectManager.managedObjectStore];
searchInfoMapping.identificationAttributes = #[ #"faresQueryType" ];
[searchInfoMapping addAttributeMappingsFromDictionary:#{
#"id" : #"ID",
#"type" : #"Type",
#"count" : #"Count",
#"route” : #"route”,
}];
RKObjectMapping *searchInfoRequestMapping =[RKObjectMapping requestMapping];
[searchInfoRequestMapping addAttributeMappingsFromDictionary:#{
#"id" : #"ID",
#"type" : #"Type",
#"count" : #"Count",
#"route” : #"route”,
}];
//Data mapping is a method that returns an RKObjectMapping for my model
RKResponseDescriptor * searchDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:searchInfoMapping pathPattern:nil keyPath:nil statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
[objectManager addResponseDescriptorsFromArray:#[searchDescriptor,]];
//Inverse mapping, to perform a POST
RKRequestDescriptor *requestDescriptor = [RKRequestDescriptor requestDescriptorWithMapping:searchInfoRequestMapping objectClass:[Search class] rootKeyPath:nil];
[objectManager addRequestDescriptor:requestDescriptor];
[appDelegate.objectManager postObject:nil path:#"routes" parameters:postParameters success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
NSLog(#"Success case %#",mappingResult);
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
NSLog(#"Failure in Flight Mapping %#",error);
[alert show];
}];
Edit
//JSON Result
{
"currency": {
"code": "USD",
"name": "U.S. Dollar",
"symbol": "US$",
"exchange_rate": 1
},
"routes": [
{
"id": "MS648-2022:MS985-2110",
"fares": [
{
"price": 745.32,
"description": "Economy",
"deeplink": "http://www.wego.com/flights/providers/2/deeplinks?search_id=CQtxCXQCRfmwhp72PAjopQ&trip_id=RUH:NYC:2013-12-20&fare_id=sky-tours.com:0&route=RUH-JFK",
"provider_code": "sky-tours.com",
"deeplink_params": {
"trip_id": "RUH:NYC:2013-12-20",
"route": "RUH-JFK",
"search_id": "CQtxCXQCRfmwhp72PAjopQ",
"fare_id": "sky-tours.com:0"
}
}
]
}
]
}
You need to supply the Search object instead of nil when you call postObject (currently you have postObject:nil). This tells RestKit which request mapping to use to send the request. As a result of not setting it the server will likely not have all of the required information (it's impossible to tell with the information provided).

RestKitObjectMapping Array off null objects

RestKitObjectMapping Array off null objects
I want to map CapitalImage object in Capital images object property.
//------------------------ The mapping I try to
[RKMIMETypeSerialization registerClass:[RKNSJSONSerialization class]
forMIMEType:#"text/html"];
RKObjectMapping *CapitalImageMap = [RKObjectMapping mappingForClass:[CapitalImage class]];
[CapitalImageMap addAttributeMappingsFromDictionary:#{
#"src": #"src"
}];
RKObjectMapping *CapitalMap = [RKObjectMapping mappingForClass:[Capital class]];
[CapitalMap addAttributeMappingsFromDictionary:#{
#"name": #"name",
#"text": #"text"
}];
[CapitalMap addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:#"images" toKeyPath:#"images" withMapping:CapitalImageMap]];
NSIndexSet *statusCodes = RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful);
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:CapitalMap
method:RKRequestMethodAny
pathPattern:nil
keyPath:nil
statusCodes:statusCodes];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:#"http://www.a10073.de4.dp10.ru/icapitals/capital.php"]];
RKObjectRequestOperation *operation = [[RKObjectRequestOperation alloc] initWithRequest:request responseDescriptors:#[responseDescriptor]];
[operation setCompletionBlockWithSuccess:^(RKObjectRequestOperation *operation, RKMappingResult *result) {
Capital *article = [result firstObject];
NSLog(#"Mapped the article: %# , %#", article.name,article.images.description);
} failure:^(RKObjectRequestOperation *operation, NSError *error) { NSLog(#"Failed with error: %#", [error localizedDescription]); }];
[operation start];
I get this result
2013-09-27 23:20:49.028 iCapitals v2[5099:c07] Mapped the article: London , (
(null),
(null),
(null),
)
LOGS - http://www.a10073.de4.dp10.ru/icapitals/consoleresult.txt
Please check the code and tell what i do wrong, Thanks!!!
Your mappings look correct. The log shows the mapping proceeding correctly. The issue appears to be with the CapitalImage class. Why is it giving a nil description? It could be that that is the only problem. So your log of the array is a list of nil, but the objects do exist.
Try logging the src of each objects. Are you seeing other issues? Did you implement the description method?

Restkit 0.20: POST CoreData relationship with Foreign-Key

I'm struggling a bit with RestKit and CoreData, especially since there are so little examples and documentation out there for RestKit 0.20.
I have an (managed) object Song with a many-to-one relationship with Album. The following code can post JSON, but not in the flattened format, which the server excepts.
// Defined elsewhere
Album *theAlbum;
RKObjectManager *objMan = [self objectManager];
// Response Mapping
RKObjectMapping *responseMapping = [RKObjectMapping mappingForClass:[Song class]];
[responseMapping addAttributeMappingsFromDictionary:#{ #"song": #"songID" }];
NSIndexSet *statusCodes = RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful);
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:responseMapping
pathPattern:#"/api/song"
keyPath:nil
statusCodes:statusCodes];
// Request Mapping
RKObjectMapping *requestMapping = [RKObjectMapping requestMapping];
RKEntityMapping *albumRelationshipMapping = [RKEntityMapping mappingForEntityForName:#"Album" inManagedObjectStore:[objMan managedObjectStore]];
[albumRelationshipMapping addAttributeMappingsFromDictionary:#{#"id": #"albumID", }];
[requestMapping addAttributeMappingsFromDictionary:#{ #"title": #"title", #"length": #"length" }];
[requestMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:#"album"
toKeyPath:#"album"
withMapping:albumRelationshipMapping]];
requestMapping = [requestMapping inverseMapping];
RKRequestDescriptor *requestDescriptor = [RKRequestDescriptor requestDescriptorWithMapping:requestMapping objectClass:[Song class] rootKeyPath:nil];
[objMan addRequestDescriptor:requestDescriptor];
[objMan addResponseDescriptor:responseDescriptor];
// Create a new temporary song object
Song *song = [NSEntityDescription insertNewObjectForEntityForName:#"Song"
inManagedObjectContext:[[objMan managedObjectStore] mainQueueManagedObjectContext]];
song.title = #"Some Title";
song.length = 123;
song.album = theAlbum;
// Post operation
objMan.requestSerializationMIMEType = RKMIMETypeJSON;
RKManagedObjectRequestOperation *operation = [objMan appropriateObjectRequestOperationWithObject:song
method:RKRequestMethodPOST
path:#"/api/song"
parameters:nil];
[operation setCompletionBlockWithSuccess:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
// Success
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
// Failure
}];
[objMan enqueueObjectRequestOperation:operation];
This code will post a JSON body like this:
{"title":"Some Title","length":"123","album":{"id":"6e32ae476815f365"}}
However, the server expects a JSON body like this:
{"title":"Some Title","length":"123","album":"6e32ae476815f365"}
I.e. the relationship album should be a flattened foreign key instead of a nested object. But when I try to alter the albumRelationshipMapping like this:
[albumRelationshipMapping setIdentificationAttributes:#[ #"albumID" ]];
[albumRelationshipMapping addAttributeMappingToKeyOfRepresentationFromAttribute:#"albumID"];
it throws an exception.
(NSInvalidArgumentException', reason: '*** -[NSProxy doesNotRecognizeSelector:allKeys] called!')
Anybody knows what I'm doing wrong here? Or is there example code out there, which can steer me in the right direction?
Sorry if this question was already answered somewhere else. I searched all of stackoverflow and the google groups, but couldn't find a specific solution for my case (RestKit 0.20, CoreData, relationship with just a FK).
Thanks, Dirk
In this case, I think you can simply use the dot notation to get albumID directly (no need to use RKRelationshipMapping)
Try updating your code this way :
// Request Mapping
RKObjectMapping *requestMapping = [RKObjectMapping requestMapping];
RKEntityMapping *albumRelationshipMapping = [RKEntityMapping mappingForEntityForName:#"Album" inManagedObjectStore:[objMan managedObjectStore]];
//[albumRelationshipMapping addAttributeMappingsFromDictionary:#{#"id": #"albumID", }];
//[requestMapping addAttributeMappingsFromDictionary:#{ #"title": #"title", #"length": #"length" }];
[requestMapping addAttributeMappingsFromDictionary:#{ #"title": #"title", #"length": #"length", #"album" : #"album.albumID" }];
//[requestMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:#"album"
// toKeyPath:#"album"
// withMapping:albumRelationshipMapping]];

Resources