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).
Related
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.
So this is the first time i'm trying to map objects into CoreData, I think I got it right, but I have few issues. First of all, I just don't know if I'm mapping it the right way and the second one is that I get a success response but without objects mapped.
I have 2 objects DbRestError & DbRestCategory. DbRestError contain the error from the server and DbRestCategory contain the category itself. the are both coming back from the same response but RestKit seems unable to map them.
Those are the objects:
DbRestError
#interface DbRestError : NSManagedObject
#property (nonatomic, retain) NSNumber * statusCode;
#property (nonatomic, retain) NSString * errorTitle;
#end
DbRestCategory
#interface DbRestCategory : NSManagedObject
#property (nonatomic, retain) NSString * title;
#property (nonatomic, retain) NSNumber * idNum;
#end
This is how I initialize my CoreData with RestKit:
- (void)setup
{
self.objectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:[self managedObjectModel]];
NSString *path = [RKApplicationDataDirectory() stringByAppendingPathComponent:#"database.sqlite"];
NSLog(#"Setting up store at %#", path);
[self.objectStore addSQLitePersistentStoreAtPath:path
fromSeedDatabaseAtPath:nil
withConfiguration:nil
options:#{ NSInferMappingModelAutomaticallyOption: #YES, NSMigratePersistentStoresAutomaticallyOption: #YES }
error:nil];
[self.objectStore createManagedObjectContexts];
}
This is how I initialize my RestKit client:
- (void)initRestClient
{
NSURL *baseURL = [NSURL URLWithString:kWebServiceBaseURL];
self.manager = [RKObjectManager managerWithBaseURL:baseURL];
[self.manager setRequestSerializationMIMEType:RKMIMETypeJSON];
[self.manager setAcceptHeaderWithMIMEType:RKMIMETypeJSON];
[self.manager addResponseDescriptorsFromArray:[RKObjectManager sharedManager].responseDescriptors];
[self.manager addRequestDescriptorsFromArray:[RKObjectManager sharedManager].requestDescriptors];
[self.manager.HTTPClient.operationQueue setMaxConcurrentOperationCount:MAX_CONCURRENT_OPERATION_COUNT];
[self.manager setManagedObjectStore:[[MainDb sharedDb] objectStore]];
[RKObjectManager setSharedManager:self.manager];
self.requestMethod = RKRequestMethodGET;
self.statusCode = RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful);
RKRoute *categoriesRoute = [RKRoute routeWithClass:[DbRestCategory class] pathPattern:kGetCategories method:self.requestMethod];
categoriesRoute.shouldEscapePath = YES;
[self.manager.router.routeSet addRoute:categoriesRoute];
// ##yosi -- Error Mapping
//
//
RKEntityMapping *errorMapping = [RKEntityMapping mappingForEntityForName:#"DbRestError" inManagedObjectStore:[[MainDb sharedDb] objectStore]];
[errorMapping addAttributeMappingsFromDictionary:#{ #"statusCode" : #"statusCode", #"description" : #"errorTitle" }];
// ##yosi -- Categories Mapping
//
//
RKEntityMapping *categoryMapping = [RKEntityMapping mappingForEntityForName:#"DbRestCategory" inManagedObjectStore:[[MainDb sharedDb] objectStore]];
[categoryMapping addAttributeMappingsFromDictionary:#{ #"id" : #"idNum", #"name" : #"title" }];
RKObjectMapping *categoriesMapping = [RKObjectMapping mappingForClass:[RestCategories class]];
[categoriesMapping addRelationshipMappingWithSourceKeyPath:#"categories" mapping:categoryMapping];
[categoriesMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:#"error" toKeyPath:#"error" withMapping:errorMapping]];
[[RKObjectManager sharedManager] addResponseDescriptor:[RKResponseDescriptor responseDescriptorWithMapping:categoriesMapping
method:self.requestMethod
pathPattern:kGetCategories
keyPath:nil
statusCodes:self.statusCode]];
}
This is how I'm doing the request itself:
[[RKObjectManager sharedManager] getObject:[[DbRestCategory alloc] init] path:nil parameters:nil success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
}];
This is how the JSON looks like:
{
error: {
statusCode: 10,
description: "success"
},
categories: [
{
id: "3",
name: "cate 3"
},
{
id: "4",
name: "cate 4"
},
{
id: "5",
name: "cate 5"
},
{
id: "1",
name: "cate 1"
},
{
id: "6",
name: "cate 6"
},
{
id: "2",
name: "cate 2"
}
]
}
Can someone please help me to understand why i'm getting a response without any objects?
Try the request mapping like this,
// Request Mapping
// Map error
RKEntityMapping *errorMapping = [RKEntityMapping mappingForEntityForName:#"DbRestError" inManagedObjectStore:[[MainDb sharedDb] objectStore]];
[errorMapping addAttributeMappingsFromDictionary:#{ #"statusCode" : #"statusCode", #"description" : #"errorTitle" }];
[[RKObjectManager sharedManager] addResponseDescriptor:[RKResponseDescriptor responseDescriptorWithMapping:errorMapping method:self.requestMethod pathPattern:kGetCategories keyPath:#"error" statusCodes:self.statusCode]];
// Map Category
RKEntityMapping *categoryMapping = [RKEntityMapping mappingForEntityForName:#"DbRestCategory" inManagedObjectStore:[[MainDb sharedDb] objectStore]];
[categoryMapping addAttributeMappingsFromDictionary:#{ #"id" : #"idNum", #"name" : #"title" }];
[[RKObjectManager sharedManager] addResponseDescriptor:[RKResponseDescriptor responseDescriptorWithMapping:categoriesMapping method:self.requestMethod pathPattern:kGetCategories keyPath:#"categories" statusCodes:self.statusCode]];
I have 2 RKObjectManager that configured to use same managedObjectStore.
With the first RKObjectManager I fetch list of objects, and with the second RKObjectManager I want to add data to these objects.
But instead of updating existing objects, new ones are created.
What am I missing?
Here is my code:
RKEntityMapping* serverAppMapping = [RKEntityMapping mappingForEntityForName:#"COApp" inManagedObjectStore:[RKObjectManager coopsiManager].managedObjectStore];
[serverAppMapping addAttributeMappingsFromDictionary:#{
#"id": #"coID"
}];
serverAppMapping.identificationAttributes = #[ #"coID" ];
RKResponseDescriptor *serverAppResponseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:serverAppMapping method:RKRequestMethodGET pathPattern:#"/me/apps" keyPath:#"data.items" statusCodes:[NSIndexSet indexSetWithIndex:200]];
RKEntityMapping *appsMapping = [RKEntityMapping mappingForEntityForName:#"COApp" inManagedObjectStore:[RKObjectManager coopsiManager].managedObjectStore];
[appsMapping addAttributeMappingsFromDictionary:#{
#"trackName": #"name",
#"trackId": #"coID",
#"artworkUrl60":#"imageURL"}];
appsMapping.identificationAttributes = #[ #"coID" ];
[serverAppMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:#"app"
toKeyPath:#"app"
withMapping:appsMapping]];
// register mappings with the provider using a response descriptor
RKResponseDescriptor *appResponseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:appsMapping method:RKRequestMethodGET pathPattern:#"/th/lookup" keyPath:#"results" statusCodes:[NSIndexSet indexSetWithIndex:200]];
[[RKObjectManager appleManager] addResponseDescriptor:appResponseDescriptor];
[[RKObjectManager coopsiManager] addResponseDescriptor:serverAppResponseDescriptor];
NSString* access_token = [[COAuthManager sharedInstance] getUserAccessToken];
NSDictionary *queryParams;
queryParams = [NSDictionary dictionaryWithObjectsAndKeys:access_token, #"access_token", nil];
[[RKObjectManager coopsiManager] getObjectsAtPath:#"/me/apps" parameters:queryParams success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
NSOrderedSet* set = [NSOrderedSet orderedSetWithArray:mappingResult.array];
[me addNewApps:set];
self.objects = [me.newApps mutableCopy];
[self.delegate dataRefrashed];
NSManagedObjectContext *moc = [[RKObjectManager coopsiManager]managedObjectStore].persistentStoreManagedObjectContext;
NSError *error;
if (![moc save:&error]) {
NSLog(#"Fail");
}else{
NSLog(#"luda rest kit objetcs - %#",me.newApps);
}
for (COApp * app in self.objects) {
NSDictionary *queryParams = [NSDictionary dictionaryWithObjectsAndKeys:app.coID, #"id", nil];
[[RKObjectManager appleManager] getObjectsAtPath:[NSString stringWithFormat:#"/th/lookup"] parameters:queryParams success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
// app.app = mappingResult.array[0];
[self.delegate dataRefrashed];
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
[self presentError:error];
}];
}
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
[self presentError:error];
}];
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.
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}