Response 200OK but code enters the failure block in restkit - restkit

I have connected Charles to check the response of the call. The response header return 200OK but even then the code enters the failure block. Does it have to do anything with the way mapping is defined or is it some other trivial issue?
NSString *reviewsRequest = [NSString stringWithFormat:#"reviews/%#", reviewerId];
[MTAuthHandler refreshTokenIfExpired:^(id result, NSError *error) {
[MTRestkitManager instance].objectManager.requestSerializationMIMEType = RKMIMETypeJSON;
[[MTRestkitManager instance].objectManager getObjectsAtPath:reviewsRequest parameters:nil success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
NSLog(#"success");
if (completion) {
completion(YES, nil);
}
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
NSLog(#"failed");
if (completion) {
completion(NO, error);
}
}];
}];
The error message shows - NSLocalizedDescription=Expected status code in (400-499), got 200
Any pointers will be highly appreciated.

Related

Error for request to endpoint 'me/feed': An open FBSession must be specified for calls to this endpoint

I know this question is posted many times but truly i didn't get any suggestion that can solve my problem. I wasted my two days on this problem but till now i didn't get any solutions. Please give your valuable guidance.
I want to post status on Facebook.
if ([PostType isEqual:#"article"])
{
[dict setObject:PostTitle forKey:#"message"];
params = [NSMutableDictionary dictionaryWithObjectsAndKeys:
PostTitle, #"message", nil];
if (FBSession.activeSession.isOpen) {
// Yes, we are open, so lets make a request for user details so we can get the user name.
if ([[[FBSession activeSession] permissions]indexOfObject:#"publish_actions"] == NSNotFound) {
[[FBSession activeSession] requestNewPublishPermissions:[NSArray arrayWithObjects: #"publish_actions",nil] defaultAudience:FBSessionDefaultAudienceFriends
completionHandler:^(FBSession *session,NSError *error){
[self promptUserWithAccountName];
}];
}else{
[self promptUserWithAccountName];
}
// a custom method - see below:
} else {
NSArray *permissions = [[NSArray alloc] initWithObjects:
#"publish_actions",
nil];
// OPEN Session!
[FBSession openActiveSessionWithPermissions:permissions
allowLoginUI:YES
completionHandler:^(FBSession *session,
FBSessionState status,
NSError *error) {
// if login fails for any reason, we alert
if (error) {
// show error to user.
} else if (FB_ISSESSIONOPENWITHSTATE(status)) {
// no error, so we proceed with requesting user details of current facebook session.
[self promptUserWithAccountName]; // a custom method - see below:
}
}];
}
Custom method:
-(void)promptUserWithAccountName {
[[FBRequest requestForMe] startWithCompletionHandler:
^(FBRequestConnection *connection, NSDictionary<FBGraphUser> *user, NSError *error) {
if (!error) {
[FBRequestConnection startWithGraphPath:#"me/feed"
parameters:params
HTTPMethod:#"POST"
completionHandler:^(FBRequestConnection *connection,
id result,
NSError *error){
if (!error) {
UIAlertView *tmp = [[UIAlertView alloc]
initWithTitle:#"Success"
message:#"Photo Uploaded"
delegate:self
cancelButtonTitle:nil
otherButtonTitles:#"Ok", nil];
[tmp show];
} else {
UIAlertView *tmp = [[UIAlertView alloc]
initWithTitle:#"Error"
message:#"Some error happened"
delegate:self
cancelButtonTitle:nil
otherButtonTitles:#"Ok", nil];
[tmp show];
}
}];
}
}];
}

How to perform a DELETE request using RestKit (0.20)?

I'm trying to send a DELETE request using RestKit, but it seems that it is always sent as "GET". Here is my code:
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor
responseDescriptorWithMapping:[self objectMapping]
method:RKRequestMethodDELETE
pathPattern:nil
keyPath:nil
statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
RKObjectRequestOperation *objectRequestOperation = [[RKObjectRequestOperation alloc] initWithRequest:request responseDescriptors:#[ responseDescriptor ]];
[objectRequestOperation setCompletionBlockWithSuccess:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
[delegate onRequestSuccess:mappingResult.array];
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
RKLogError(#"operation failed with error: %#", error);
[delegate onRequestError:operation message:error];
}];
[objectRequestOperation start];
I tried also using RKObjectManager:deleteObject, which does correctly send a DELETE request, but the response does not get mapped.
RKObjectManager *manager = [RKObjectManager managerWithBaseURL:request.url];
[manager addResponseDescriptor:responseDescriptor];
[manager deleteObject:nil path:request.urlString parameters:nil
success:^(RKObjectRequestOperation *operation , RKMappingResult *mappingResult) {
Tag *tag = mappingResult.firstObject; // this is null, does not get mapped
} failure:^(RKObjectRequestOperation *operation , NSError *error) {
RKLogError(#"Error deleting tag %#, error: %#", tagId, error);
}];
If you're using RKObjectRequestOperation you need to configure the request yourself. It's GET because that is the default.
If you use RKObjectManager then you can use deleteObject instead which will do it for you.

AFNetworking are not writing a response in variable

I have a problem code with using AFNetworking:
#import "SyncProfile.h"
#import "AFNetworking.h"
#implementation SyncProfile: NSObject
#synthesize delegate = _delegate;
- (BOOL)syncProfile {
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
NSString *token =[userDefaults objectForKey:#"token"];
int user_id = [userDefaults objectForKey:#"user_id"];
if([token length]) {
self.profileData = [[self sendRequest:#"method.get" token:token withUser:user_id andParameters:#"param1,param2"] valueForKeyPath:#"response"];
NSLog(#"%#", self.profileData);
return YES;
} else
return NO;
}
-(id)sendRequest:(NSString *)apiMethod token:(NSString *)token withUser:(int)user_id andParameters:(NSString *)param {
NSMutableString *apiLink = [NSMutableString stringWithFormat:#"https://domain.com/method/%#?uid=%#&fields=%#&access_token=%#", apiMethod, user_id, param, token];
NSURL *url = [[NSURL alloc] initWithString:apiLink];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
NSLog(#"%#", JSON);
self.req = JSON;
[self myMethod:JSON];
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
NSLog(#"Request Failed with Error: %#, %#", error, error.userInfo);
}];
[operation start];
return self.req;
}
- (id)myMethod:(id)data {
NSLog(#"%#",data);
return 0;
}
#end
I need to return a variable with the result AFNetworking back method. But the result is given much later than the method returns. When I use a different method to handle the result, it does not. Tried to use the [operation waitUntilFinished] but nothing has changed.
Result in Xcode Output:
//Return variable from "sync" method
2013-02-26 23:57:29.793 walkwithme[13815:11303] (null)
//Return from AFN response
2013-02-26 23:57:31.063 walkwithme[13815:11303] {response = ({someJSON})}
//Return from MyMethod
2013-02-26 23:57:31.063 walkwithme[13815:11303] {response = ({someJSON})}
You definitely don't want to use any wait methods. What you need to do is have a call back in your success and failure blocks. You can do this the way I showed in this question you could also do something else like message passing. The key thing to realize is you won't be using the typical method return pattern. Reason being with asynchronous methods like this you have no idea when it will finish which is why it uses the block call backs. Like I said you definitely don't want to wait because that could entirely block your application.
EDIT:
I use this code in one of my projects:
Declare method
- (void)postText:(NSString *)text
forUserName:(NSString *)username
ADNDictionary:(NSDictionary *)dictionary
withBlock:(void(^)(NSDictionary *response, NSError *error))block;
Then inside this method I pass those parameters to the network request.
Return values in the block with:
if (block) {
block(responseObject, someError);
}
Then I call it with this:
[[KSADNAPIClient sharedAPI] postText:postText
forUserName:username
ADNDictionary:parameters
withBlock:^(NSDictionary *response, NSError *error)
{
if (error) {
// Deal with error
} else {
// Probably success!
}
}
This way the called method returns it's values to the caller method inside the block. I think about it that it defers the block to the caller.

Restkit 0.20 basic operation

I am just getting started with RestKit and have arrived just as Rk 0.20 is going live and the documentation and demo's are a step behind. Most stuff on the web is for RK 0.10 and there are big changes in the 0.20 version.
I don't want to fall back to an earlier version when the new one will very soon be up and running.
I have a JSON resource at a URL "test.myserver.com" that returns a simple datagram -
{
"id_user": "4401",
"datalocation": "4401",
"country": "Great-Britain",
"data": "testdata",
"login": "Fred Bloggs",
"password": "579c0cb0ed2dc25db121283f7a98cc71",
"accessLevel": "2",
"timestamp": "1012",
"datahash": "2749da29f20ce7a85092323f193adee8"
}
I am pretty sure I have the Mappings etc sorted but my service requires authentication so I need to pass a user name and password in the request to the server.
I have got this so far
NSURL *url = [NSURL URLWithString:#"http://test.myserver.com"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
RKObjectRequestOperation *objectRequestOperation = [[RKObjectRequestOperation alloc] initWithRequest:request responseDescriptors:#[ responseDescriptor ]];
[objectRequestOperation setCompletionBlockWithSuccess:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
RKLogInfo(#"Load collection of Articles: %#", mappingResult.array);
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
RKLogError(#"Operation failed with error: %#", error);
}];
[objectRequestOperation start];
Which appears to contact the server but inevitably logs the following error
restkit.network:RKObjectRequestOperation.m:296 Object request failed: Underlying HTTP request operation failed with error: Error Domain=org.restkit.RestKit.ErrorDomain Code=-1011 "Expected status code in (200-299), got 401" UserInfo=0x7884030 {NSLocalizedRecoverySuggestion={
"error": {
"code": 401,
"message": "Unauthorized: Authentication required"
}
}, AFNetworkingOperationFailingURLRequestErrorKey=http://elancovision.umfundi.com>, NSErrorFailingURLKey=http://elancovision.umfundi.com, NSLocalizedDescription=Expected status code in (200-299), got 401, AFNetworkingOperationFailingURLResponseErrorKey=}
The question of course is how I add the user name and password into the request.
Sorry for the noob question!
With basic HTTP authentication, username and password should be inserted into the HTTP request authorization header field for each request.
First, I suggest you to use RKObjectManager to centralize configuration for requests and mappings. http://restkit.org/api/latest/Classes/RKObjectManager.html
RKObjectManager can store network parameters (through AFNetworking Library), then build appropriate http query based on username/password, paths, objectmapping.
Adapting your example, it would give something like :
NSURL* url = [[NSURL alloc]initWithString:#"http://test.myserver.com"];
RKObjectManager* objectManager = [RKObjectManager managerWithBaseURL:url];
[objectManager.HTTPClient setAuthorizationHeaderWithUsername:#"username" password:#"password"];
//NSURLRequest *request = [NSURLRequest requestWithURL:url];
NSURLRequest *request = [objectManager requestWithObject:nil method:RKRequestMethodGET path:#"/yourAPI/yourmethod" parameters:nil];
RKObjectRequestOperation *objectRequestOperation = [[RKObjectRequestOperation alloc] initWithRequest:request responseDescriptors:#[ responseDescriptor ]];
[objectRequestOperation setCompletionBlockWithSuccess:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
RKLogInfo(#"Load collection of Articles: %#", mappingResult.array);
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
RKLogError(#"Operation failed with error: %#", error);
}];
[objectRequestOperation start];
If authentication works, having a look at the RESTKit wiki should give you the next hints to build correct mappings : https://github.com/RestKit/RestKit/wiki/Object-mapping
My solution here:
// Build a RestKit manager object to look after the restful stuff
RKObjectManager *manager = [RKObjectManager managerWithBaseURL:[NSURL URLWithString:#"http://test.myserver.com"]];;
// Hash the GUI input password string and pass the username in plain text
NSString *md5PW = [umfundiCommon md5:passwordField.text];
[manager.HTTPClient setAuthorizationHeaderWithUsername:userField.text password:md5PW];
RKObjectMapping *WebResponse = [RKObjectMapping mappingForClass:[WSObject class]];
[WebResponse addAttributeMappingsFromDictionary:#{#"id_user":#"id_user", #"datalocation": #"datalocation", #"country":#"country", #"data": #"data", #"login": #"login", #"password": #"password", #"accessLevel": #"accessLevel", #"timestamp": #"timestamp", #"datahash": #"datahash"}];
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:WebResponse pathPattern:nil keyPath:nil statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
// Add the above response descriptor to the manager
[manager addResponseDescriptor:responseDescriptor];
// the getObject makes the call using the stuff assembled into the manager Object and drops into either the success or the failure routines.
[manager getObject:nil path:#"" parameters:nil success:^(RKObjectRequestOperation *operation, RKMappingResult *result)
{
NSLog (#"Server WS call success:");
NSArray *theresults = [result array];
for (WSObject *item in theresults) {
NSLog(#"datahash=%#",item.datahash);
NSLog(#"user_id=%#",item.id_user);
}
} failure:^(RKObjectRequestOperation * operation, NSError * error)
{
NSLog (#"Server WS call failure: operation: %# \n\nerror: %#", operation, error);
}];
........

Access Response Data in Success callback

Is there any way to access the response data in the success block for a request using the object manager?
[objectManager postObject:[User class] path:#"/users" parameters:nil success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
NSLog(#"success");
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
NSLog(#"failure");
}];
It seems like there should be some way to use the mapping or operation to get this information as maybe NSData or something.
You can get this info from the RKObjectRequestOperation *operation
operation.HTTPRequestOperation.response
operation.HTTPRequestOperation.responseData
operation.HTTPRequestOperation.responseString
try this
[objectRequestOperation setCompletionBlockWithSuccess:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
// parse the response---
NSDictionary *myDic = [NSJSONSerialization JSONObjectWithData:operation.HTTPRequestOperation.responseData options:NSJSONReadingMutableLeaves error:nil];
NSLog(#"=======:%#",myDic);
NSLog(#"MY email============ %# ",[myDic objectForKey:#"Email"]);
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
RKLogError(#"Operation failed with error: %#", error);
}];

Resources