AFNetworking PUT request Error 400 - iphone

I am trying to make a PUT request using AFNetworking. There is a JSON on a remote location, which I want to update with the request.
I have managed to serialize my object into JSON, and I have put it an NSDictionary object:
NSDictionary *container = [NSDictionary dictionaryWithObject:[self notifications] forKey:#"notifications"];
This way when I print out the container using NSLog, I get precisely the JSON I want to send.
Then I try to use AFNetworking for my request:
AFHTTPClient *putClient = [[AFHTTPClient alloc] initWithBaseURL:[NSURL URLWithString:#"http://creativemind.appspot.com"]];
[putClient setParameterEncoding:AFJSONParameterEncoding];
NSMutableURLRequest *putRequest = [putClient requestWithMethod:#"PUT"
path:#"/notifications"
parameters:container];
AFHTTPRequestOperation *putOperation = [[AFHTTPRequestOperation alloc] initWithRequest:putRequest];
[putClient registerHTTPOperationClass:[AFHTTPRequestOperation class]];
[putOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"Response: %#", [[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding]);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
[putOperation start];
When I try this solution, I get the following error message:
2013-08-10 16:10:40.741 NotificationReader[1132:c07] Error: Error
Domain=AFNetworkingErrorDomain Code=-1011 "Expected status code in
(200-299), got 400" UserInfo=0x75c89e0
{NSLocalizedRecoverySuggestion={"cause":null,"class":"java.lang.NumberFormatException","localizedMessage":"null","message":"null"},
AFNetworkingOperationFailingURLRequestErrorKey=http://creativemind.appspot.com/notifications>,
NSErrorFailingURLKey=http://creativemind.appspot.com/notifications,
NSLocalizedDescription=Expected status code in (200-299), got 400,
AFNetworkingOperationFailingURLResponseErrorKey=}
I think it's important to note that when I try the same request with nil parameters, I get te same error message. I also tried to perform a GET request on the same JSON to check if I can reach it and it works perfectly. I really have no idea what I could do. Any help would be appreciated

Related

POST Request with AFNetworking 2.0 not working, but working in HTTP Request tester

I've just started using the new AFNetworking 2.0 API having used the previous versions for a while now. I'm trying to do a bog standard http POST request, but sadly I'm not doing too well. This is my current code:
AFHTTPRequestOperationManager *operationManager = [AFHTTPRequestOperationManager manager];
NSDictionary *parameters = #{#"username" : self.usernameField.text,
#"password" : self.passwordField.text};
[operationManager POST:#"https:URL GOES HERE" parameters:parameters success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"JSON: %#", [responseObject description]);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
Now this returns a JSON of (NULL) and doesn't give me a status code like 404 or something (incidentally how do we attain the status code when using AFN 2.0?). However, when I try the information with a web app like apikitchen.com which tests the HTTP Post request for me, it works when I put the username and password in the param field. So really my question is, why don't the parameters in the AFN 2.0 parameter property act in the same way as the parameters in the web app? And more generally why aren't the post request parameters working for me in AFN 2.0?
Thanks for the help in advance,
Mike
EDIT: I'm struggling with the implementation of the suggested fix. My Post method now looks like this, but It doesn't make sense to me right now.
AFHTTPRequestOperationManager *operationManager = [AFHTTPRequestOperationManager manager];
NSDictionary *parameters = #{#"username" : self.usernameField.text,
#"password" : self.passwordField.text};
operationManager.requestSerializer.queryStringSerializationWithBlock =
^NSString*(NSURLRequest *request,
NSDictionary *parameters,
NSError *__autoreleasing *error) {
NSString* encodedParams = form_urlencode_HTTP5_Parameters(parameters);
return encodedParams;
};
[operationManager POST:#"URL HERE" parameters:parameters success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"JSON: %#", [responseObject description]);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
Now this returns a JSON of (NULL) and doesn't give me a status code like 404 or something (incidentally how do we attain the status code when using AFN 2.0?).
It should at least give an error. What does the failure handler print out?
So really my question is, why don't the parameters in the AFN 2.0 parameter property act in the same way as the parameters in the web app? And more generally why aren't the post request parameters working for me in AFN 2.0?
After examining how AFN (Version 2.0.1) encodes the parameters, it appears to me that these aren't encoded as they should: The application/x-www-form-urlencoded encoding algorithm.
Until this has been fixed, you may try the following workaround. The following algorithm encodes parameters strictly as suggested by w3c for HTTP 5, at least for Mac OS X 10.8 where I've tested it:
static NSString* form_urlencode_HTTP5_String(NSString* s) {
CFStringRef charactersToLeaveUnescaped = CFSTR(" ");
CFStringRef legalURLCharactersToBeEscaped = CFSTR("!$&'()+,/:;=?#~");
NSString *result = CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(
kCFAllocatorDefault,
(__bridge CFStringRef)s,
charactersToLeaveUnescaped,
legalURLCharactersToBeEscaped,
kCFStringEncodingUTF8));
return [result stringByReplacingOccurrencesOfString:#" " withString:#"+"];
}
(Note: the code above depends on the implementation details of function CFURLCreateStringByAddingPercentEscapes. It's entirely possible to implement the suggested algorithm easily without any dependencies, which I would recommend - it becomes just not that short.)
static NSString* form_urlencode_HTTP5_Parameters(NSDictionary* parameters)
{
NSMutableString* result = [[NSMutableString alloc] init];
BOOL isFirst = YES;
for (NSString* name in parameters) {
if (!isFirst) {
[result appendString:#"&"];
}
isFirst = NO;
assert([name isKindOfClass:[NSString class]]);
NSString* value = parameters[name];
assert([value isKindOfClass:[NSString class]]);
NSString* encodedName = form_urlencode_HTTP5_String(name);
NSString* encodedValue = form_urlencode_HTTP5_String(value);
[result appendString:encodedName];
[result appendString:#"="];
[result appendString:encodedValue];
}
return [result copy];
}
Then, when using AFN, you can customize the serializing algorithm as shown below:
AFHTTPRequestOperationManager *operationManager = [AFHTTPRequestOperationManager manager];
operationManager.requestSerializer.queryStringSerializationWithBlock =
^NSString*(NSURLRequest *request,
NSDictionary *parameters,
NSError *__autoreleasing *error) {
NSString* encodedParams = form_urlencode_HTTP5_Parameters(parameters);
return encodedParams;
};
Put / after the url. I've missed it for hours.

Login using POST with RestKit returns 404 error

I'm totally new to RestKit and I'm trying to use a POST request to login to my system. I'm using RestKit version 0.20.3 and this is how I did:
- (IBAction)login:(id)sender {
NSString *email = [self.emailTextField text];
NSString *password = [self.passwordTextField text];
NSURL *url = [[NSURL alloc] initWithString:#"http://myhost.com/api.php"];
RKObjectManager *manager = [RKObjectManager managerWithBaseURL:url];
NSDictionary *tmp = #{#"rquest":#"user",
#"tag":#"login",
#"email":email,
#"password":password};
[manager postObject:tmp path:#"" parameters:nil
success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
NSDictionary *result = [mappingResult dictionary];
if([[result objectForKey:#"success"] isEqualToNumber:[NSNumber numberWithInt:1]]){
NSUserDefaults *def = [NSUserDefaults standardUserDefaults];
[def setBool:YES forKey:#"isLoggedIn"];
// set user details...
[self.navigationController popToRootViewControllerAnimated:YES];
}
}
failure:^(RKObjectRequestOperation *operation, NSError *error) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Error"
message:[error localizedDescription]
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
NSLog(#"Hit error: %#", error);
}];
}
As you can see, since I don't really need to map the response into an object, I tried to access the response data with NSDictionary. I'm not sure if this is the problem, but when I try to run the above code, I get the error:
013-10-06 11:24:51.897 Eateries[1182:454b] E restkit.network:RKResponseMapperOperation.m:304 Failed to parse response data: Loaded an unprocessable response (404) with content type 'application/json'
2013-10-06 11:24:51.902 Eateries[1182:1003] E restkit.network:RKObjectRequestOperation.m:243 POST 'http://myhost.com/api.php' (404 Not Found / 0 objects) [request=0.1479s mapping=0.0000s total=0.1648s]: Error Domain=org.restkit.RestKit.ErrorDomain Code=-1017 "Loaded an unprocessable response (404) with content type 'application/json'" UserInfo=0x8ee81e0 {NSErrorFailingURLKey=http://myhost.com/api.php, NSUnderlyingError=0x8ef4ea0 "The operation couldn’t be completed. (Cocoa error 3840.)", NSLocalizedDescription=Loaded an unprocessable response (404) with content type 'application/json'}
2013-10-06 11:24:51.978 Eateries[1182:a0b] Hit error: Error Domain=org.restkit.RestKit.ErrorDomain Code=-1017 "Loaded an unprocessable response (404) with content type 'application/json'" UserInfo=0x8ee81e0 {NSErrorFailingURLKey=http://myhost.com/api.php, NSUnderlyingError=0x8ef4ea0 "The operation couldn’t be completed. (Cocoa error 3840.)", NSLocalizedDescription=Loaded an unprocessable response (404) with content type 'application/json'}
I'm really confused because I don't really know what I did wrong here. If you have any suggestion, please kindly let me know. Thank you.
P.s: I changed the name of my host just for my personal purpose, but my server really responses ok with the request when I try to test it from other platforms.
You are using the wrong API.
postObject:... is meant for posting an object to be mapped, meaning that the object parameter - if not nil - will be used as target to map the response.
If you don't want to map the response, just use the underlying AFHTTPClient to perform a plain POST request.
[[RKObjectManager sharedManager].HTTPClient postPath:#"" parameters:tmp success:^(AFHTTPRequestOperation *operation, id responseObject) {
// ...
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
// ...
}

I am getting bad request from the server when making DELETE request

I am using AFNetworking shared client in order to make request to the REST server.
My code for delete is:
NSMutableDictionary* params = [[NSMutableDictionary alloc] init];
[[ApiClient sharedClient] deletePath:[NSString stringWithFormat:#"users/%#/venues/%#/", appDelegate.currentUser.userId, venue.venueId] parameters:params success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"venue deleted from saved");
} failure:^(AFHTTPRequestOperation *operation, NSError *error){
NSLog(error.description);
}];
When I am configuring the client, I am adding:
[self registerHTTPOperationClass:[AFJSONRequestOperation class]];
[self setDefaultHeader:#"Accept" value:#"application/json"];
[self setDefaultHeader:#"Content-Type" value:#"application/json"];
[self setParameterEncoding:AFJSONParameterEncoding];
POST request is working fine, but there is a problem with the DELETE request. Where am I wrong?
You will need to look at the error and check what is going wrong. If there error is not helpful, then you will need to use a proxy (perhaps Charles) and see exactly what is happening with the request and why the server does not like it.

TWRequest post reply NSURLErrorDomain

I am having trouble sending a reply to a tweet using TWRequest api. I am able to post a new tweet/status successfully but replies are failing with error below. Please advise
The error I receive on the reply post is:
Error Domain=NSURLErrorDomain Code=-1012 "The operation couldn’t be completed.
(NSURLErrorDomain error -1012.)" UserInfo=0x6c67900 {NSErrorFailingURLKey=https://api.twitter.com/1/statuses/update.json, NSErrorFailingURLStringKey=https://api.twitter.com/1/statuses/update.json,
NSUnderlyingError=0x6ce28a0 "The operation couldn’t be completed. (kCFErrorDomainCFNetwork error -1012.)"}
Sample code below:
NSDictionary *paramDict = nil;
if(isReply)
{
paramDict = [NSDictionary dictionaryWithObjectsAndKeys:
in_reply_to_status_id, #"in_reply_to_status_id",
status, #"status",
nil];
NSLog(#"Status is %# %#",status,in_reply_to_status_id);
}
else
{
paramDict = [NSDictionary dictionaryWithObject:status forKey:#"status"];
}
TWRequest *sendTweet = [[TWRequest alloc]
initWithURL:[NSURL URLWithString:#"https://api.twitter.com/1/statuses/update.json"]
parameters:paramDict
requestMethod:TWRequestMethodPOST];
sendTweet.account = self.account;
[sendTweet performRequestWithHandler:^(NSData *responseData,
NSHTTPURLResponse *urlResponse,
NSError *error) {
if ([urlResponse statusCode] == 200) {
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(#"Sent tweet: %#", status);
});
}
else {
NSLog(#"Problem sending tweet: %#", error);
}
}];
Stop looking for any help with TWRequest Twitter.framework is deprecated with iOS 6.0 For any
references do visit the dev.twitter.com
Use Social.Framework if you only need to post tweet or Images with tweet you can use SLComposeViewController for that purpose.
In Other Cases like replying to a tweet or favorite or even embedding Try this Singleton Class:
https://github.com/fhsjaagshs/FHSTwitterEngine
Read it's description do launch the demo and YOUR all set

Converting from ASIHTTPRequest to AFNetworking

I am converting my app routines from ASIHTTP to AFNetworking due to the unfortunate discontinuation of work on that project ... and what I found out later to be the much better and smaller codebase of AFNetworking.
I am finding several issues. My code for ASIHTTPRequest is built as a method. This method takes a few parameters and posts the parameters to a url ... returning the resulting data. This data is always text, but in the interests of making a generic method, may sometimes be json, sometimes XML or sometimes HTML. Thus I built this method as a standalone generic URL downloader.
My issue is that when the routine is called I have to wait for a response. I know all the "synchronous is bad" arguments out there...and I don't do it a lot... but for some methods I want synchronous.
So, here is my question. My simplified ASIHTTP code is below, followed by the only way i could think of coding this in AFNetworking. The issue I have is that the AFNetworking sometimes does not for the response before returning from the method. The hint that #mattt gave of [operation waitUntilFinished] totally fails to hold the thread until the completion block is called... and my other method of [queue waitUntilAllOperationsAreFinished] does not necessarily always work either (and does NOT result in triggering the error portion of the [operation hasAcceptableStatusCode] clause). So, if anyone can help, WITHOUT The ever-present 'design it asynchronously', please do.
ASIHTTP version:
- (NSString *) queryChatSystem:(NSMutableDictionary *) theDict
{
NSString *response = [NSString stringWithString:#""];
NSString *theUrlString = [NSString stringWithFormat:#"%#%#",kDataDomain,kPathToChatScript];
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:[NSURL URLWithString:theUrlString]];
for (id key in theDict)
{
[request setPostValue:[theDict objectForKey:key] forKey:key];
}
[request setNumberOfTimesToRetryOnTimeout:3];
[request setAllowCompressedResponse:YES];
[request startSynchronous];
NSError *error = [request error];
if (! error)
{
response = [request responseString];
}
return response;
}
AFNetworking version
- (NSString *) af_queryChatSystem:(NSMutableDictionary *) theDict
{
NSMutableDictionary *theParams = [NSMutableDictionary dictionaryWithCapacity:1];
for (id key in theDict)
{
[theParams setObject:[theDict objectForKey:key] forKey:key];
}
AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:[NSURL URLWithString:kDataDomain]];
NSMutableURLRequest *theRequest = [httpClient requestWithMethod:#"POST" path:[NSString stringWithFormat:#"/%#",kPathToChatScript] parameters:theParams];
__block NSString *responseString = [NSString stringWithString:#""];
AFHTTPRequestOperation *operation = [[[AFHTTPRequestOperation alloc] initWithRequest:theRequest] autorelease];
operation.completionBlock = ^ {
if ([operation hasAcceptableStatusCode]) {
responseString = [operation responseString];
NSLog(#"hasAcceptableStatusCode: %#",responseString);
}
else
{
NSLog(#"[Error]: (%# %#) %#", [operation.request HTTPMethod], [[operation.request URL] relativePath], operation.error);
}
};
NSOperationQueue *queue = [[[NSOperationQueue alloc] init] autorelease];
[queue addOperation:operation];
[queue waitUntilAllOperationsAreFinished];
[httpClient release];
return responseString;
}
Thanks very much for any ideas.
- (void)af_queryChatSystem:(NSMutableDictionary *) theDict block:(void (^)(NSString *string))block {
...
}
Now within the completionBlock do:
block(operation.responseString);
block will act as the delegate for the operation. remove
-waitUntilAllOperationsAreFinished
and
return responseString
You call this like:
[YourInstance af_queryChatSystem:Dict block:^(NSString *string) {
// use string here
}];
Hope it helps. You can refer to the iOS example AFNetworking has
I strongly recommend to use this opportunity to convert to Apple's own NSURLConnection, rather than adopt yet another third party API. In this way you can be sure it won't be discontinued. I have found that the additional work required to get it to work is minimal - but it turns out to be much more robust and less error prone.
My solution is manually to run the current thread runloop until the callback have been processed.
Here is my code.
- (void)testRequest
{
MyHTTPClient* api = [MyHTTPClient sharedInstance]; // subclass of AFHTTPClient
NSDictionary* parameters = [NSDictionary dictionary]; // add query parameters to this dict.
__block int status = 0;
AFJSONRequestOperation* request = [api getPath:#"path/to/test"
parameters:parameters
success:^(AFHTTPRequestOperation *operation, id responseObject) {
// success code
status = 1;
NSLog(#"succeeded");
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
// failure
status = 2;
NSLog(#"failed");
}];
[api enqueueHTTPRequestOperation:request];
[api.operationQueue waitUntilAllOperationsAreFinished];
while (status == 0)
{
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
beforeDate:[NSDate date]];
}
STAssertEquals(status, 1, #"success block was executed");
}