I have JSON of following kind
{
"Client": {
"FirstName": "String",
"LastName": "String",
"Email": "String",
"Password": "String",
"PhoneNumber": "String",
"Token": "String"
},
"ErrorMessage": "String",
"FriendlyMessage": "String"
}
I know that while mapping if I specify a key path then RestKit matches fields from object specified, in this case Client, to the code I am using for that is as follows
[responseMapping addAttributeMappingsFromDictionary:#{
#"FirstName": #"FirstName",
#"LastName": #"LastName",
#"Email": #"Email",
#"PhoneNumber": #"PhoneNumber",
#"Token": #"Token",
#"Password": #"Password",
#"ErrorMessage": #"ErrorMessage"}];
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:responseMapping
method:RKRequestMethodPOST
pathPattern:nil
keyPath:#"Client"
statusCodes:[NSIndexSet indexSetWithIndex:200]];
But I have two additional fields to map which aren't under client object. How do I map ErrorMessage and FriendlyMessage fields ?
Generally you wouldn't want to map them into your client object, you would want to map them into some other object. You would usually use a different object and response mapping, where the response mapping uses a different key path.
If for some reason you did want them in the same object then you could look at using the #metadata / #parent to get to the parent (https://github.com/RestKit/RestKit/pull/1435).
Related
The API need to pass an array in an url query parameter, how to acheive this in iOS?
I only know how to pass a single vaue, like the API below : ?title=Design Milk&id=feed/http://feeds.feedburner.com/design-milk
API sample:
"title": "Design Milk",
"id": "feed/http://feeds.feedburner.com/design-milk",
"categories": [
{
"id": "user/c805fcbf-3acf-4302-a97e-d82f9d7c897f/category/design",
"label": "design"
},
{
"id": "user/c805fcbf-3acf-4302-a97e-d82f9d7c897f/category/weekly",
"label": "weekly"
},
{
"id": "user/c805fcbf-3acf-4302-a97e-d82f9d7c897f/category/global.must",
"label": "must reads"
}
]
Create a collection and then use NSJSONSerialization to create JSON data representation. Use the resulting data as the POST data.
NSDictionary *parameters = #{
#"title": #"Design Milk",
#"id": #"feed/http://feeds.feedburner.com/design-milk",
#"categories": #[
#{
#"id": #"user/c805fcbf-3acf-4302-a97e-d82f9d7c897f/category/design",
#"label": #"design"
},
#{
#"id": #"user/c805fcbf-3acf-4302-a97e-d82f9d7c897f/category/weekly",
#"label": #"weekly"
},
#{
#"id": #"user/c805fcbf-3acf-4302-a97e-d82f9d7c897f/category/global.must",
#"label": #"must reads"
}
]
};
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dictData options:0 error:&error];
I have the following JSON structure which I want to map with RestKit in CoreData:
[
{
"id": 1,
"type": "folder",
"name": "Folder 1",
"children": [
{
"id": 1,
"type": "document",
"name": "Document 1"
},
{
"id": 2,
"type": "folder",
"name": "Folder 2",
"children": [
{
"id" : 2,
"type": "document",
"name": "Document 2"
}
]
}
]
}
]
It's a typical filesystem structure where a folder can contain other folders or documents.
I have two CoreData entities: Folder and Document.
The Folder entity has the following relationships:
Here is my Mapping Code:
RKEntityMapping* foldersMapping = [RKEntityMapping mappingForEntityForName:#"Folder" inManagedObjectStore:managedObjectStore];
foldersMapping.identificationAttributes = #[ #"objectId" ];
[foldersMapping addAttributeMappingsFromDictionary:#{#"id" : #"objectId",
#"name" : #"name"}];
RKEntityMapping* documentsMapping = [RKEntityMapping mappingForEntityForName:#"Document" inManagedObjectStore:managedObjectStore];
documentsMapping.identificationAttributes = #[ #"objectId" ];
[documentsMapping addAttributeMappingsFromDictionary:#{#"id" : #"objectId",
#"name" : #"name"}];
In my dynamic mapping I use the type of the object to decide if it is a document or a folder.
RKDynamicMapping* dynamicMapping = [RKDynamicMapping new];
[dynamicMapping setObjectMappingForRepresentationBlock:^RKObjectMapping *(id representation) {
if ([[representation valueForKey:#"type"] isEqualToString:#"Folder"]) {
return foldersMapping;
} else if ([[representation valueForKey:#"type"] isEqualToString:#"Document"]) {
return documentsMapping;
}
return nil;
}];
Now I added the dynamic mapping as relationship mapping to the folder mapping for the property children two times.
[foldersMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:#"children" toKeyPath:#"children" withMapping:dynamicMapping]];
[foldersMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:#"children" toKeyPath:#"documents" withMapping:dynamicMapping]];
And here is my Problem: All this works, but I got the following Warnings:
RestKitNesterFolderTestProject[9969:3a03] W
restkit.object_mapping:RKMappingOperation.m:554 WARNING: Failed
mapping nested object: The operation couldn’t be completed. (Cocoa
error 1550.)
I think the Problem is that I doubled the mapping for the relationship children, so RestKit tries to map each child two times, once as Folder and once as Document.
Any help is appreciated.
I am searching a way to map 2 different arrays with the following JSON
"establishments": [
{
"id": 1,
"name": "Boudin Sourdough Bakery and Cafe",
"address": "1 Stockton St",
"zip_code": "94108",
"city": "San Francisco",
"country": "us",
"phone_number": "",
"position": {
"latitude": 37.78590500000001,
"longitude": -122.406289
},
"distance_from": 13.75783097391759
}
],
"places": [
{
"id": 3,
"name": "Private Place",
"position": {
"latitude": 37.78583400000001,
"longitude": -122.406417
},
"is_private": false,
"distance_from": 0
}
]
I have 2 different mappings. One for establishment and another for place. I found some help with the documentation but it's working only for PUT or POST requests.
Currently, I have the following request
[session.objectManager getObjectsAtPathForRouteNamed:APICallSearchSearchPlaceRouteName object:nil parameters:params success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
NSArray * resultPlaces=mappingResult.array;
[delegate APICallDidSearch:resultPlaces];
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
NSError* myError=[self catchCustomErrorInRKError:error setDomain:#"Search"];
if (myError.code == NSURLErrorCancelled) return;
[delegate APICallDidFailSearch:myError];
}];
Mapping & Mapping Descriptor
RKEntityMapping *establishmentMapping = [APICallEstablishment RKGetEstablishmentMappingForManagedObjectStore:self.appDelegate.managedObjectStore];
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:establishmentMapping
method:RKRequestMethodGET
pathPattern:APICallSearchSearchPlacePattern
keyPath:#"establishments"
statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
[session.objectManager addResponseDescriptor:responseDescriptor];
I tried to adapt the example to my case with that (just before my request written above)
RKManagedObjectRequestOperation *operation = [session.objectManager appropriateObjectRequestOperationWithObject:establishmentMapping method:RKRequestMethodGET path:#"/whatever" parameters:nil];
operation.targetObject = nil;
//Does it still exist ? (XCode says an error)
//operation.targetObjectID = nil;
[session.objectManager enqueueObjectRequestOperation:operation];
Thank you in advance for your help.
Using session.objectManager getObjectsAtPathForRouteNamed... is a good option (better than trying to use RKManagedObjectRequestOperation directly).
You need to create another response descriptor, like responseDescriptor, but for places key path and mapping.
I am using RestKit to map the following JSON to core data.
This is my model:
this is my methods:
RKEntityMapping *userMapping = [RKEntityMapping mappingForEntityForName:NSStringFromClass([User class]) inManagedObjectStore:managedObjectStore];
userMapping.identificationAttributes = #[#"id"];
[userMapping addAttributeMappingsFromDictionary:#{
#"birthday":#"birthday",
#"email":#"email",
#"facebook_token":#"facebook_token",
#"first_name":#"first_name",
#"gender":#"gender",
#"interested_in":#"interested_in",
#"last_name":#"last_name",
#"password":#"password",
#"m8_status":#"m8_status",
#"status":#"status",
#"languages": #"languages",
#"hometown":#"hometown",
#"location":#"location",
#"avatar_url":#"avatar_url",
#"mood":#"mood"
}];
RKEntityMapping *findUserMapping = [RKEntityMapping mappingForEntityForName:NSStringFromClass([FindUser class]) inManagedObjectStore:managedObjectStore];
findUserMapping.identificationAttributes = #[#"id"];
[findUserMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:#"users" toKeyPath:#"users" withMapping:userMapping]];
[manager addResponseDescriptorsFromArray:#[
[RKResponseDescriptor responseDescriptorWithMapping:findUserMapping
pathPattern:#"/v1/users"
keyPath:nil statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)]
]];
This is getting objects from example JSON:
{
"users": [
{
"avatar_url": null,
"birthday": "04/11/1984",
"email": "antonina.duminskaya#wildermancruickshank.co.uk", "first_name": "Antonina",
"gender": "female",
"hometown": null,
"id": "5264ee384d61632c4b2f0000",
"interested_in": [
"male",
"female" ],
"languages": [], "last_name": "Duminskaya", "location": null, "m8_status": null,
"mood": null,
"status": null
} ]
}
here:
[objectManager getObjectsAtPath:#"/v1/users" parameters:#{#"session_id":session.id} success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
FindUser *findUsers = [[self.fetchedFindUsersResultsController fetchedObjects] lastObject];
NSLog(#"%#", findUsers.users);
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
}];
I have message in log:
Relationship 'users' fault on managed object (0x8e964a0) <FindUser: 0x8e964a0> (entity: FindUser; id: 0x8da0790 <x-coredata://083BB731-FDD7-4A35-A174-724F50862A02/FindUser/p1> ; data: {
id = nil;
users = "<relationship fault: 0x8deb260 'users'>";
})
And In mappingResults I have all results about json
Core Data is representing the relationship initially as fault saving memory by not loading all the object graph at once.
https://developer.apple.com/library/ios/documentation/cocoa/conceptual/CoreData/Articles/cdFaultingUniquing.html
Also, do not use the reserved word 'id' as the Restkit identification attribute for your managed objects. Try using findUserId and userId and update your mappings accordingly.
I have the following JSON structure:
{
"category": "MyCategory"
"objects": [
{ "id": 1, "name": "A" },
{ "id": 2, "name": "B" },
{ "id": 3, "name": "C" }
]
}
I'm mapping each object to a separate Core Data entity like this:
RKEntityMapping *mapping = [RKEntityMapping mappingForEntityForName:#"Object" inManagedObjectStore:manager.managedObjectStore];
mapping.identificationAttributes = #[ #"id" ];
[mapping addAttributeMappingsFromDictionary:#{ #"name": #"name" }];
How do I configure the mapping to store their shared category on each object?
The thing I would like is to be able to traverse upwards in the JSON like this:
[mapping addAttributeMappingsFromDictionary:#{ #"name": #"name", #"PARENT.category": #"category" }];
As of now (RestKit 0.20.1), there is no way to do this by using the mapping engine.
FUTURE
There is a new metadata feature under development making it possible to access the parent object:
[mapping addAttributeMappingsFromDictionary:#{ #"name": #"name", #"#metadata.parentObject.category": #"category" }];
PRESENT
I'm modifying my deserialized response using willMapDeserializedResponseBlock. I've added a category on RKObjectManager to make it easy to modify the response:
https://gist.github.com/gunnarblom/5677324