RestKit understand what to put in "pathPattern" and "keyPath" in RKResponseDescriptor - ios

I would like to use RestKit but I don't see how to write the pathPattern and the keyPath, where the json returns :
{
"photos": {
"page": 1,
"pages": 39594,
"perpage": 10,
"total": "395933",
"photo": [
{
"id": "16766829152",
"owner": "32546988#N00",
"secret": "5b38b40c57",
"server": "8744",
"farm": 9,
"title": "City box lights",
"ispublic": 1,
"isfriend": 0,
"isfamily": 0
}
]
}
}
The error :
Error Domain=org.restkit.RestKit.ErrorDomain Code=1001 "No mappable object representations were found at the key paths searched
This is what I have now :
#define kBaseRESTURL #"https://api.flickr.com/services/rest/?method="
#define kSearchMethod #"flickr.photos.search"
-(void)configureRestKit{
NSString *url = [NSString stringWithFormat:#"%#%#", kBaseRESTURL, kSearchMethod];
NSURL *baseURL = [NSURL URLWithString:url];
AFHTTPClient* client = [[AFHTTPClient alloc] initWithBaseURL:baseURL];
RKObjectManager *manager = [[RKObjectManager alloc] initWithHTTPClient:client];
RKObjectMapping* photoMapping = [RKObjectMapping mappingForClass:[Photo class]];
[photoMapping addAttributeMappingsFromArray:#[#"title"]];
RKResponseDescriptor *responseDesc = [RKResponseDescriptor responseDescriptorWithMapping:photoMapping method:RKRequestMethodGET pathPattern:#"" keyPath:#"photos.photo" statusCodes:[NSIndexSet indexSetWithIndex:200]];
[manager addResponseDescriptor:responseDesc];
}
-(void)loadCities : (void(^)(NSArray*))completion {
[self configureRestKit];
NSDictionary *queryParams = #{#"api_key" : apiKey,
#"tags" : #"cities",
#"per_page" : #"10",
#"format" : #"json",
#"nojsoncallback" : #"1"
};
[[RKObjectManager sharedManager] getObjectsAtPath:#"" parameters:queryParams success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
NSLog(#"ok");
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
NSLog(#" ");
NSLog(#"error : %#", error);
}];
}
Thanks

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 response only first KVC in mapping result dictionary or array

I'm receiving a dictionary from my restkit request as respond but only one of values are included. I am missing bunch of KV from my JSON.
JSON response from API:
{"categories" : [
{
"status" : 1,
"rest_id" : 1,
"id" : 1,
"title" : "01. BasicC",
"description" : "basic description"
},
{
"status" : 1,
"rest_id" : 1,
"id" : 26,
"title" : "01. Deli",
"description" : "deli description"
}
]}
IOS Function to request:
- (void)loadProduct{
_categoriesDic=[[NSDictionary alloc]init];
RKObjectMapping* productMapping = [RKObjectMapping mappingForClass:[ProductCategory class]];
[productMapping addAttributeMappingsFromDictionary:#{
#"id": #"id",
#"rest_id": #"rest_id",
#"title": #"title",
#"description": #"description",
#"status":#"status"
}];
RKLogConfigureByName("RestKit/Network", RKLogLevelTrace);
RKLogConfigureByName("RestKit/ObjectMapping", RKLogLevelTrace);
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:productMapping method:RKRequestMethodPOST pathPattern:nil keyPath:#"categories" statusCodes:[NSIndexSet indexSetWithIndex:200]];
RKObjectManager *objectManager = [[RKObjectManager alloc] init];
[objectManager addResponseDescriptor:responseDescriptor];
NSString *jsonRequest = [NSString stringWithFormat:#"id=1"];
NSURL *url=[NSURL URLWithString:#"http://example.com/REST/v2/productCategories"];
NSData *json_data = [NSData dataWithBytes:[jsonRequest UTF8String] length:[jsonRequest length]];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setHTTPMethod:#"POST"];
[request setHTTPBody: json_data];
RKObjectRequestOperation *objectRequestOperation = [[RKObjectRequestOperation alloc] initWithRequest:request responseDescriptors:#[ responseDescriptor ]];
[objectRequestOperation setCompletionBlockWithSuccess:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
RKLogInfo(#"Load collection of Categories: %#", mappingResult.dictionary);
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
RKLogError(#"Operation failed with error: %#", error);
}];
[objectRequestOperation start];
}
response:
Load collection of Categories: {
categories = (
"basic description",
"deli description"
);
}
While your code does some slightly odd things (like create an empty immutable dictionary, and POST to an endpoint which should be using a GET) it does appear to work. It looks like you just aren't fully understanding the response, and that's because you are inadvertently overriding a built in method.
The log you show contains:
{
categories = (
"basic description",
"deli description"
);
}
is the description of a dictionary which contains 1 key (categories), which is an array of 2 objects. Now, those 2 objects have their description method called as well in order to generate the log contents. Unfortunately, you have a property called description so that is accessed instead of the superclass implementation., and hence you just get the descriptions.
Now, that doesn't mean the mapping hasn't worked, just that the log is misleading.
You should change the description on your destination object to another name, like overview and then your log will be meaningful (and you won't see similar issues in future).

Mapping an object to CoreData with 2 classes

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]];

RestKit: How can I send object through post protocol in some key?

I want send object through post protocol to server. I use for it RestKit framework.
so, example:
PData *item = [[PData alloc] init];
item.uri = #"http://google.com";
item.status = #"0";
item.updated = [NSDate date];
item.created = [NSDate date];
item.user_id = #"3";
RKObjectManager *sharedManager = RKObjectManager sharedManager;
[sharedManager postObject:item
path:nil
parameters:nil
success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
[self printPData:mappingResult];
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
NSLog(#"\n\n\n == \nERROE = %#",error);
}];
How can I push json (which consist data of item) in some key ("data")?
(this data on server I can take from $_POST["data"])
How can I do request like this?
{
"data": {
"created": "2014-03-05 14:49:30",
"status": "0",
"updated": "2014-03-05 14:49:30",
"uri": "http:\/\/google.com",
"user_id": "3"
}
}
now, I have had only this:
{
"status": "0",
"updated": "2014-03-05 14:52:17",
"user_id": "3",
"uri": "http:\/\/google.com",
"created": "2014-03-05 14:52:17"
}
It sounds like you haven't specified a key path in your request descriptor. At the moment, somewhere in your code, you'll have something like this:
RKRequestDescriptor *descriptor =
[RKRequestDescriptor requestDescriptorWithMapping:mapping
objectClass:[PData class]
rootKeyPath:nil
method:RKRequestMethodAny];
You need to change it to:
RKRequestDescriptor *descriptor =
[RKRequestDescriptor requestDescriptorWithMapping:mapping
objectClass:[PData class]
rootKeyPath:#"data"
method:RKRequestMethodAny];
That way RestKit will know that PData objects ought to be mapped to the data key path.

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).

Resources