Mapping nested object with RESTKIT - ios

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

Related

RESTKit - post a large array of objects to server

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"
}
]

RestKit using RKConnectionDescription to sideload data [duplicate]

I'm totally new to RestKit and am struggling somewhat.
JSON:
{
"teams": [
{
"id": 1,
"name": "Team A"
},
{
"id": 2,
"name": "Team B"
}
],
"users": [
{
"id": 1,
"name": "cameron",
"teamId": 1
},
{
"id": 2,
"name": "paul",
"teamId": 2
}
]
}
CoreData:
#interface Team : NSManagedObject
#property (nonatomic, retain) NSNumber * teamId;
#property (nonatomic, retain) NSString * name;
#end
#interface User : NSManagedObject
#property (nonatomic, retain) NSNumber * userId;
#property (nonatomic, retain) NSString * name;
#property (nonatomic, retain) Team * team;
#end
My application logic looks like this:
// team mapping
RKEntityMapping *teamMapping = [RKEntityMapping mappingForEntityForName:#"Team" inManagedObjectStore:[RKManagedObjectStore defaultStore]];
teamMapping.identificationAttributes = #[#"teamId"];
[teamMapping addAttributeMappingsFromDictionary:#{
#"id": #"teamId",
#"name": #"name"
}];
// Register our mappings with the provider
RKResponseDescriptor *teamResponseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:teamMapping
pathPattern:nil
keyPath:#"teams"
statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
[self.objectManager addResponseDescriptor:teamResponseDescriptor];
// user mapping
RKEntityMapping *userMapping = [RKEntityMapping mappingForEntityForName:#"User" inManagedObjectStore:[RKManagedObjectStore defaultStore]];
userMapping.identificationAttributes = #[#"userId"];
[userMapping addAttributeMappingsFromDictionary:#{
#"id": #"userId",
#"name": #"name"
}];
// Register our mappings with the provider
RKResponseDescriptor *userResponseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:userMapping
pathPattern:nil
keyPath:#"users"
statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
[self.objectManager addResponseDescriptor:userResponseDescriptor];
I can't for the life of me work out how to get RestKit to populate the team Property of the user objects.
I've look at so many posts but nothing I try works, is this not a usual use case?
Does anyone know how to do this, help would be very appreciated!
Thanks.
You need to add a transient attribute to your User entity which holds the associated teamId. This needs to be added to your userMapping.
Then, you need to add a relationship definition to your userMapping:
[userMapping addConnectionForRelationship:#"team" connectedBy:#{ #"teamId": #"teamId" }];
This gives RestKit the information it needs to make the connection and instructs it to make the connection as part of the mapping operation.

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"

Foreign key relationship mapping with RestKit

I'm totally new to RestKit and am struggling somewhat.
JSON:
{
"teams": [
{
"id": 1,
"name": "Team A"
},
{
"id": 2,
"name": "Team B"
}
],
"users": [
{
"id": 1,
"name": "cameron",
"teamId": 1
},
{
"id": 2,
"name": "paul",
"teamId": 2
}
]
}
CoreData:
#interface Team : NSManagedObject
#property (nonatomic, retain) NSNumber * teamId;
#property (nonatomic, retain) NSString * name;
#end
#interface User : NSManagedObject
#property (nonatomic, retain) NSNumber * userId;
#property (nonatomic, retain) NSString * name;
#property (nonatomic, retain) Team * team;
#end
My application logic looks like this:
// team mapping
RKEntityMapping *teamMapping = [RKEntityMapping mappingForEntityForName:#"Team" inManagedObjectStore:[RKManagedObjectStore defaultStore]];
teamMapping.identificationAttributes = #[#"teamId"];
[teamMapping addAttributeMappingsFromDictionary:#{
#"id": #"teamId",
#"name": #"name"
}];
// Register our mappings with the provider
RKResponseDescriptor *teamResponseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:teamMapping
pathPattern:nil
keyPath:#"teams"
statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
[self.objectManager addResponseDescriptor:teamResponseDescriptor];
// user mapping
RKEntityMapping *userMapping = [RKEntityMapping mappingForEntityForName:#"User" inManagedObjectStore:[RKManagedObjectStore defaultStore]];
userMapping.identificationAttributes = #[#"userId"];
[userMapping addAttributeMappingsFromDictionary:#{
#"id": #"userId",
#"name": #"name"
}];
// Register our mappings with the provider
RKResponseDescriptor *userResponseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:userMapping
pathPattern:nil
keyPath:#"users"
statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
[self.objectManager addResponseDescriptor:userResponseDescriptor];
I can't for the life of me work out how to get RestKit to populate the team Property of the user objects.
I've look at so many posts but nothing I try works, is this not a usual use case?
Does anyone know how to do this, help would be very appreciated!
Thanks.
You need to add a transient attribute to your User entity which holds the associated teamId. This needs to be added to your userMapping.
Then, you need to add a relationship definition to your userMapping:
[userMapping addConnectionForRelationship:#"team" connectedBy:#{ #"teamId": #"teamId" }];
This gives RestKit the information it needs to make the connection and instructs it to make the connection as part of the mapping operation.

Rails way to change current json output

I'm working with the JSON below. The outer label is missing.
[{
"id":1,
"updated_at":"2012-01-13T17:13:47Z",
"created_at":"2012-01-13T17:13:47Z",
"name":"dave"},
{
"id":2,
"updated_at":"2012-01-13T17:13:55Z",
"created_at":"2012-01-13T17:13:55Z",
"name":"steve"
}]
I think RestKit expects
{***people:***
[{
"id":1,
"updated_at":"2012-01-13T17:13:47Z",
"created_at":"2012-01-13T17:13:47Z",
"name":"dave"},
{
"id":2,
"updated_at":"2012-01-13T17:13:55Z",
"created_at":"2012-01-13T17:13:55Z",
"name":"steve"
}]
}
#interface Data : NSObject {
Person *person;
NSArray *dogs;
}
#property (nonatomic ,retain) Person *person;
#property (nonatomic ,retain) NSArray *dogs;
#end
#interface Person : NSObject {
NSString *name;
NSNumber *personId;
NSDate *updatedAt;
NSDate *createdAt;
}
#property (nonatomic , retain) NSDate * createdAt;
#property (nonatomic , retain) NSDate * updatedAt;
#property (nonatomic , retain) NSNumber *personId;
#property (nonatomic , retain) NSString *name;
#end
Here is my mapping:
RKObjectMapping* userMapping = [RKObjectMapping mappingForClass:[Person class]];
[userMapping mapKeyPath:#"updated_at" toAttribute:#"updatedAt"];
[userMapping mapKeyPath:#"created_at" toAttribute:#"createdAt"];
[userMapping mapKeyPath:#"name" toAttribute:#"name"];
[userMapping mapKeyPath:#"id" toAttribute:#"personId"];
RKObjectMapping* dogMapping = [RKObjectMapping mappingForClass:[Dog class]];
[dogMapping mapKeyPath:#"created_at" toAttribute:#"createdAt"];
[dogMapping mapKeyPath:#"person_id" toAttribute:#"spersonId"];
[dogMapping mapKeyPath:#"name" toAttribute:#"name"];
[dogMapping mapKeyPath:#"updated_at" toAttribute:#"updatedAt"];
[dogMapping mapKeyPath:#"id" toAttribute:#"dogId"];
[[RKObjectManager sharedManager].mappingProvider setMapping:userMapping
forKeyPath:#"person"];
RKObjectRouter * router = [RKObjectManager sharedManager].router;
[router routeClass: [Person class] toResourcePath:#"/people/:personId"];
[router routeClass: [Person class] toResourcePath:#"/people"
forMethod:RKRequestMethodPOST];
RKObjectMapping *personSerializationMapping= [RKObjectMapping mappingForClass:
[NSDictionary class]];
[personSerializationMapping mapKeyPath:#"name" toAttribute:#"person[name]"];
[[RKObjectManager sharedManager].mappingProvider
setSerializationMapping:personSerializationMapping forClass: [Person class]];
Person* dave =[[Person alloc]init ];
dave.name = #"data";
NSLog(#"%#", [daveLiu name]);
//NSLog("name is %#", daveLiu.description );
[[RKObjectManager sharedManager] postObject:dave delegate:self];
UPDATE! I got the above code to work. It will save to the rails server, but I'm getting a keypath error still!
Processing PeopleController#create (for 127.0.0.1 at 2012-01-16 06:12:18) [POST]
Parameters: {"person"=>{"name"=>"data"}}
Person Create (0.4ms) INSERT INTO "people" ("updated_at", "created_at", "name") VALUES('2012-01-16 14:12:18', '2012-01-16 14:12:18', 'data')
Completed in 11ms (View: 1, DB: 0) | 200 OK [http://localhost/people]
W restkit.object_mapping:RKObjectMapper.m:60 Adding mapping error: Could not find an object mapping for keyPath: ''
E restkit.network:RKObjectLoader.m:178 Encountered errors during mapping: Could not find an object mapping for keyPath: ''
Error Domain=org.restkit.RestKit.ErrorDomain Code=1001 "Could not find an object mapping for keyPath: ''" UserInfo=0x4e6c4e0 {=RKObjectMapperKeyPath, NSLocalizedDescription=Could not find an object mapping for keyPath: ''}

Resources