RESTKit POST Request Tutorial - ios

I would like to know if there is a specific tutorial on how to do a POST request with RESTKit. I have looked at some tutorials but I haven't found any that say, "This is exactly how you do a POST request with RESTKit." Help is much appreciated.

Assuming you already have a mapped model, you can simply perform this:
First, set a requestDescriptor with the inverseMapping of your responseDescriptor, assuming you have one with your mapping.
//This is used for mapping responses, you already should have one of this. PS:[Data mapping] is a method that returns an RKObjectMapping for my model. You should create yours or use a previous created one
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:[Data mapping] pathPattern:nil keyPath:#"data" statusCodes:statusCodeSet];
[[RKObjectManager sharedInstance] addResponseDescriptor:responseDescriptor];
//Inverse mapping, to perform a POST
RKRequestDescriptor *requestDescriptor = [RKRequestDescriptor requestDescriptorWithMapping:[[Data mapping] inverseMapping] objectClass:[Data class] rootKeyPath:nil];
[[RKObjectManager sharedInstance] addRequestDescriptor:requestDescriptor];
After that, to perform a POST, just simply call the method below. Restkit will get the instance that you are trying to post, serialize it and send to the path chosen.
[[RKObjectManager sharedInstance] postObject:instanceOfYourModel path:yourPathHere parameters:nil success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
NSLog(#"Success");
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
NSLog(#"Error");
}];
If you don't have a mapped model, let me know so we can try something else.

Related

RestKit 0.24 || getObjectsAtPath || resulting object has NSString parameters set to NSNull

I am having NSString parameters in my object getting set to NSNull when null is returned in the JSON. I would like the the NSString to be set to nil. Any Ideas?
I have tried setting [mapping setAssignsDefaultValueForMissingAttributes:NO]; but that does not seem to work even when I implement changes from Fix 1714. I'm really just spinning my wheels at this point.
Here is everything I have for making this call so far.
Returned JSON
{
val1 = "something";
val2 = "<null>";
}
Class cMyClass
#interface cMyClass : NSObject {
NSString *val1;
NSString *val2;
}
RKObjectMapping
RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[cMyClass class]];
[mapping addAttributeMappingsFromDictionary:#{#"val1":#"val1", #"val2":#"val2"}];
RKResponseDescriptor
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:mapping method:RKRequestMethodAny pathPattern:#"GetMyClass" keyPath:nil statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
RKObjectManager
NSURL *baseURL = [NSURL URLWithString:#"http://www.domain.com/MyAPI.svc/rest"];
RKObjectManager *objectManager = [RKObjectManager managerWithBaseURL:baseURL];
[objectManager addResponseDescriptor:responseDescriptor];
objectManager.requestSerializationMIMEType = RKMIMETypeJSON;
[objectManager.HTTPClient setDefaultHeader:#"Accept" value:RKMIMETypeJSON];
[objectManager.HTTPClient setParameterEncoding:AFJSONParameterEncoding];
API Call
NSDictionary *params = ...
objectManager getObjectsAtPath:#"GetMyClass" parameters:params success:(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
completionBlock:(mappingResult.array[0]);
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
failureBlock(error);
}];
I'm grasping at straws since I am just starting out with Restkit myself...but, do you perhaps think there might be an issue with the mappings?
It looks like the values in your cMyClass are ivars instead of properties. If I am not mistaken, unless otherwise stated, those are "protected" so you can't really access those if you are calling an instance of the class. Maybe move them to properties and see if it works from there!

Uploading image with Restkit - adding two rows to UITableView instead of one

I'm trying to post new managed object with image to the web database as below and everything works fine for me except the little weird bug. When the managed object is uploaded successfully, 2 rows are added instead of one to the UITableView. When I'm refreshing the UITableView the one of the previously added UITableViewCell is populating with uploaded image. When I rebuild the app everything works fine. Previously added managed object is displayed correctly without duplication. Does anyone can take a look at my code and tell me what is the reason for that bug and how can I fix it? Let me know if you need more code.
-(void)postRequest{
NSEntityDescription *watchEntityDesc = [NSEntityDescription entityForName:#"Watches" inManagedObjectContext:[[RKObjectManager sharedManager]managedObjectStore].mainQueueManagedObjectContext];
Watches *watch = [[Watches alloc]initWithEntity:watchEntityDesc insertIntoManagedObjectContext:[[RKObjectManager sharedManager]managedObjectStore].mainQueueManagedObjectContext];
watch.phonewatchno = #"124512";
watch.latitude = [NSNumber numberWithDouble:-33.856870];
watch.longitude = [NSNumber numberWithDouble:151.215279];
NSEntityDescription *wearersEntityDesc = [NSEntityDescription entityForName:#"Wearers" inManagedObjectContext:[[RKObjectManager sharedManager]managedObjectStore].mainQueueManagedObjectContext];
Wearers *wearer = [[Wearers alloc]initWithEntity:wearersEntityDesc insertIntoManagedObjectContext:[[RKObjectManager sharedManager]managedObjectStore].mainQueueManagedObjectContext];
wearer.name =_nameTextField.text,
wearer.watches =[NSSet setWithObject:watch];
RKEntityMapping *watchesMapping = [RKEntityMapping mappingForEntityForName:#"Watches" inManagedObjectStore:[[EFDateModel sharedDataModel]objectStore]];
[watchesMapping addAttributeMappingsFromDictionary:#{
#"id": #"watch_id",
#"latitude":#"latitude",
#"longitude":#"longitude",
#"phonewatchno":#"phonewatchno",
}
];
[watchesMapping addConnectionForRelationship:#"wearer" connectedBy:#{
#"wearer_id":#"wearer_id"
}];
[watchesMapping setIdentificationAttributes:#[#"watch_id"]];
RKResponseDescriptor *responseDescr = [RKResponseDescriptor responseDescriptorWithMapping:watchesMapping method:RKRequestMethodPOST pathPattern:#"/watches.json" keyPath:nil statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
[[RKObjectManager sharedManager]addResponseDescriptor:responseDescr];
RKEntityMapping *wearersMapping = [RKEntityMapping mappingForEntityForName:#"Wearers" inManagedObjectStore:[[EFDateModel sharedDataModel] objectStore]];
[wearersMapping addAttributeMappingsFromDictionary:#{
#"id":#"wearer_id",
#"name":#"name",
}
];
wearersMapping.identificationAttributes = #[#"wearer_id"];
[wearersMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:#"watch" toKeyPath:#"watches" withMapping:watchesMapping]];
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:wearersMapping method:RKRequestMethodPOST pathPattern:#"/wearers.json" keyPath:nil statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
RKRequestDescriptor *requestDescriptor = [RKRequestDescriptor requestDescriptorWithMapping:[wearersMapping inverseMapping] objectClass:[Wearers class] rootKeyPath:nil method:RKRequestMethodPOST ];
[[RKObjectManager sharedManager]addResponseDescriptor:responseDescriptor];
[[RKObjectManager sharedManager]addRequestDescriptor:requestDescriptor];
[[RKObjectManager sharedManager]setRequestSerializationMIMEType:RKMIMETypeJSON];
[[RKObjectManager sharedManager]setAcceptHeaderWithMIMEType:#"application/json"];
UIImage *image =[UIImage imageWithCGImage:_wearerImage.CGImage scale:0.4 orientation:UIImageOrientationUp];
NSMutableURLRequest *request = [[RKObjectManager sharedManager] multipartFormRequestWithObject:wearer method:RKRequestMethodPOST path:#"/wearers.json" parameters:nil constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
[formData appendPartWithFileData:UIImagePNGRepresentation(image)
name:#"wearer_photo"
fileName:#"photo.png"
mimeType:#"image/png"];
}];
NSManagedObjectContext *moc =[[[RKObjectManager sharedManager]managedObjectStore]mainQueueManagedObjectContext];
RKManagedObjectRequestOperation *managedObjectOperation = [[RKObjectManager sharedManager]managedObjectRequestOperationWithRequest:request managedObjectContext:moc success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
NSLog(#"Mapping result = %#",mappingResult.array);
[[RKObjectManager sharedManager]removeResponseDescriptor:responseDescriptor];
[[RKObjectManager sharedManager]removeRequestDescriptor:requestDescriptor];
[[NSNotificationCenter defaultCenter]
postNotificationName:#"ReloadTable"
object:self];
[self dismissViewControllerAnimated:YES completion:nil];
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
NSLog(#"Error : \n %#",error.description);
}];
[[RKObjectManager sharedManager] enqueueObjectRequestOperation:managedObjectOperation];
}
Cheers
Every time you are calling this method you are calling alloc]initWithEntity:... insertIntoManagedObjectContext: twice and creating two new entity instances. You should probably be passing an entity instance to this method that it uses and not creating any new instances.
Also, it is inefficient to keep creating new descriptors and adding and removing them. And if you try to make 2 requests at the same time you will get an error. Configure the object manager once before you first use it and then just use it repeatedly without reconfiguring.

Wresting a simple dictionary from RestKit

I am attempting to upgrade my current RestKit to 0.20.3, and in one case I need to get the result back as a dictionary, not mapped to any object.
Unfortunately, the code below results in an essentially empty RKMappingResult object, despite the fact that a correct dictionary does exist deeper in RestKit (I checked).
[self.objectManager addResponseDescriptor:[RKResponseDescriptor responseDescriptorWithMapping:[RKObjectMapping mappingForClass:[NSMutableDictionary class]]
method:RKRequestMethodGET
pathPattern:#"permission.json"
keyPath:nil
statusCodes:nil]];
[self loadObject:[[NSMutableDictionary alloc] init]
method:RKRequestMethodGET
path:#"permission.json"
params:nil
success:^(RKObjectRequestOperation *op, RKMappingResult *result) {
if (success)
success([result dictionary]);
}
failure:^(RKObjectRequestOperation *op, NSError *error) {
if (failure)
failure(error);
}];
Load object calls the following:
RKObjectRequestOperation *const operation =
[self operationForObject:object
method:method
path:path
params:params
success:success
failure:failure];
[self.objectManager enqueueObjectRequestOperation:operation];
return operation;
Can anyone give me some direction on how I might convince RestKit to give me back a dictionary?
This is indeed one of the correct ways to create the mapping instance for a dictionary result:
[RKObjectMapping mappingForClass:[NSMutableDictionary class]]
But you still need to set the key names that should be mapped or RestKit will just do no mapping.

cannot add a requestdescriptor for a same class restkit ios throws error nsinternal inconsistency error

i just update a content using restkit patchobject..when first time the method call invoked it leads success.but during second time call the same method ,the app crashes with NSInternal inconsistecy error.Cannot add adddescriptor for same class.thanks. below link also have same problem,but i dont know how to solve.
Restkit + Objective-c - Multiple calls to same web service
here is my method code
-(void)setContact:(int)_orgID :(int)_personID :(Person *)p1
{
AddressScreenViewController *addressView= [[AddressScreenViewController alloc]init];
addressView.mobileno = p1.mobile_phone;
addressView.workno = p1.work_phone;
addressView.homeno = p1.home_phone;
addressView.address1=p1.address1;
addressView.address2=p1.address2;
addressView.city=p1.city;
addressView.zip=p1.zip;
[AFNetworkActivityIndicatorManager sharedManager].enabled = YES;
LoginAppDelegate * appDelegate = [[UIApplication sharedApplication] delegate];
RKObjectManager *objectManager = [RKObjectManager sharedManager];
[objectManager setRequestSerializationMIMEType:RKMIMETypeJSON];
RKObjectMapping *personRequestMapping = [RKObjectMapping requestMapping];
[personRequestMapping addAttributeMappingsFromDictionary:#{ #"mobileno" : #"phone_numbers.mobile_number", #"workno" : # "phone_numbers.work_number" , #"homeno" :#"phone_numbers.home_number",#"address1":#"mailing_address.address1",#"address2":#"mailing_address.address2",#"city":#"mailing_address.city",#"zip":#"mailing_address.zip"}];
RKLogConfigureByName("RestKit", RKLogLevelWarning);
RKLogConfigureByName("RestKit/Network", RKLogLevelTrace);
RKLogConfigureByName("RestKit/ObjectMapping", RKLogLevelTrace);
RKRequestDescriptor *requestDescriptor =[RKRequestDescriptor requestDescriptorWithMapping:personRequestMapping objectClass:[AddressScreenViewController class] rootKeyPath:#"person"];
[objectManager addRequestDescriptor:requestDescriptor];
NSString * orgPath = [NSString stringWithFormat:myurl];
[objectManager patchObject:addressView path:orgPath parameters:nil success:^(RKObjectRequestOperation *operation, RKMappingResult *result)
{
NSLog(#"result: %#", result);
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
NSLog(#"failuer function");
}];
}
The issue you are facing is because you are adding same request descriptor multiple times. You should set all request and response descriptor only once for example, in app delegate.
+ (void)setupDescriptors {
RKObjectManager *objectManager = [[AppDelegate appDelegate] objectManager];
objectManager.requestSerializationMIMEType = RKMIMETypeJSON;
NSIndexSet *statusCodes = RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful);
// Add Request Descriptors
//
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:[Human rkEntityMappingForResponse:YES] method:RKRequestMethodAny pathPattern:nil keyPath:#"human" statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
RKRequestDescriptor *userRequestDescriptor = [RKRequestDescriptor requestDescriptorWithMapping:[User rkObjectMappingForRequest:YES] objectClass:[User class] rootKeyPath:#"user" method:RKRequestMethodAny];
RKRequestDescriptor *signupUserRequestDescriptor = [RKRequestDescriptor requestDescriptorWithMapping:[User rkObjectMappingForSignupRequest:YES] objectClass:[User class] rootKeyPath:#"user" method:RKRequestMethodAny];
[objectManager addRequestDescriptorsFromArray:#[signupUserRequestDescriptor,userRequestDescriptor]];
RKResponseDescriptor *userResponseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:[User rkEntityMappingForResponse:YES] method:RKRequestMethodAny pathPattern:nil keyPath:#"user" statusCodes:statusCodes];
[objectManager addResponseDescriptorsFromArray:#[userResponseDescriptor,responseDescriptor]];
}
But in some scenarios, you still want to add multiple request descriptor then this is done by dynamic mapping as answered by Author of REST Kit. Please see following link.
Adding two request descriptors for a given class in Restkit 0.2
I hope this helps.
You can't add a descriptor for the same key twice. You haven't added any code, but I know that you're adding all of your mappings and descriptors in the method where you're calling 'patch'. Don't...
Separate your configuration from your usage. Put all of your mapping and descriptor setup code into one method and call it once before you do anything else. Then, when you want to 'patch', call a different method which just does that and doesn't include any additional mappings.

How do I use RKResponseDescriptor with an id?

I am trying to create a RKResponseDescriptor to get people in a session.
I have a response descriptor for /sessions but I don't know how to create it to get the people in the sessions /sessions/20/people (/sessions/sessionID/people).
My session response descriptor is;
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:sessionsMapping
pathPattern:#"/sessions"
keyPath:nil
statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
The response descriptor for the people in the session is;
RKResponseDescriptor *clientInSessionResponseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:clientsInSessionMapping
pathPattern:#"/sessions/:sessionID/people"
keyPath:nil
statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
I keep getting the error, "Failed with error: No response descriptors match the response loaded."
I noticed in the documentation there is a lot of usage of the :id but can't seem to figure it out. Also, should I use a RKPathMatcher to build the path?
Any help would be greatly appreciated.
What I did was a parameter substitution when sending the request path. So in your case I would do the following:
NSString *idValue; // this is the sessionID value
NSString *path = [#"/sessions/:sessionID/people" stringByReplacingOccurrencesOfString:#":sessionID" withString:idValue];
[[RKObjectManager sharedManager] getObjectsAtPath:path parameters:nil success:^(RKObjectRequestOperation *operation,RKMappingResult *mappingResult)
{
// handle success
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
RKLogError(#"*** RK load FAIL");
}]

Resources