RESTKit - post a large array of objects to server - ios

How can I post an array of objects to my server with RESTKit?
I have a custom object called Contact which have some properties like name, phone etc. I would like to send an array of these Contact objects to the server.
The method I know for this is postObject:path:parameters:success:failure, but what object I put here? If I put Contact - how will it know it is an array? and if I put NSArray, how will it know it is a Contact?
My Contact object header file is:
#interface Contact : NSObject
#property (strong, nonatomic) NSString *name;
#property (strong, nonatomic) NSString *phone;
#property (nonatomic) NSInteger order;
#property (strong, nonatomic) NSString *firstName;
#property (strong, nonatomic) NSString *lastName;
#end
my response mapping is:
RKObjectMapping *personMapping = [RKObjectMapping mappingForClass:[Contact class]];
[personMapping addAttributeMappingsFromDictionary:#{
#"username": #"name",
#"firstname" : #"firstName",
#"lastname" : #"lastName",
}];
my response descriptor is:
RKResponseDescriptor *personResponseDescriptorForArrayOfPhones =
[RKResponseDescriptor responseDescriptorWithMapping:personMapping
method:RKRequestMethodANY
pathPattern:#"getUsersInfoByPhones"
keyPath:nil
statusCodes:[NSIndexSet indexSetWithIndex:200]];
my request mapping is:
RKObjectMapping *personRequestMapping = [RKObjectMapping requestMapping ];
[personRequestMapping addAttributeMappingsFromDictionary:#{
#"name": #"username",
#"firstName" : #"firstName",
#"lastName" : #"lastName",
#"phone" : #"usernames"
}];
my request descriptor is:
RKRequestDescriptor *personRequestDescriptor = [RKRequestDescriptor requestDescriptorWithMapping:personRequestMapping
objectClass:[Contact class]
rootKeyPath:nil
method:RKRequestMethodAny];
Does this implementation looks good?
Also, this array I want to send to the server could be very big, around 200-1000 objects. Is that possible with RESTKit?
Update: Actually, I would prefer to send an array of strings (which would be phone numbers), and get from the server the Contact objects I have. How can I set RESTKit to post the array of strings and to expect a response of an array of Contact objects?
The json I need to send looks like this:
{
"usernames":["11","22"]
}
the json I expect to get is:
[
{
"_id" : "53e23a54e811310000955f70",
"profileUpdatesCounter" : 3,
"lastname" : "SMITH",
"firstname" : "BOB",
"username" : "11"
}
]

Related

Mapping nested object with RESTKIT

