So I'm trying to use [RKObjectManager postObject:path:parameters:success:failure:] but am having some trouble getting it working with my login POST request. For some reason I keep getting a response back from my server saying that the parameters for email and password are required, even though I'm passing the following dictionary in for parameters:
NSDictionary *params = #{#"email": #"fakeEmail#fakeDomain.com, #"password": #"test123!"};
When I log out the RKObjectRequestOperation it doesn't show any parameters on the request. Do I have to pass an object in with the request? If so, what object would I pass in?
(Previously I was just using and AFJSONRequestOperation, but I would like to update the app to use RestKit and take advantage of the easy object mapping it provides).
Any help would be appreciated.
EDIT With More Code:
I have a subclass of RKObjectManager called UserAuthService, using RKMIMETYPEJSON as the requestSerializationMIMEType, with the following request descriptor setup:
// User
RKResponseDescriptor *userResponseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:[UserAuthMappingProvider userMapping]
method:RKRequestMethodPOST
pathPattern:#"user/login"
keyPath:#"response.users"
statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
[self addResponseDescriptor:userResponseDescriptor];
The method I'm using to actually request is:
- (void)logUserInWithEmail:(NSString *)email andPassword:(NSString *)password success:(void (^)(UserObject *))success failure:(void (^)(RKObjectRequestOperation *, NSError *))failure
{
// Request Params
NSDictionary *params = #{#"email": email, #"password": password};
NSLog(#"Params: %#", params);
[self postObject:nil path:#"user/login" parameters:params
success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult){
if (success)
{
NSArray *userArray = [mappingResult array];
success([userArray firstObject]);
}
}
failure:^(RKObjectRequestOperation *operation, NSError *error){
NSLog(#"Error: %#", error);
if (failure)
{
failure(operation, error);
}
}];
}
the userMapping method in UserAuthMappingProvider looks like this:
+ (RKEntityMapping *)userMapping
{
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
RKEntityMapping *userMapping = [RKEntityMapping mappingForEntityForName:#"User" inManagedObjectStore:appDelegate.managedObjectStore];
userMapping.identificationAttributes = #[ #"uuid" ];
[userMapping addAttributeMappingsFromDictionary:#{#"email": #"email",
#"first_name": #"firstName",
#"last_name": #"lastName",
#"is_logged_in": #"isLoggedIn",
#"site_id": #"siteID",
#"user_name": #"username",
#"uuid": #"uuid"}];
return userMapping;
}
and the UserObject (with each set to #dynamic in the .m):
#interface UserObject : NSManagedObject
#property (strong, nonatomic) NSString *email;
#property (strong, nonatomic) NSString *firstName;
#property (strong, nonatomic) NSString *lastName;
#property (assign, nonatomic) BOOL isLoggedIn;
#property (strong, nonatomic) NSNumber *siteID;
#property (strong, nonatomic) NSString *username;
#property (strong, nonatomic) NSString *uuid;
#end
The error I'm getting back is:
Error Domain=org.restkit.RestKit.ErrorDomain Code=-1011 "Expected status code in (200-299), got 400" UserInfo=0x8eadbf0 {NSLocalizedRecoverySuggestion={"required_parameters":{"email":"string","password":"string"},"status":"failed","message":"Insufficient information passed. see 'required_parameters'"}
Basically my goal is to take the success response of the user/login call and map it to the UserObject.
Finally figure it out, and of course it was a really stupid issue. The server was expecting a dictionary of params, but my object manager's requestSerializationMIMEType was set to RKMIMETypeJSON. So, once I commented that line out the request worked fine with the object being nil and the parameters being set to a dictionary of #{#"email": email, #"password": password}
Related
{"coord":{"lon":72.62,"lat":23.03},"weather":[{"id":500,"main":"Rain","description":"light rain","icon":"10n"}],"base":"stations","main":{"temp":303.082,"pressure":1014.85,"humidity":66,"temp_min":303.082,"temp_max":303.082,"sea_level":1018.46,"grnd_level":1014.85},"wind":{"speed":1.07,"deg":340.501},"rain":{"3h":0.435},"clouds":{"all":76},"dt":1475333911,"sys":{"message":0.0033,"country":"IN","sunrise":1475283682,"sunset":1475326567},"id":1279233,"name":"Ahmadabad","cod":200}
Above is my API response.
Now I want to mapping of "weather" and "name" and want the same object as a response.
I can create to class
#interface WeatherStatus : NSObject
#property (nonatomic, copy) NSString *name;
#property (nonatomic, strong) WeatherInfo *info;
#end
and
#interface WeatherInfo : NSObject
#property (nonatomic, copy) NSString *description;
#property (nonatomic, copy) NSString *icon;
Below is mapping code.
RKObjectMapping *weatherInfo = [RKObjectMapping mappingForClass:[WeatherInfo class]];
[weatherInfo addAttributeMappingsFromDictionary:#{#"description": #"description", #"icon": #"icon"}];
RKObjectMapping *weatherStatus = [RKObjectMapping mappingForClass:[WeatherStatus class]];
[weatherStatus addAttributeMappingsFromArray:#[#"name"]];
[weatherStatus addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:#"weather" toKeyPath:#"weather" withMapping:weatherInfo]];
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:weatherStatus method:RKRequestMethodGET pathPattern:nil keyPath:#"weather" statusCodes:nil];
[objectManager addResponseDescriptor:responseDescriptor];
NSDictionary *queryParams;
queryParams = [NSDictionary dictionaryWithObjectsAndKeys:kAPP_KEY, #"appid", #"Ahmedabad", #"q", nil];
[[RKObjectManager sharedManager] getObjectsAtPath:#"/data/2.5/weather" parameters:queryParams success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
WeatherStatus *obj = [mappingResult.array objectAtIndex:0];
NSLog(#"info %#",obj.info);
NSLog(#"name %#",obj.name);
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
NSLog(#"What do you mean by 'there is no coffee?': %#", error);
}];
I am getting
info (null)
name (null)
Can anyone let me know where is the mistake?
I have already seen RestKit complex and simple JSON RKObjectMapping almost working, but
Don't use description as a property name, it'll only cause you problems. Use overview or something similar instead.
In the JSON, the weather is an array, so you should make your weather (info) property a NSArray, and be sure the name in the mapping and the property match.
I change the property of info object in "WeatherStatus" class to NSArray.
#property (nonatomic, copy) NSString *name;
#property (nonatomic, strong) NSArray *weather;
Here is the modification of mapping code.
RKObjectMapping *venueMapping = [RKObjectMapping mappingForClass:[WeatherStatus class]];
[venueMapping addAttributeMappingsFromDictionary:#{#"name": #"name"}];
RKObjectMapping *locationMapping = [RKObjectMapping mappingForClass:[WeatherInfo class]];
[locationMapping addAttributeMappingsFromDictionary:#{#"description": #"description",#"icon":#"icon"}];
[venueMapping addRelationshipMappingWithSourceKeyPath:#"weather" mapping:locationMapping];
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:venueMapping method:RKRequestMethodGET pathPattern:nil keyPath:nil statusCodes:nil];
[objectManager addResponseDescriptor:responseDescriptor];
Add relationship mapping with WeatherStatus class.
Credit goes to https://stackoverflow.com/users/1988185/wain
I'm calling a web service using AFNetworking and saving the return data in NSDictionary object. But nothing's being stored in it, even when data is successfully logged in NSLog().
This is my dictionary:
#property (strong, nonatomic) NSDictionary *newsItems;
and this is my codes:
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
NSDictionary *parameters = #{#"key": #"keyy", #"q": #"ads" };
[manager POST:BaseURLString parameters:parameters success:^(AFHTTPRequestOperation *operation, id responseObject) {
self.newsItems = (NSDictionary *) responseObject;
NSLog(#"JSON: %#", responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
First, check whether you're getting any response from web service using the below line:
NSLog(#"RESPONSE : %#", operation.responseString);
Second, if your web service is supposed to return an array of dictionaries, then you should declare an array instead on dictionary.
#property (strong, nonatomic) NSArray *newsItems;
instead of
#property (strong, nonatomic) NSDictionary *newsItems;
You need to declare an NSArray & not NSDictionary like following:
#property (strong, nonatomic) NSArray *newsItems;
And assign responseObject like following:
self.newsItems = (NSArray *) responseObject;
Hope this helps.
I can not seem to figure out how to map the following JSON, I am trying to map the hostedLargeUrl from the response. I am not sure what to do for this issue, and would like to apologize if my info is not detailed enough. Not too sure what type of details you would need.
Thank you in advance.
images: [
{
imageUrlsBySize: {
90: "http://lh4.ggpht.com/ZXiwjS55Zk7oBu6GWaVr0HAqIPKumXwBfGtzsCWEFdrJSOXiCcC-I3TpUwrXBnP_DPNuBm-ib-4-3aXbs4mfXA=s90-c",
360: "http://lh4.ggpht.com/ZXiwjS55Zk7oBu6GWaVr0HAqIPKumXwBfGtzsCWEFdrJSOXiCcC-I3TpUwrXBnP_DPNuBm-ib-4-3aXbs4mfXA=s360-c"
},
hostedLargeUrl: "http://i.yummly.com/Pasta-with-garlicky-broccoli-rabe-305651-270310.l.jpg",
hostedSmallUrl: "http://i.yummly.com/Pasta-with-garlicky-broccoli-rabe-305651-270310.s.jpg"
}
Here is my code:
+ (RKMapping *)recipeDetailMapping
{
RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RecipeDetails class]];
[mapping addAttributeMappingsFromDictionary:#{
#"attribution.text" : #"attributionText",
#"images.hostedLargeUrl" : #"images"
}];
[mapping addAttributeMappingsFromArray:#[#"ingredientLines",
#"name",
#"totalTime",
]];
return mapping;
}
RecipeDetails
#property (nonatomic, copy) NSArray *ingredientLines;
#property (nonatomic, copy) NSString *name;
#property (nonatomic, copy) NSString *totalTime;
#property (nonatomic, copy) NSString *attributionText;
#property (nonatomic, copy) NSString *images;
Last bit of code
- (void)loadRecipeDetails
{
NSIndexSet *statusCodeSet = RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful);
RKMapping *mapping = [MappingProvder recipeDetailMapping];
NSString *resourcePath = [NSString stringWithFormat:#"/v1/api/recipe/%#", self.recipeInfo.recipeId];
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:mapping
method:RKRequestMethodGET
pathPattern:resourcePath
keyPath:nil
statusCodes:statusCodeSet];
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:#"https://api.yummly.com/v1/api/recipe/%#?_app_id=%#&_app_key=%#&requirePictures=true", self.recipeInfo.recipeId
,Yummly_APP_ID , Yummly_API_kEY ]];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
RKObjectRequestOperation *operation = [[RKObjectRequestOperation alloc] initWithRequest:request
responseDescriptors:#[responseDescriptor]];
[operation setCompletionBlockWithSuccess:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
self.recipeData = mappingResult.array;
[self updateUI];
[SVProgressHUD dismiss];
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
NSLog(#"Response: %#", operation.HTTPRequestOperation.responseString);
[SVProgressHUD showErrorWithStatus:#"Request Failed"];
}];
[operation start];
}
The source data is in an array and you need to deal with that in some way.
Option 1.
Change the property to NSArray *images;
Option 2.
Add a custom method setImageArray: and implement it to extract the first image and store it. Then change the mapping to use a destination key of imageArray.
Other options really require a different object graph...
I'm using RestKit and this is how I initialize it and add routes and descriptors:
- (void)initRestClient
{
NSURL *baseURL = [NSURL URLWithString:kSomeBaseURL];
self.manager = [RKObjectManager managerWithBaseURL:baseURL];
[self.manager setRequestSerializationMIMEType:RKMIMETypeJSON];
[self.manager setAcceptHeaderWithMIMEType:RKMIMETypeJSON];
[self.manager addResponseDescriptorsFromArray:[RKObjectManager sharedManager].responseDescriptors];
[self.manager addRequestDescriptorsFromArray:[RKObjectManager sharedManager].requestDescriptors];
[self.manager.HTTPClient.operationQueue setMaxConcurrentOperationCount:5];
[RKObjectManager setSharedManager:self.manager];
// AFHTTPClient *client = [RKObjectManager sharedManager].HTTPClient;
[self initRoutes];
[self initMappingObjectsAndDiscriptors];
}
- (void)initRoutes
{
RKRoute *bannersRoute = [RKRoute routeWithClass:[RKBanner class] pathPattern:#"Banners?categoryID=:categoryID" method:RKRequestMethodGET];
bannersRoute.shouldEscapePath = YES;
[self.manager.router.routeSet addRoute:bannersRoute];
RKRoute *branchesRoute = [RKRoute routeWithClass:[RKBranches class] pathPattern:#"Branches?city=:city&type=:type" method:RKRequestMethodGET];
branchesRoute.shouldEscapePath = YES;
[self.manager.router.routeSet addRoute:branchesRoute];
RKRoute *shortTokenRoute = [RKRoute routeWithClass:[RKShortToken class] pathPattern:#"users/login/quick/shortToken?phone=:phone&extraCode=:extraCode" method:RKRequestMethodGET];
shortTokenRoute.shouldEscapePath = YES;
[self.manager.router.routeSet addRoute:shortTokenRoute];
RKRoute *longTokenRoute = [RKRoute routeWithClass:[RKLongToken class] pathPattern:#"users/login/quick/userDetails?shortToken=:shortToken" method:RKRequestMethodGET];
longTokenRoute.shouldEscapePath = YES;
[self.manager.router.routeSet addRoute:longTokenRoute];
}
- (void)initMappingObjectsAndDiscriptors
{
RKObjectMapping *bannerMapping = [RKObjectMapping mappingForClass:[RKBanner class]];
[bannerMapping addAttributeMappingsFromDictionary:[RKBanner getAttributes]];
RKResponseDescriptor *bannerDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:bannerMapping method:RKRequestMethodAny pathPattern:nil keyPath:#"Banners" statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
RKObjectMapping *branchesMapping = [RKObjectMapping mappingForClass:[RKBranches class]];
[branchesMapping addAttributeMappingsFromDictionary:[RKBranches getAttributes]];
RKResponseDescriptor *branchesDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:branchesMapping method:RKRequestMethodGET pathPattern:nil keyPath:#"Branches" statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
RKObjectMapping *shortTokenMapping = [RKObjectMapping mappingForClass:[RKShortToken class]];
[shortTokenMapping addAttributeMappingsFromDictionary:[RKShortToken getAttributes]];
RKResponseDescriptor *shortTokenDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:shortTokenMapping method:RKRequestMethodGET pathPattern:nil keyPath:nil statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
RKObjectMapping *longTokenMapping = [RKObjectMapping mappingForClass:[RKLongToken class]];
[longTokenMapping addAttributeMappingsFromDictionary:[RKLongToken getAttributes]];
// longTokenMapping.setDefaultValueForMissingAttributes = YES;
// longTokenMapping.setNilForMissingRelationships = YES;
RKResponseDescriptor *longTokenDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:longTokenMapping method:RKRequestMethodGET pathPattern:nil keyPath:nil statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
[self.manager addResponseDescriptorsFromArray:#[bannerDescriptor, branchesDescriptor, shortTokenDescriptor, longTokenDescriptor]];
}
This is how each one of the classes is build:
#interface RKBanner : NSObject
#property (strong, nonatomic) NSNumber *idNum;
#property (strong, nonatomic) NSString *name;
#property (strong, nonatomic) NSString *addressURL;
#property (strong, nonatomic) NSString *bannerPosition;
#property (strong, nonatomic) NSString *imageALT;
#property (strong, nonatomic) NSNumber *imageHeight;
#property (strong, nonatomic) NSString *imageURL;
#property (strong, nonatomic) NSNumber *imageWidth;
#property (strong, nonatomic) NSString *subtitle;
#property (strong, nonatomic) NSString *targetURL;
#property (strong, nonatomic) NSString *textURL;
#property (strong, nonatomic) NSString *title;
+ (NSDictionary*)getAttributes;
#end
#implementation RKBanner
+ (NSDictionary*)getAttributes
{
return [NSDictionary dictionaryWithObjects:#[#"idNum", #"name", #"addressURL", #"bannerPosition", #"imageALT", #"imageHeight",
#"imageURL", #"imageWidth", #"subtitle", #"targetURL", #"textURL", #"title"]
forKeys:#[#"ID", #"Name", #"AddressURL", #"BannerPosition", #"ImageALT", #"ImageHeight",
#"ImageURL", #"ImageWidth", #"SubTitle", #"TargetURL", #"TextURL", #"Title"]];
}
#end
#interface RKBranches : NSObject
#property (strong, nonatomic) NSNumber *idNum;
#property (strong, nonatomic) NSString *branchTitle;
#property (strong, nonatomic) NSString *address;
#property (strong, nonatomic) NSNumber *branchType;
#property (strong, nonatomic) NSString *city;
#property (strong, nonatomic) NSString *fax;
#property (assign, nonatomic) BOOL isCanOrder;
#property (assign, nonatomic) BOOL isMe;
#property (strong, nonatomic) NSString *openHours;
#property (strong, nonatomic) NSString *orderCode;
#property (strong, nonatomic) NSString *phone;
#property (strong, nonatomic) NSString *remarks;
+ (NSDictionary*)getAttributes;
#end
#implementation RKBranches
+ (NSDictionary*)getAttributes
{
return [NSDictionary dictionaryWithObjects:#[#"idNum", #"branchTitle", #"address", #"branchType", #"city", #"fax",
#"isCanOrder", #"isMe", #"openHours", #"orderCode", #"phone", #"remarks"]
forKeys:#[#"ID", #"Name", #"Address", #"BranchType", #"City", #"Fax",
#"IsCanOrder", #"IsMe", #"OpenHours", #"OrderCode", #"Phone", #"Remarks"]];
}
#end
#interface RKShortToken : NSObject
#property (strong, nonatomic) NSString *responseError;
#property (strong, nonatomic) NSString *shortToken;
+ (NSDictionary*)getAttributes;
#end
#implementation RKShortToken
+ (NSDictionary*)getAttributes
{
return [NSDictionary dictionaryWithObjects:#[#"responseError", #"shortToken"]
forKeys:#[#"responseError", #"shortToken"]];
}
#end
#interface RKLongToken : NSObject
#property (strong, nonatomic) NSString *responseError;
#property (strong, nonatomic) NSString *responseMessage;
#property (strong, nonatomic) NSString *responseHttpCode;
#property (strong, nonatomic) NSString *responseUserMessage;
#property (strong, nonatomic) NSString *abroadInd;
#property (strong, nonatomic) NSString *accountType;
#property (strong, nonatomic) NSString *customerID;
#property (strong, nonatomic) NSString *longToken;
+ (NSDictionary*)getAttributes;
#end
#implementation RKLongToken
+ (NSDictionary*)getAttributes
{
return [NSDictionary dictionaryWithObjects:#[#"responseError", #"responseMessage", #"responseHttpCode", #"responseUserMessage",
#"abroadInd", #"accountType", #"customerID", #"longToken"]
forKeys:#[#"responseError", #"responseError.DeveloperMessage", #"responseError.HttpCode", #"responseError.UserMessage",
#"abroadInd", #"accountType", #"customerId", #"longToken"]];
}
#end
Than when I try to call RKShortToken, I get a good response, but the object that I get is RKLongToken:
- (void)quickLoginWithTelephone:(NSString*)telephone extraCode:(NSString *)extraCode completionBlock:(quickLoginExtraCodeCompletionBlock)success
{
NSDictionary *params = #{ #"phone" : telephone, #"extraCode" : extraCode };
[[RKObjectManager sharedManager] getObjectsAtPath:#"users/login/quick/shortToken?"
parameters:params
success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
NSLog(#"%#", operation.HTTPRequestOperation.responseString);
NSLog(#"%#", mappingResult.array);
success(YES);
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
NSLog(#"Error occurred.");
}];
}
Here is the logs:
2014-01-06 15:46:01.428 Online[8796:60b] I restkit.network:RKObjectRequestOperation.m:180 GET 'http://10.174.10.35/service/service.svc/users/login/quick/shortToken?&extraCode=null&phone=0505717596'
2014-01-06 15:50:03.999 Online[8796:60b] {"responseError":null,"shortToken":"I55933325601458654742"}
2014-01-06 15:46:01.577 Online[8796:60b] (
"<RKLongToken: 0x14dd3a50>"
)
2014-01-06 15:46:04.490 Online[8796:1403] I restkit.network:RKObjectRequestOperation.m:250 GET 'http://10.174.10.35/service/service.svc/users/login/quick/shortToken?&extraCode=null&phone=0505717596' (200 OK / 1 objects) [request=3.0587s mapping=0.0030s total=3.1129s]
What seems to be the problem here?
UPDATE:
I've added pathPattern to the descriptor as #Wain told me to, but now I'm getting an error. It looks like this:
"No mappable object representations were found at the key paths searched."
NSLocalizedFailureReason=The mapping operation was unable to find any nested object representations at the key paths searched: Banners, Branches, BranchTypes, Cities, MenuList
The representation inputted to the mapper was found to contain nested object representations at the following key paths: responseError, shortToken
This likely indicates that you have misconfigured the key paths for your mappings., NSLocalizedDescription=No mappable object representations were found at the key paths searched., keyPath=null}`
All of your response descriptors have pathPattern:nil, so RestKit can't filter and will apply all of them and see what happens. So, for all of your JSON you will get multiple objects containing only the parts of each mapping that match the JSON.
To fix, add path patterns to allow RestKit to determine which response descriptor matches each of your requests.
The correct way to do that is first to initialize the RestKit client:
NSURL *baseURL = [NSURL URLWithString:kServiceBaseURL];
self.manager = [RKObjectManager managerWithBaseURL:baseURL];
[self.manager setRequestSerializationMIMEType:RKMIMETypeJSON];
[self.manager setAcceptHeaderWithMIMEType:RKMIMETypeJSON];
[self.manager addResponseDescriptorsFromArray:[RKObjectManager sharedManager].responseDescriptors];
[self.manager addRequestDescriptorsFromArray:[RKObjectManager sharedManager].requestDescriptors];
[self.manager.HTTPClient.operationQueue setMaxConcurrentOperationCount:5];
[RKObjectManager setSharedManager:self.manager];
Than to initialize the Routes that you want:
RKRoute *shortTokenRoute = [RKRoute routeWithClass:[RKShortToken class] pathPattern:#"users/login/quick/shortToken" method:RKRequestMethodGET];
shortTokenRoute.shouldEscapePath = YES;
[self.manager.router.routeSet addRoute:shortTokenRoute];
Than to create a reponseDescriptor:
RKObjectMapping *shortTokenMapping = [RKObjectMapping mappingForClass:[RKShortToken class]];
[shortTokenMapping addAttributeMappingsFromDictionary:#{ #"responseError" : #"responseError", #"shortToken" : #"shortToken" }];
RKResponseDescriptor *shortTokenDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:shortTokenMapping
method:RKRequestMethodAny
pathPattern:#"users/login/quick/shortToken"
keyPath:nil
statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
[[RKObjectManager sharedManager] addResponseDescriptor:shortTokenDescriptor];
Than the request:
NSDictionary *params = #{ #"phone" : telephone, #"extraCode" : extraCode };
[[RKObjectManager sharedManager] getObject:[[RKShortToken alloc] init]
path:#"users/login/quick/shortToken"
parameters:params
success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
NSLog(#"%#", operation.HTTPRequestOperation.responseString);
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
NSLog(#"%#", error.localizedDescription);
}];
Enjoy.
i'm having a web service that that collects the company names and phone numbers from the database. But sometimes a phone number is not provided. When i try to map the phone number to the object with restkit 'im getting a warning that value is nil sometimes. then i get the warning message:
Coercing NSNull value to nil in shouldSetValue:atKeyPath: -- should be fixed.
any suggestions how to map nil to NSNull?
this is my header file of my customerrealtion class (.h):
#import <Foundation/Foundation.h>
#import <RestKit/RestKit.h>
#interface CustomerRelation : NSObject
#pragma private fields
#property (nonatomic, copy) NSString *companyName;
#property (nonatomic, copy) NSString *phoneNumber;
#end
implementation file of customer relation class (.m)
#import "CustomerRelation.h"
#implementation CustomerRelation
-(BOOL)ValidatecompanyName:(id*)ioValue error:(NSError **)outError {
NSLog(#"error");
}
-(BOOL)validatephoneNumber:(id *)ioValue error:(NSError **)outError {
if (*ioValue == nil) {
if (outError != NULL) {
}
return NO;
}
return YES;
}
#end
this is where i do the mapping:
- (void)viewDidAppear:(BOOL)animated{
RKObjectManager * client = [RKObjectManager managerWithBaseURL:[NSURL URLWithString:#"http://127.0.0.1"]];
RKObjectMapping *articleMapping = [RKObjectMapping requestMapping];
[articleMapping addAttributeMappingsFromDictionary:#{#"Companyname": #"companyName",
#"Phonenumber": #"phoneNumber"}];
RKResponseDescriptor *rkresponsedesc = [RKResponseDescriptor responseDescriptorWithMapping:articleMapping method:RKRequestMethodGET pathPattern:nil keyPath:#"customers" statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
[client addResponseDescriptor:rkresponsedesc];
NSMutableURLRequest *request = [client requestWithObject:nil method:RKRequestMethodGET path:#"test.php" parameters:nil];
RKObjectRequestOperation *operation = [client objectRequestOperationWithRequest:request
success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
[self mappingSuccess:mappingResult];
} failure: ^(RKObjectRequestOperation *operation, NSError *error) {
NSLog(#"Failed with error: %#", [error localizedDescription]);
}];
[client enqueueObjectRequestOperation:operation];
MainViewController *viewController = [self.storyboard instantiateViewControllerWithIdentifier:#"mainViewController"];
[self.navigationController pushViewController:viewController animated:YES];
}
- (void)mappingSuccess:(RKMappingResult*)mappingResult
{
NSLog(#"Success block: %#", mappingResult);
}
Seeing that error I guess you're using an old version of RestKit and that you should update.
That said you should be able to tie into this with KVC validation which RestKit supports. If you implement validateValue:forKey:error: on your destination model object you can verify and edit the value being set for any key.
i finally found why the validate methods were never called.
the error was in the line
RKObjectMapping *customerRelationMapping = [RKObjectMapping requestMapping];
what should get the class instead:
RKObjectMapping *customerRelationMapping = [RKObjectMapping mappingForClass:[Article class]];