I'm doing a very basic POST request.
setting my requestSerializationMIMEType into RKMIMETypeFormURLEncoded as my server would expect (although it's the default).
Now in the log the request.body would look like this:
request.body=[param1]=test&[param2]=2724
Resulting unknown form values in the server.
The problem here is the param names, they're between square brackets, which I don't have an explanation why they're serialised like this!
My code is somehow exactly the same of the example provided on github.
NOTE: I have done the POST request manually without the square brackets and it's working fine.
EDIT
The code
RKObjectMapping *responseMapping = [RKObjectMapping mappingForClass:[GenericResponse class]];
[responseMapping addAttributeMappingsFromDictionary:#{#"error":#"error", #"status":#"status"}];
NSIndexSet *statusCodes = RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful);
RKResponseDescriptor *genericDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:responseMapping method:RKRequestMethodAny pathPattern:#"" keyPath:#"" statusCodes:statusCodes];
RKObjectMapping *requestMapping = [RKObjectMapping requestMapping];
[requestMapping addAttributeMappingsFromDictionary:[User generateJSONMapping]];//dictionary mapping
RKRequestDescriptor *requestDescriptor = [RKRequestDescriptor requestDescriptorWithMapping:requestMapping objectClass:[User class] rootKeyPath:#"" method:RKRequestMethodPOST];
RKObjectManager *manager = [RKObjectManager managerWithBaseURL:[NSURL URLWithString:#"https://foo.com/rest/createUser/"]];
[manager addRequestDescriptor:requestDescriptor];
[manager addResponseDescriptor:genericDescriptor];
manager.requestSerializationMIMEType=RKMIMETypeFormURLEncoded;
// POST to create
[manager postObject:user path:#"" parameters:nil success:^(RKObjectRequestOperation *operation, RKMappingResult *result) {
NSLog(#"success");// the request is success but the params are not delivered to the server
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
NSLog(#"fail");
}];
The User is very simple I guess
#interface User : NSObject
#property NSNumber *idShort;
#property NSNumber *idLong;
#property NSNumber *idCom;
#property NSString *comment;
#property NSString *token;
+ (NSDictionary *) generateJSONMapping;
#end
#implementation User
+ (NSDictionary *) generateJSONMapping
{
return #{
#"idShort": #"idShort",
#"idLong": #"idLong",
#"idCom":#"idCom",
#"comment":#"comment",
#"token":#"token",
};
}
#end
The problem is in the RKRequestDescriptor, passing rootKeyPath as an empty string would cause this.
Passing nil would solve the problem.
RKRequestDescriptor *requestDescriptor = [
RKRequestDescriptor requestDescriptorWithMapping:requestMapping
objectClass:[User class]
rootKeyPath:nil
method:RKRequestMethodPOST];
Related
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!
I have a JSON response from REST service I am using RESTKit and its not getting mapped , below is the source for the same
RKObjectMapping *userMapping = [RKObjectMapping requestMapping];
[userMapping addPropertyMapping:[RKAttributeMapping attributeMappingFromKeyPath:#"strCode" toKeyPath:#"UserCode"]];
RKRequestDescriptor *requestDescriptor = [RKRequestDescriptor requestDescriptorWithMapping:userMapping
objectClass:[User class]
rootKeyPath:nil method:RKRequestMethodPOST];
RKObjectMapping *responseMapping = [RKObjectMapping mappingForClass:[User class]];
[responseMapping addAttributeMappingsFromDictionary:#{ #"Id":#"Id",#"UserCode":#"strCode",#"FirstName": #"strFname", #"LastName": #"strLname",#"Email":#"strEmail",#"PhoneNumber":#"strPhoneNumber",#"CompanyName":#"strCompany",#"Address":#"strAddress",#"Abn":#"strAbn"}];
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:responseMapping
method:RKRequestMethodAny
pathPattern:nil
keyPath:nil
statusCodes:[NSIndexSet indexSetWithIndex:200]];
RKObjectManager *manager = [RKObjectManager sharedManager];
[manager addRequestDescriptor:requestDescriptor];
[manager addResponseDescriptor:responseDescriptor];
RKObjectMapping *errResponseMapping = [RKObjectMapping mappingForClass:[ServiceError class]];
[errResponseMapping addAttributeMappingsFromDictionary:#{ #"ErrorMessage": #"strErrorMessage", #"FriendlyMessage": #"strFriendlyMessage"}];
RKResponseDescriptor *errResponseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:errResponseMapping
method:RKRequestMethodAny
pathPattern:nil
keyPath:nil
statusCodes:[NSIndexSet indexSetWithIndex:200]];
[manager addResponseDescriptor:errResponseDescriptor];
manager.requestSerializationMIMEType = RKMIMETypeJSON;
User *user = [user new];
user.strCode = txtCode.text;
// POST the parameterized representation of the `page` object to `/posts` and map the response
[manager postObject:user path:[ServiceUrls userDetails] parameters:nil success:^(RKObjectRequestOperation *operation, RKMappingResult *result) {
NSlog(#"%d",result.count);
}
} failure:nil];
The user class looks like this
#interface User : NSObject
{
}
#property (nonatomic,retain) NSNumber *Id;
#property (nonatomic,retain) NSString *strCode;
#property (nonatomic,retain) NSString *strFname;
#property (nonatomic,retain) NSString *strLname;
#property (nonatomic,retain) NSString *strEmail;
#property (nonatomic,retain) NSString *strPhoneNum;
#property (nonatomic,retain) NSString *strCompany;
#property (nonatomic,retain) NSString *strAddress;
#property (nonatomic,retain) NSString *strAbn;
#end
JSON response that i get but isn't mapping is as follows
{"Id":7,
"UserCode":"CC1234",
"FirstName":"Test name_",
"LastName":"Banga",
"Email":"p#b.com",
"PhoneNumber":"0421196587",
"CompanyName":"String",
"Address":"String",
"Abn":"String"}
Not sure whats wrong with the code I have added, any clue ?
Maybe try this.
Mapping:
-(void) getUserMapping {
RKEntityMapping *userEntityMapping = [self generateEntityMappingFromClass:[User class]];
userEntityMapping.identificationAttributes = #[#"Id"];
return userEntityMapping;
}
Generate Mapping:
+ (RKEntityMapping *)generateEntityMappingFromClass:(Class)objectClass {
NSAssert(objectClass != NULL, #"Cannot generate a mapping from a null object class.");
NSDictionary *propertiesAndClasses = [[RKPropertyInspector sharedInspector] propertyInspectionForClass:objectClass];
NSAssert([propertiesAndClasses count] > 0, #"Cannot generate a mapping from a class containing zero properties.");
RKEntityMapping *mapping = [RKEntityMapping mappingForEntityForName:NSStringFromClass(objectClass) inManagedObjectStore: [RKManagedObjectStore defaultStore]];
NSMutableDictionary *mappingDictionary = [[NSMutableDictionary alloc] init];
for (NSString *property in [propertiesAndClasses allKeys]) {
NSLog(#"property: %#", property);
[mappingDictionary setObject:property forKey:property];
}
[mapping addAttributeMappingsFromDictionary:mappingDictionary];
return mapping;
}
Response descriptor:
RKResponseDescriptor *responseDescriptorBody = [RKResponseDescriptor responseDescriptorWithMapping:[self getUserMapping] method:RKRequestMethodGET pathPattern:#"" keyPath:#"" statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
I think your problem is JSON without keyPath, try to change it from nil to #""
When I POST a mapped model through Restkit the resultant Json looks like so, the doubles are strings, I want them to be doubles:
{
Coordinate = (
"39.2",
"-121.0"
);
}
I want:
{
Coordinate = (
39.2,
-121.0
);
}
this is my mapping
+(RKObjectMapping *)mapping
{
RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[self class]];
[mapping addAttributeMappingsFromArray:#[#"Coordinate"]];
return mapping;
}
When setting the coordinate of the Location object:
#interface MYLocationDTO : NSObject
#property (strong, nonatomic) NSArray *Coordinate;
+(RKObjectMapping *)mapping;
#end
I am passing in an array of two nsnumbers, that were set from double values.
Anyone know of how to post this nsarray collection as numbers not strings?
Thanks!
Here is my post call:
-(void)updateLocationOfUserWithLocationDTO:(WHMLocationDTO *)dto withCompletionBlock:(void (^)(BOOL, NSString *))callbackBlock
{
//whim-ios.herokuapp.com/users/password-reset
RKObjectManager *manager = [WHMDataController getManagerWithSession];
RKObjectMapping *requestMapping = [[WHMLocationDTO mapping] inverseMapping];
RKRequestDescriptor *requestDesc = [RKRequestDescriptor requestDescriptorWithMapping:requestMapping objectClass:[WHMLocationDTO class] rootKeyPath:nil method:RKRequestMethodPOST];
[manager addRequestDescriptor:requestDesc];
RKObjectMapping *responseMapping = [WHMResponseMapping responseMapping];
RKDynamicMapping *dynamicMapping = [WHMResponseMapping createDynamicMappingWithResponseMapping:responseMapping];
[manager addResponseDescriptor:[RKResponseDescriptor responseDescriptorWithMapping:dynamicMapping method:RKRequestMethodPOST pathPattern:nil keyPath:nil statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)]];
//POST
__weak __typeof__(self) weakSelf = self;
[manager postObject:dto
path:#"user/loc"
parameters:nil
success:^(RKObjectRequestOperation *operation, RKMappingResult *result)
{
Why not use Apple's API to generate the JSON, as demonstrated in this article: http://www.raywenderlich.com/5492/working-with-json-in-ios-5
and just POST the JSON?
For 2 days now, I've been trying to find out why I'm getting the error using iOS 6.1.3 with Xcode 4.6.2 and RestKit 0.20.0:
"...this class is not key value coding-compliant for the key Text."
The strange part is that I can receive (GET) the JSON object fine. The error happens when I create my sample SignalMessage object and then try to PUT it back to the server.
The JSON is as follows:
{"Text":"New Message","HasMessage":"true"}
The SignalMessage object looks like this:
#import <Foundation/Foundation.h>
#interface SignalMessage : NSObject {
}
#property (nonatomic, copy) NSString *signalText;
#property (nonatomic, retain) NSNumber *isHasMessage;
#end
And the implementation like this:
#import "SignalMessage.h"
#implementation SignalMessage
#synthesize isHasMessage, signalText;
#end
My correctly working getMessage function looks like this:
- (IBAction)getMessage:(id)sender;
{
NSLog(#"%#", #"Getting message... ");
NSURL *url = [NSURL URLWithString:#"http://ec2-54-243-148-145.compute-1.amazonaws.com/TabletPractice/api/signal?clientIdentifier=2"];
RKObjectManager *manager = [RKObjectManager managerWithBaseURL:url];
RKObjectMapping *responseMapping = [RKObjectMapping mappingForClass:[SignalMessage class]];
[responseMapping addAttributeMappingsFromDictionary:#{#"Text":#"signalText", #"HasMessage": #"isHasMessage"}];
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:responseMapping pathPattern:nil keyPath:nil statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
[manager addResponseDescriptor:responseDescriptor];
[manager getObject:nil path:#"" parameters:nil success:^(RKObjectRequestOperation *operation, RKMappingResult *result)
{
NSArray *theresults = [result array];
for (SignalMessage *item in theresults) {
self.txtMessage.text = item.signalText;
[self hideControls];
}
} failure:^(RKObjectRequestOperation * operation, NSError * error)
{
NSLog (#"Server WS call failure: operation: %# \n\nerror: %#", operation, error);
}];
}
And here is the sendClicked message that gives me grieve:
- (IBAction)btnSendClicked:(id)sender;
{
if ([txtMessage.text length] < 1)
return;
NSURL *url = [NSURL URLWithString:#"http://ec2-54-243-148-145.compute-1.amazonaws.com/TabletPractice/api/signal?clientIdentifier=2"];
RKObjectManager *manager = [RKObjectManager managerWithBaseURL:url];
RKObjectMapping *requestMapping = [RKObjectMapping requestMapping];
[requestMapping addAttributeMappingsFromDictionary:#{#"Text":#"signalText", #"HasMessage": #"isHasMessage"}];
RKRequestDescriptor *requestDescriptor = [RKRequestDescriptor requestDescriptorWithMapping:requestMapping
objectClass:[SignalMessage class]
rootKeyPath:#""];
[manager addRequestDescriptor:requestDescriptor];
SignalMessage *newMessage = [[SignalMessage alloc] init];
newMessage.signalText = #"Test Message";
BOOL isMsg = TRUE;
NSNumber *boolAsNumber = [NSNumber numberWithBool:isMsg];
newMessage.isHasMessage = boolAsNumber;
[manager putObject:newMessage path:#"" parameters:nil success:^(RKObjectRequestOperation *operation, RKMappingResult *result) {
NSLog(#"We object mapped the response with the following result: %#", result);
} failure:^(RKObjectRequestOperation * operation, NSError * error)
{
NSLog (#"Server WS call failure: operation: %# \n\nerror: %#", operation, error);
}];
[self hideControls];
}
At this point, I'm at a loss.
Please add a inverse mapping to your RKRequestDescriptor in your btnSendClicked method like below:
RKRequestDescriptor *requestDescriptor = [RKRequestDescriptor
requestDescriptorWithMapping:[requestMapping inverseMapping]
objectClass:[SignalMessage class]
rootKeyPath:#""];
i am able to send request correctly but after receiving response i get
response.body ={"status":"success","loginToken":"xxxxyyyzzz"}
but with an error saying
It Failed: Error Domain=org.restkit.RestKit.ErrorDomain Code=1001 "No response descriptors
match the response loaded." UserInfo=0x2b55b0 {NSErrorFailingURLStringKey=http://192.168.1.71
/firstyii/index.php?r=site/login, NSLocalizedFailureReason=A 200 response was loaded from the
URL 'http://192.168.1.71/firstyii/index.php?r=site/login', which failed to match all (1)
response descriptors:
<RKResponseDescriptor: 0x2a5860 baseURL=http://192.168.1.71 pathPattern=/firstyii
/index.php?r=site/login statusCodes=200-299> failed to match: response path '/firstyii
/index.php?r=site/login' did not match the path pattern '/firstyii/index.php?r=site/login'.,
NSLocalizedDescription=No response descriptors match the response loaded., keyPath=null,
NSErrorFailingURLKey=http://192.168.1.71/firstyii/index.php?r=site/login,
NSUnderlyingError=0x2b6070 "No mappable object representations were found at the key paths
searched."}
LoginResponse.h
#interface LoginResponse : NSObject
#property (nonatomic, strong) NSString *status;
#property (nonatomic, strong) NSString *loginToken;
+(RKObjectMapping*)defineLoginResponseMapping;
#end
LoginResponse.m
#import "LoginResponse.h"
#implementation LoginResponse
#synthesize loginToken;
#synthesize status;
+(RKObjectMapping*)defineLoginResponseMapping {
RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[LoginResponse class]];
[mapping addAttributeMappingsFromDictionary:#{
#"status": #"status",
#"loginToken": #"loginToken",
}];
return mapping;
}
#end
Code in LoginManager.m
-(void)LoginWithUserName:(NSString *)username password:(NSString*)password {
LoginRequest *dataObject = [[LoginRequest alloc] init];
[dataObject setUsername:username];
[dataObject setPassword:password];
NSURL *baseURL = [NSURL URLWithString:#"http://192.168.1.71"];
AFHTTPClient * client = [AFHTTPClient clientWithBaseURL:baseURL];
[client setDefaultHeader:#"Accept" value:RKMIMETypeJSON];
RKObjectManager *objectManager = [[RKObjectManager alloc] initWithHTTPClient:client];
[RKMIMETypeSerialization registerClass:[RKNSJSONSerialization class]
forMIMEType:#"application/json"];
RKObjectMapping *requestMapping = [[LoginRequest defineLoginRequestMapping] inverseMapping];
[objectManager addRequestDescriptor: [RKRequestDescriptor
requestDescriptorWithMapping:requestMapping objectClass:[LoginRequest class] rootKeyPath:nil
]];
// what to print
RKLogConfigureByName("RestKit/Network", RKLogLevelTrace);
RKLogConfigureByName("Restkit/Network", RKLogLevelDebug);
RKObjectMapping *responseMapping = [LoginResponse defineLoginResponseMapping];
[objectManager addResponseDescriptor:[RKResponseDescriptor
responseDescriptorWithMapping:responseMapping pathPattern:#"/firstyii/index.php?r=site/login"
keyPath:nil statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)]];
[objectManager setRequestSerializationMIMEType: RKMIMETypeJSON];
[objectManager postObject:dataObject path:#"/firstyii/index.php?r=site/login"
parameters:nil success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
NSLog(#"It Worked: %#", [mappingResult array]);
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
NSLog(#"It Failed: %#", error);
}];
}
i think that the code used above is to map response with array ,
so i need code to map simple json like this one response.body={"status":"success","loginToken":"logingngngnnggngngae"}
Such responses are to be mapped using pathpattern , non keyvalue mapping mentioned at https://github.com/RestKit/RestKit/wiki/Object-mapping.
I was using pathPattern having "?" in it , hence it was not matching properly.
,also path pattern shouldnot have "/" at beginning.
the above code works fine if i change the pathPattern to pathPattern:#"site/login"
,and postObject to postObject:#"site/login"
and ofcourse changed the baseurl = #"http://json.xxxxxxx.xxxxx:8179/jsonresponse/index.php" so that there are not special charaters in it.