I'm trying to map a object through the following JSON:
{
"main_email": {"id": 1, "address": "mainemail#email.com"},
"id": 1,
"first_name": "first name",
"last_name": "last name",
}
I have a object called User with the properties:
#property (nonatomic, assign) NSInteger userID;
#property (nonatomic, copy) NSString *firstName;
#property (nonatomic, copy) NSString *lastName;
#property (nonatomic, strong) Email *mainEmail;
And the object Email have the properties:
#property (nonatomic, assign) NSInteger emailID;
#property (nonatomic, copy) NSString *emailAddress;
Now i'm mapping in the User like bellow:
RKObjectMapping *userMapping = [RKObjectMapping mappingForClass:[User class]];
[userMapping addAttributeMappingsFromDictionary:#{#"id": #"userID",
#"first_name": #"firstName",
#"last_name": #"lastName"}];
RKObjectMapping *emailMapping = [RKObjectMapping mappingForClass:[Email class]];
[emailMapping addAttributeMappingsFromDictionary:#{#"main_email.id": #"emailID",
#"main_email.address": #"emailAddress"}];
[userMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:#"mainEmail"
toKeyPath:#"mainEmail"
withMapping:emailMapping]];
This code keeps returning a empty Email object in User.mainEmail
First off your property mapping should be fromKeyPath:#"main_email" toKeyPath:#"mainEmail" the fromKeyPath is the key path in the JSON and the toKeyPath is the attribute/relationship in CoreData.
Second in your email mapping you don't need to prefix each key path with "main_email." when RestKit does nested mapping it will handle this for you (assuming your property mapping is set up properly)
Here is your example with those changes:
RKObjectMapping *userMapping = [RKObjectMapping mappingForClass:[User class];
[userMapping addAttributeMappingsFromDictionary:#{#"id": #"userID",
#"first_name": #"firstName",
#"last_name": #"lastName"}];
RKObjectMapping *emailMapping = [RKObjectMapping mappingForClass:[Email class]];
[emailMapping addAttributeMappingsFromDictionary:#{#"id": #"emailID",
#"address": #"emailAddress"}];
[userMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:#"main_email"
toKeyPath:#"mainEmail"
withMapping:emailMapping]];

Posting an array of objects not working with Restkit [duplicate]

This question already has an answer here:
Restkit request not sending parameters
(1 answer)
Closed 8 years ago.
I have the following two entities
#interface MEContactInfo : NSObject
#property (nonatomic,strong) NSString* phone ;
#property (nonatomic,strong) NSString* email;
#end
#interface MEContact : NSObject
#property (nonatomic,strong) NSString* _id ;
#property (nonatomic,strong) NSString* lastName;
#property (nonatomic,strong) NSString* firstName;
#property (nonatomic,strong) NSString* data ;
#property (nonatomic,strong) NSMutableArray* contactInfos ;
#end
The second entity contact contains the array of contact infos. Now I want to post this to my server but I am not able to do so. My mappings are as following:
RKObjectMapping* contactMapping = [RKObjectMapping mappingForClass:[MEContact class]];
[contactMapping addAttributeMappingsFromArray:#[#"_id",#"lastName",#"firstName",#"data"]];
RKObjectMapping* contactInfosMapping = [RKObjectMapping mappingForClass:[MEContactInfo class]];
[contactInfosMapping addAttributeMappingsFromArray:#[#"email",#"phone"]];
[contactMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:#"contactInfos" toKeyPath:#"contactInfos" withMapping:contactInfosMapping]];
My request descriptor is as following:
requestDescriptor = [RKRequestDescriptor
requestDescriptorWithMapping:[contactMapping inverseMapping]
objectClass: [MEContact class]
rootKeyPath:nil method:RKRequestMethodAny];
Now when I post something like this:
{ firstName:”abc”,
lastName:”xyz”,
contactInfos: [{
email:”test#test.com”,
phone:”9999999999”
}]
}
I receive
{
firstName:”abc”,
lastName:”xyz”,
contactInfos: [ ”test#test.com”,”9999999999”]
}
If I have multiple entries in the contactInfos array, they all are appended to the contactInfos array I receive on the server side. Basically the contactInfo object is flattening in an array. Can you please let me know how I can fix this.
I got it to work. Everything above was correct. The problem was that data was not going as JSON to the server. The solution was that I had to set request serialization MimeType which can be done by doing this
[objectManger setRequestSerializationMIMEType:RKMIMETypeJSON];
Thanks

RestKit RKObjectMapping of a list

I am new to RestKit and am trying to map a json object that contains an array of objects my model. I have debugged and found that the response hits my server --> json is return --> RestKit says the mapping was successful and that I have 1 object mapped... However, the errorCode field and the array of businesses (bList) are both null when I do BusinessObjectModel *response = result.array.firstObject;
in the OnSuccessBlock.
Json:
{
"bList":
[
{
"id": 1,
"name": "aName",
"owner": 1,
"category": 1,
}
{
"id": 2,
"name": "aName2",
"owner": 1,
"category": 1,
}
],
"errorCode": 0
}
Want to map this Json to this objective c object:
BussinessObjectModel Object Mapping:
RKObjectMapping *responseMapping = [RKObjectMapping mappingForClass:[BusinessObjectModel class]];
[responseMapping addAttributeMappingsFromDictionary:#{
#"id": #"business_id",
#"name": #"business_name",
}];
return responseMapping;
BModel:
#interface bModel : NSObject
#property (nonatomic, copy) NSNumber *errorCode;
#property (nonatomic, copy) NSMutableArray *bList;
+(RKObjectMapping *) getMapping;
#end
BModel Object Mapping:
RKObjectMapping *bMapping = [BusinessObjectModel getMapping];
RKObjectMapping *buslstMapping = [RKObjectMapping mappingForClass:[BModel class]];
[buslstMapping addAttributeMappingsFromDictionary:#{#"errorCode": #"errorCode"}];
// Define the relationship mapping
[buslstMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:nil
toKeyPath:nil
withMapping:bussinessMapping]];
return buslstMapping;
Descriptor looks as follows:
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:ResponseMapping method:RKRequestMethodAny pathPattern:nil keyPath:#"bList" statusCodes:nil];
EDIT
I want to map the above Json to :
#interface bModel : NSObject
#property (nonatomic, copy) NSNumber *errorCode;
#property (nonatomic, copy) NSMutableArray *bList;
#end
Where bList is an array of the following object:
#interface Business : NSObject
#property (nonatomic, copy) NSNumber *id;
#property (nonatomic, copy) NSString *name;
#property (nonatomic, copy) NSNumber *id;
#property (nonatomic, copy) NSNumber *id;
#end
I guess the question is how do I do nested relationships (what would the Response Descriptor have to be for the above relationship)?
Great to see that your using RestKit. Your first helper will be the logging that RestKit provides. Add this line of code do your AppDelegate and watch the console for errors.
// The * will send everything RestKit does to the console
// Replace the * with the module you want to check (Network/CoreData/...)
RKLogConfigureByName("RestKit/*", RKLogLevelTrace);
When looking at your JSON you want to get the objects from the keyPath "bList" on the one hand and on the other hand the error code or message when something goes wrong. RestKit provides a build in error handling to get that information out of your JSON.
Init the RKObjectMapping for the RKErrorMessage class and add a RKResponseDescriptor to your requests with the right keyPaths including the range of status codes (here using client errors). RestKit will automatically detect the error code (when sent within the header) and apply the mapping to get the content of the error message.
// Init error mapping
RKObjectMapping *errorMapping = [RKObjectMapping mappingForClass:[RKErrorMessage class]];
[errorMapping addPropertyMapping:[RKAttributeMapping attributeMappingFromKeyPath:nil toKeyPath:#"errorMessage"]];
// Add mapping as response descriptor
RKResponseDescriptor *errorDescriptor =
[RKResponseDescriptor responseDescriptorWithMapping:errorMapping
method:RKRequestMethodGET
pathPattern:nil
keyPath:#"message" // Edit the keyPath to the value of your JSON (e.g. errorCode)
statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassClientError)];
[RKObjectManager.sharedManager addResponseDescriptor:errorDescriptor];
To get the error message when a failure occurs, you simply get the message object. When using a block to get objects, you can use the userInfo dictionary from the given NSError.
RKErrorMessage *errorMessage = [[error.userInfo objectForKey:RKObjectMapperErrorObjectsKey] firstObject];
NSLog(#"Error: %#", errorMessage);
Now you can simplify your object model a bit and concentrate on mapping the BusinessObjectModel. When mapping the object using the dictionary, you need to check of your local attributes matches the value in your JSON.
RKObjectMapping *responseMapping = [RKObjectMapping mappingForClass:[BusinessObjectModel class]];
[responseMapping addAttributeMappingsFromDictionary:#
{
#"value_from_remote_json": #"value_in_local_object", // e.g. #"id" : #"business_id"
...
}];
return responseMapping;
You don't need to use a RKRelationshipMapping any more. Reconfigure your objects/mappings and try again. The logging will show you the provided mapping and if the mapping operations are working. Last bit not least make sure that the mapping is in memory when using it by throwing an NSAssert error.
RKObjectMapping *bMapping = [BusinessObjectModel getMapping];
NSAssert(bMapping, #"bMapping mapping must not be nil");
Edit
To map values without a keyPath (like the "errorCode" field) additionally to the mapping of your objects, you'll need to provide an object with an according mapping. Taking the example from the documentation you'll end with something like:
// Init object
#interface RKErrorCode : NSObject
#property (nonatomic) NSNumber *errorCode;
#end
// Init mapping
RKObjectMapping *codeMapping = [RKObjectMapping mappingForClass:[RKErrorCode class]];
[codeMapping addPropertyMapping:[RKAttributeMapping attributeMappingFromKeyPath:nil toKeyPath:#"errorCode"]];
// Add response descriptor for request
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:codeMapping method:RKRequestMethodAny pathPattern:nil keyPath:#"errorCode" statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
[[RKObjectManager sharedManager] addResponseDescriptor:responseDescriptor];
Your response descriptor shouldn't have keyPath:#"bList", it should be set to nil as you don't want to drill in.
It also shouldn't use ResponseMapping based on the structure of your mappings, it should use the other mapping.
Your mapping is also wrong here:
#{
#"business_id": #"business_id",
#"business_name": #"business_name",
}];
It should be:
#{
#"id": #"business_id",
#"name": #"business_name",
}];
Because this specifies the JSON names and the core data names.
To fix your new issues, put this back:
[buslstMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:#"bList" toKeyPath:#"bList"
And this:
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:buslstMapping method:RKRequestMethodAny pathPattern:nil keyPath:nil statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
Found the solution and it looks something like this:
RKObjectMapping *bModelMapping = [RKObjectMapping mappingForClass:[business class]];
[bModelMapping addAttributeMappingsFromDictionary:#{
#"id": #"business_id",
#"name": #"business_name",
}];
RKObjectMapping *buslstMapping = [RKObjectMapping mappingForClass:[bModel class]];
[buslstMapping addAttributeMappingsFromDictionary:#{#"errorCode": #"errorCode"}];
// Define the relationship mapping
[buslstMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:#"bList"
toKeyPath:#"bList" bModelMapping]];
return buslstMapping;
Also Change the following:
#property (nonatomic, copy) NSMutableArray *bList;
to
#property (nonatomic, retain) NSArray *bList;
This gives me a bModel object with an error code value and a bList which is an array of business which can then be cast to a business by doing the following Business *business = [bModel.blist firstObject];

RestKit : how to map an array with correct type?

Got:
#property(nonatomic, retain) NSString *user;
#property(nonatomic, retain) NSString *token;
#property(nonatomic, retain) NSArray *list;// NSNumber only please!
And:
RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[MyResponse class]];
[mapping addAttributeMappingsFromDictionary:#{
#"user" : #"user",
#"token" : #"token",
#"list" : #"list",
}];
And I receive Json:
{"user":"foobar","token":"azerty","list":[0,1,"2"]}
Unfortunately, list will be a mix of NSString and NSNumber. How to tell RestKit 0.2x I only want NSNumber or NSString in my NSArray?
RestKit uses KVC so surely if you just want numbers you could use the appropriate keyPath e.g. if I wanted the numbers to always be integers I could use the method integerValue which both NSNumber and NSString have:
RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[MyResponse class]];
[mapping addAttributeMappingsFromDictionary:#{
#"user" : #"user",
#"token" : #"token",
#"list.integerValue" : #"list",
}];
Rather than rewriting a JSON parser to do your particular task, why not just post-process 'list' and check each object with if([list[i] isKindOfClass:[NSString class]]) and convert it to an NSNumber?

Restkit mapping objects to NSArray

I have an object that consists of some fields such as:
#property (nonatomic, copy) NSString* title;
#property (nonatomic, copy) NSString* body;
#property (nonatomic, copy) NSArray* imageUrls;
#property (nonatomic, copy) NSString* postId;
#property (nonatomic) CLLocationCoordinate2D location;
#property (nonatomic) LTUser *user;
#property (nonatomic) LTPlace *place;
#property (nonatomic, copy) NSArray* comments;
All NSString and custom objects (such as LTUser/LTPlace) and it is mapping well.
But, how can I map to the NSArray of (imageUrls - which is an array of NSString / comments - which is an array of custom objects (LTComment))?
"images": [
"http://****.com/images/1385929903887.jpg",
"http://****.com/images/131315313131.jpg",
"http://****.com/images/1351351351.jpg"
]
Mapping for main object:
RKObjectMapping *userMapping = [RKObjectMapping mappingForClass:[LTUser class]];
[userMapping addAttributeMappingsFromDictionary:#{
#"_id":#"userId",
#"username":#"userName",
#"name":#"name"
}];
RKObjectMapping *placeMapping = [RKObjectMapping mappingForClass:[LTPlace class]];
[placeMapping addAttributeMappingsFromDictionary:#{
#"_id":#"placeId",
#"image":#"name",
#"name":#"image"
}];
RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[LTPost class]];
[mapping addAttributeMappingsFromDictionary:#{
#"_id" : #"postId",
#"createdAt" : #"createdAt",
#"body" : #"body",
#"title" : #"title"
}];
[mapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:#"user" toKeyPath:#"user" withMapping:userMapping]];
[mapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:#"place" toKeyPath:#"place" withMapping:placeMapping]];
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:mapping
method:RKRequestMethodGET
pathPattern:kLTAPIGetPostsRequest
keyPath:#"posts"
statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
[[RKObjectManager sharedManager] addResponseDescriptor:responseDescriptor];
LTComment mapping
RKObjectMapping* commentMapping = [RKObjectMapping mappingForClass:[LTComment class]];
[commentMapping addAttributeMappingsFromDictionary:#{
#"user_name":#"userName",
#"text":#"text"
}];
The mapping for comments should be just like you mappings for user and place (just with a different mapping obviously, commentMapping). RestKit will determine that the destination is a collection and that the source is a collection and do the right thing.
For imageUrls, the JSON is already an array of strings so RestKit can basically copy it. All you need to do is add to the 'container' mapping (whichever that one is):
#"images" : #"imageUrls"

Resources