When i request data from server with AFHHTPClient this way:
[[NetworkHelper sharedHelper] postPath:path parameters:parameters] success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"%#", [operation class]);
NSLog(#"%#", [responseObject class]);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"%#", [error localizedDescription]);
}];
I got this:
2012-10-10 13:24:36.881 MyApp[4635:c07] AFHTTPRequestOperation
2012-10-10 13:24:36.881 MyApp[4635:c07] NSConcreteData
I tried to force application/json content-type in server's response, but i still got AFHTTPRequestOperation.
But if i use this:
[[AFJSONRequestOperation JSONRequestOperationWithRequest:[NSURLRequest requestWithURL:myURL] success:^(NSURLRequest *request, NSURLResponse *response, id JSON) {
NSLog(#"%#", JSON);
} failure:^(NSURLRequest *request, NSURLResponse *response, NSError *error, id JSON) {
NSLog(#"%#", [error localizedDescription]);
}] start];
I got JSON responce i need.
What should i do to get JSON response with AFHTTPClient?
UPDATE:
I add NSLog(#"%#",[self.response MIMEType]); in - (BOOL)hasAcceptableContentType method in AFHTTPRequestOperation class and i recieve
2012-10-11 09:48:25.052 MyApp[3339:3803] application/json
but i still get AFHTTPRequestOperation class.
Try to set AFHTTPRequestOperation:acceptableContentTypes:
+ (NSSet *)acceptableContentTypes {
return [NSSet setWithObjects:#"application/json", #"text/json", #"text/javascript", nil];
}
I've had the same problem that I suspect may have something to do with the way AFJSONRequestOperation handles responses.
I've dispatched the exact same request using AFJSONRequestOperation using the NSMutableURLRequest returned from [AFHTTPClient clientRequestWithMethod] and constructing my own NSMutableURLRequest and each has a response with a different mime type — the one from [AFHTTPClient clientRequestWithMethod] indicates text/plain; the one from NSMutableURLRequest constructed "by hand" is text/json.
I've mentioned this here in this question:
AFNetworking with AFHTTPClient with AFJSONRequestOperation // MIME-Type Issues
Related
I'm a newbie in iOS development and I'm trying to figure out how to send GET request with AFNetworking.
I used the example provided in Tutorial on Using AFNetworking 2.0 and placed it in main expecting a error:
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
[manager GET:#"http://samwize.com/api/poos/"
parameters:nil
success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"JSON: %#", responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
...and I've got nothing, so I tried to point to the webservice that returns a valid JSON and also got nothing. Why none of blocks (success or failure) are executed?
Your code does not execute blocks (success or failure) beacause somthing went wrong.
but if you use try catch block then it will go into catch block try once.
code:
try {
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
[manager GET:#"http://samwize.com/api/poos/"
parameters:nil
success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"JSON: %#", responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
}#catch (NSException *exception) {
**// you will get error here**
}
Use following function and just send your URL in Argument
- (void)callWebservice : (NSString *)strURL{
AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:[NSURL urlWithEncoding:strURL]];
[httpClient registerHTTPOperationClass:[AFJSONRequestOperation class]];
[httpClient setDefaultHeader:#"Accept" value:#"application/json"];
[httpClient setParameterEncoding:AFJSONParameterEncoding];
NSMutableURLRequest *request = [httpClient requestWithMethod:#"GET" path:#"" parameters:nil];
[request setTimeoutInterval:180];
[AFJSONRequestOperation addAcceptableContentTypes:[NSSet setWithObject:#"text/html"]];
AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON)
{
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
NSLog(#"Success");
} failure:^ (NSURLRequest *request, NSURLResponse *response, NSError *error, id json){
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
NSLog(#"Failure");
}];
[GlobalManager setOperationInstance:operation];
[operation start];
}
It was strange, I just created another project (iOS instead of OSX) and called the same code from the IBAction and it worked easily. In Podfile I specified a new version of AFNetworking (2.5 instead of 2.4). I don't know if this is relevant.
Thank you everyone for trying to help me.
Try following code to do that.
#try {
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
manager.responseSerializer = [AFJSONResponseSerializer serializer];
[manager GET:stringURL parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject){
NSLog(#"JSON: %#", responseObject);
}
failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
}
#catch (NSException *exception) {
NSLog(#"Exception - %#", [exception debugDescription]);
}
#finally {
}
And make sure you have a valid JSON.
I am querying my server using AFNetworking, the latest - to date - version.
My server side PHP is sending a PHP related error but I am unable to see what the error is ( so I can debug it) as AFNetworking is expecting a JSON.
Could anyone tell me how could I see the full HTTP result. I've researched and I know is something to do with operation.responseString inside the success / fail block my current block does not have AFHTTPRequestOperation* operation and I can't add it as another block variable somehow.
I would really appreciate some help.
The following code uses
NSURL *url = [[NSURL alloc]initWithString:URL];
AFHTTPClient *httpClient = [[AFHTTPClient alloc]initWithBaseURL:url];
NSURLRequest *request = [httpClient multipartFormRequestWithMethod:#"POST" path:URLPATH parameters:params constructingBodyWithBlock:^(id<AFMultipartFormData> formData)
{
//...
}
AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request
success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON){
NSLog(#"Inside the success block %#",JSON);
[[self delegate ]shareExerciseDone:JSON];
[[self delegate] activityIndicatorFinish];
}
failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON){
NSLog(#"Response text is: %#", operation.responseString);
NSLog(#"json text is: %#", JSON);
NSLog(#"Request failed with error: %#, %#", error, error.userInfo);
[[self delegate] activityIndicatorFinish];
}];
[operation start];
The error
Request failed with error: Error Domain=NSCocoaErrorDomain Code=3840 "The operation couldn’t be completed. (Cocoa error 3840.)" (JSON text did not start with array or object and option to allow fragments not set.) UserInfo=0xc1b4520 {NSDebugDescription=JSON text did not start with array or object and option to allow fragments not set.}, {
NSDebugDescription = "JSON text did not start with array or object and option to allow fragments not set.";
Don't use AFJSONRequestOperation, just use AFHTTPRequestOperation.
For Uploading Images From iOS to Server i am using Afnetworking
can you try with this Code.and you will get response in success or failure.
NSData *userImgToUpload = UIImagePNGRepresentation(userImg.image);
NSURL *url = [NSURL URLWithString:#"www.domainname.com"];
AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:url];
NSLog(#"%#",#"Uploading data");
NSDictionary *parameters = [NSDictionary dictionaryWithObjectsAndKeys:usernameTxt.text,#"username", firstnameTxt.text,#"first_name",lastnameTxt.text,#"last_name", nil];
// Upload Image
NSMutableURLRequest *request = [httpClient multipartFormRequestWithMethod:#"POST" path:#"/addPatient" parameters:parameters constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
[formData appendPartWithFileData:userImgToUpload name:#"patientimage" fileName:[NSString stringWithFormat:#"%#.png",usernameTxt.text] mimeType:#"image/png"];
}];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"response: %#",[operation.responseString objectFromJSONString]);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Upload Failed");
NSLog(#"error: %#", [operation error]);
}];
[operation start];
You should listen for the AFNetworkingOperationDidStartNotification and AFNetworkingOperationDidFinishNotification events that fire at the beginning and end of the operation:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(YourOperationStartMethod:)
name:AFNetworkingOperationDidStartNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(YourOperationFinishMethod:)
name:AFNetworkingOperationDidFinishNotification
object:nil];
You can grab the operation object from the notification like this:
AFHTTPRequestOperation *operation =
(AFHTTPRequestOperation *) [notification object];
This operation object contains request and response properties.
A good example of how all this works can be found in the AFHTTPRequestOperationLogger plugin (which, of course, you could simply use, instead of writing your own thing).
I'm doing a request to the server and the server returns a JSON. AFNetworking framework returns a wrong formatted JSON.
This is what the server sends:
{"email":"XXXXXXX","firstName":"XXXXXX","lastName":"XXXXXXX","gender":"male","userToken":"XXXXXXXXXXX"}
This is what AFNetworking receives:
{
email = "XXXXXXX";
firstName = XXXXXX;
gender = male;
lastName = XXXXXXX;
token = XXXXXXXXXXXX;
}
My code:
AFHTTPClient *client = [[AFHTTPClient alloc] initWithBaseURL:[NSURL URLWithString:server_ip]];
NSURLRequest *request = [client requestWithMethod:#"POST" path:path parameters:params];
AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
NSLog(#"%#", JSON);
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
NSLog(#"Request Failed with Error: %#, %#", error, error.userInfo);
}];
[operation start];
The object you are printing out is the NSDictionary representation of the JSON received from the server.
If you want to see the raw JSON returned from the server, you should look at the responseString of the operation:
NSLog(#"%#", operation.responseString);
I've been trying to get a grip on AFHTTPClient in the specific instance of dispatching a request to a REST-based service that requires OAuth authentication. I have no problem with creating the OAuth authentication using GTMOAuth.
I can also successfully marshall parameters to dispatch the request and obtain a well-formed JSON response using a hand-cobbled NSMutableURLRequest and both AFJSONRequestOperation and an NSURLConnection. Those latter two mechanics were my sanity check that I was touching the service correctly.
I get a response using
[AFHTTPClient HTTPRequestOperationWithRequest:request success:^(AFHTTPRequestOperation *operation, id responseObject)]
but no matter what — it's interpreted as text/plain. The returned object's class is __NCFData.
No bueno.
This bit of code doesn't want to return a response that's a dictionary of any sort.
- (IBAction) testFlickr {
// marshall parameters
NSString *urlStr = #"http://api.flickr.com/";
NSURL *url = [NSURL URLWithString:urlStr];
AFHTTPClient *client = [[AFHTTPClient alloc]initWithBaseURL:url];
[client registerHTTPOperationClass:[AFJSONRequestOperation class]];
[client setParameterEncoding:AFJSONParameterEncoding];
NSDictionary *params = [[NSDictionary alloc]initWithObjectsAndKeys:#"json", #"format", #"66854529#N00", #"user_id", #"1", #"jsoncallback", nil];
NSString *path = [[NSString alloc]initWithFormat:#"services/rest/?method=flickr.people.getPhotos"];
NSMutableURLRequest *af_request = [client requestWithMethod:#"GET" path:path parameters:params];
// flickrAuth instance variable is an instance of GTMOAuthAuthentication
[self.flickrAuth authorizeRequest:af_request];
[client setAuthorizationHeaderWithToken:[self.flickrAuth accessToken]];
[client setDefaultHeader:#"Accept" value:#"application/json"];
[client requestWithMethod:#"GET" path:path parameters:params];
LOG_FLICKR_VERBOSE(0, #"Can Authorize? %#", ([self.flickrAuth canAuthorize] ? #"YES":#"NO"));
LOG_FLICKR_VERBOSE(0, #"%#", client);
// first way of trying..
AFHTTPRequestOperation *af_operation = [client HTTPRequestOperationWithRequest:af_request success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSString *str = [[NSString alloc] initWithData:responseObject
encoding:NSUTF8StringEncoding];
LOG_FLICKR_VERBOSE(0, #"Weird af_operation semantics, but.. %#", str);
LOG_FLICKR_VERBOSE(0, #"Weird af_operation semantics returns %#", [responseObject class]);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
//
LOG_FLICKR_VERBOSE(0, #"Weird af_operation semantics, error.. %#", error);
}];
[af_operation start];
}
This request goes through okay. The response data itself is what I'd expect, but it is not any kind of dictionary class.
I'd rather keep to using methods of AFHTTPClient (as opposed to, for example, [AFJSONRequestOperation JSONRequestOperationWithRequest]) so I can use AFHTTPClient's Reachability methods and so forth.
Strangely (to me, at least) if I do the request like this:
NSMutableURLRequest *aj_request = [client requestWithMethod:#"GET" path:path parameters:params];
[self.flickrAuth authorizeRequest:aj_request];
AFJSONRequestOperation *aj_operation =
[AFJSONRequestOperation JSONRequestOperationWithRequest:af_request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
LOG_FLICKR_VERBOSE(0, #"AFJSONRequestOperation %#", JSON);
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
LOG_FLICKR_VERBOSE(0, #"AFJSONREquestOperation Error %#", error);
}];
[aj_operation start];
It fails with a "401" because it was expecting application/json in the response header and instead thinks it's received text/plain
But, if I do the request like this:
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[[NSURL alloc]initWithString:#"http://api.flickr.com/services/rest/?method=flickr.people.getPhotos&format=json&user_id=66854529#N00&nojsoncallback=1"]];
[self.flickrAuth authorizeRequest:request];
AFJSONRequestOperation *operation =
[AFJSONRequestOperation JSONRequestOperationWithRequest:request
success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
LOG_FLICKR_VERBOSE(0, #"Success Flickr =========\n%# %#", JSON, [JSON valueForKeyPath:#"photos.total"]);
/////handler(JSON, nil);
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
LOG_FLICKR(0, #"URL Was %#", url);
LOG_FLICKR(0, #"Failed Flickr ==========\n%# %#", error, JSON);
/////handler(nil, error);
}];
[operation start];
It works fine, including nice JSON, dictionary-formed data.
In the first instance, I'm using AFHTTPClient to produce the NSMutableURLRequest. In the second instance, I'm creating the NSMutableURLRequest on my own. In both cases I'm using AFJSONRequestOperation to dispatch the request leaving the only culprit for the problem to (besides myself..) AFHTTPClient.
In the first example that I can get to work, it's not returning JSON-y data.
In the second example AFHTTPClient seems to create an NSMutableURLRequest that blatantly fails — but (AFAICT) the same URL succeeds when that URL is created "by hand" using [NSMutableURLRequest requestWithURL].
I wonder — what am I missing when using AFHTTPClient?
Help?
In your first code example, it looks like you're doing NSMutableURLRequest *af_request = [client requestWithMethod:#"GET" path:path parameters:params]; and then setting default headers afterwards. Default headers only get applied to requests created after they were specified. Maybe that's where things are going amiss.
Also, that 401 error may be complaining about its content type, but 401 is an error status code, meaning that you're unauthenticated.
I ended up removing all the header parameters to isolate the problem, but it made no difference. Examining the response quite closely gave me a clue. While Flickr does return "JSON" it is not Lint-free, it seems and requires a tweak to one of the parameters. I had been sending jsoncallback=1 but it should be nojsoncallback=1. Once I fixed that parameter AFJSONRequestOperation handles the response correctly and parses the JSON.
My final code looks like this (for others, n.b. the nojsoncallback=1 parameter)
- (IBAction)testFlickrAFJSON:(id)sender
{
// marshall parameters
NSString *urlStr = #"http://api.flickr.com/";
NSURL *url = [NSURL URLWithString:urlStr];
//NSDictionary *params = [[NSDictionary alloc]initWithObjectsAndKeys:#"json", #"format", #"66854529#N00", #"user_id", nil];
NSDictionary *params = [[NSDictionary alloc]initWithObjectsAndKeys:#"json", #"format", #"66854529#N00", #"user_id", #"1", #"nojsoncallback", nil];
NSString *path = [[NSString alloc]initWithFormat:#"services/rest/?method=flickr.people.getPhotos"];
AFHTTPClient *client = [[AFHTTPClient alloc]initWithBaseURL:url];
NSMutableURLRequest *af_request = [client requestWithMethod:#"GET" path:path parameters:params];
[self.flickrAuth authorizeRequest:af_request];
LOG_FLICKR_VERBOSE(0, #"Can Authorize? %#", ([self.flickrAuth canAuthorize] ? #"YES":#"NO"));
AFJSONRequestOperation *af_operation_2 = [AFJSONRequestOperation JSONRequestOperationWithRequest:af_request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
LOG_FLICKR_VERBOSE(0, #"AFJSONRequestOperation Alt %#", JSON);
LOG_FLICKR_VERBOSE(0,#"AFJSONRequestOperation Alt response MIMEType %#",[response MIMEType]);
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
LOG_FLICKR_VERBOSE(0, #"AFJSONREquestOperation Alt Error %#", error);
NSHTTPURLResponse *resp = [[error userInfo] valueForKey:AFNetworkingOperationFailingURLResponseErrorKey];
LOG_FLICKR_VERBOSE(0,#"AFJSONRequestOperation Alt Error response MIMEType %#",[resp MIMEType]);
}];
[af_operation_2 start];
}
I'm sending the following message to an instance of AFHTTPClient. I expect the success block to be sent a Foundation object (a dictionary) but the debugger shows me that JSON is a _NSCFData object. This question on SO states that I need to set the Accept header to 'application/json'. Well, I'm doing that but AFNetworking still is not decoding the JSON in the response body. If I decode the json myself using NSJSONSerialization I get an NSDictionary as I expect. What am I doing wrong?
[client setDefaultHeader:#"Accept" value:#"application/json"];
[client postPath:#"/app/open_connection/"
parameters:params
success:^(AFHTTPRequestOperation *operation, id JSON) {
NSLog(#"successful login! %#", [JSON valueForKeyPath:#"status"]);
}
failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"error opening connection");
NSAlert *alert = [NSAlert alertWithError:error];
[alert runModal];
}
];
Note: I'm programming the server in Python using Django. The content type of the response is 'application/json'
When you're working with AFHTTPClient and a JSON API, you will typically need to set all three of these settings:
httpClient.parameterEncoding = AFJSONParameterEncoding;
[httpClient setDefaultHeader:#"Accept" value:#"application/json"];
[httpClient registerHTTPOperationClass:[AFJSONRequestOperation class]];
Now when you make requests using your client, it will know to parse the response as JSON.
[httpClient postPath:#"/app/open_connection/"
parameters:params
success:^(AFHTTPRequestOperation *operation, id response) {
NSLog(#"JSON! %#", response);
}
failure:^(AFHTTPRequestOperation *operation, NSError *error) {
}];
Here's a trick that I discovered as well. In the NSError object you can parse it and retrieve the error message (if the HTTP response had a JSON error message):
failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSDictionary *JSON =
[NSJSONSerialization JSONObjectWithData: [error.localizedRecoverySuggestion dataUsingEncoding:NSUTF8StringEncoding]
options: NSJSONReadingMutableContainers
error:nil];
failureCallback(JSON[#"message"]);
}
Try this ... I think there maybe something wrong with your client settings.
NSMutableURLRequest *request = [client requestWithMethod:#"POST" path:#"/app/open_connection/" parameters:params];
AFJSONRequestOperation *operation =
[AFJSONRequestOperation JSONRequestOperationWithRequest:request
success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
NSLog(#"successful login! %#", [JSON valueForKeyPath:#"status"]);
}
failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
NSLog(#"error opening connection");
NSAlert *alert = [NSAlert alertWithError:error];
[alert runModal];
}];
[operation start];