I'm trying to send a JSON request using AFNetworking and have a problem with making values be translated to the json form of {"value": true}. Instead, I'm getting: {"value": 1}
Here's basically how I'm creating the request:
NSMutableURLRequest *request =
[self.httpClient requestWithMethod:#"POST"
path:url
parameters:#{#"value": #YES}];
AFJSONRequestOperation *operation =
[AFJSONRequestOperation JSONRequestOperationWithRequest:request ...];
[operation start];
Am I missing something trivial here? :)
Short answer:
Make sure you are running a recent version of AFNetworking. That's all I can see as the problem based on the code you've provided.
Long answer:
I've tried reproducing the issue you're describing with the most recent versions of AFNetworking and I could not. I dug into AFNetworking to see how the encoding of JSON is done. AFHTTPClient.m:442 uses NSJSONSerialization to encode JSON requests. I came up with the following code to test the issue:
NSError* error = nil;
NSData* jsonData = [NSJSONSerialization dataWithJSONObject:#{#"value" : #YES} options:0 error:&error];
NSLog(#"Resulting JSON:\n\n%#\n", [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]);
outputs:
{"value":true}
So #YES should do it. As a note, be sure not to use #(YES) in your code as it will output as a 1 instead of true.
NSError* error = nil;
NSData* jsonData = [NSJSONSerialization dataWithJSONObject:#{#"value" : #(YES)} options:0 error:&error];
NSLog(#"JSON:%#", [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]);
outputs:
{"value":1}
With that I went through and tried to figure out how AFHTTPClient need to be configured to send out a bool as 1/0 instead of true/false and could not find any. Here's my networking code.
AFHTTPClient* httpClient = [[AFHTTPClient alloc] initWithBaseURL:[NSURL URLWithString:#"http://<SERVER HERE>"]];
[httpClient setParameterEncoding:AFJSONParameterEncoding];
NSMutableURLRequest *jsonRequest = [httpClient requestWithMethod:#"POST" path:#"/" parameters:#{#"value": #YES}];
AFHTTPRequestOperation *jsonOperation = [AFJSONRequestOperation JSONRequestOperationWithRequest:jsonRequest success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
NSLog(#"Success");
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
NSLog(#"Failure");
}];
[jsonOperation start];
Since #YES is an NSNumber, NSJSONSerialization turns this to 0/1.
I don't think there's a way other than #{#"value": (yesOrNo ? #"true" : #"false")} or using a different serialization class.
For people who might be running into this issue, there's another reason why it might be happening.
Make sure you set the parameterEncoding property of your AFHTTPClient subclass to AFJSONParameterEncoding, otherwise you'll run into the issue of NSNumber's initialization value not being correctly detected, and will see 0s and 1s being output instead by the encoder.
See this for reference as well.
Hope this helps.
In the subclass of HTTPClient. Instead of:
self.responseSerializer = [AFJSONResponseSerializer serializer];
try with:
$self.responseSerializer = [AFJSONResponseSerializer serializerWithReadingOptions:NSJSONReadingAllowFragments];
I have the same error, I am sending the #YES but the services give me fail, so I create and string of a json and create an jsonObject like this:
NSString* paramsString = #"{";
NSString* appending = [NSString stringWithFormat:#"\"%#\":%#,", KEY_CHECKED, (checked ? #"true" : #"false")];
paramsString = [paramsString stringByAppendingString: appending];
paramsString = [paramsString stringByAppendingString:#"}"];
id object = [NSJSONSerialization JSONObjectWithData:[paramsString dataUsingEncoding:NSUTF8StringEncoding] options:0 error:nil];
Use this object for send the post with AFNetworking
[self postParameters:object];
for me works!
Related
I work with Core data and I want to call a function for returning an object. This object is completed in this function with AFNetworking into a completion block. I want to know if it's possible to return this object into this completion block... for use it later. Failed code here, because newMember in completion block is not allowed and not working.
This error appears :
Incompatible block pointer types sending 'Member *(^)(NSURLRequest...'
+(Member *)returnMemberModelWithId:(NSString *)myid withContext:(NSManagedObjectContext *)managedObjectContext{
__block NSMutableArray *dicoNe =[[NSMutableArray alloc] init];
__block Member *newMember = [NSEntityDescription
insertNewObjectForEntityForName:#"Member"
inManagedObjectContext:managedObjectContext];
NSString *s= #".json";
NSString *str = [NSString stringWithFormat: #"%#%#", myid, s];
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:#"http://epnet.fr/"]];
AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:url];
[httpClient setParameterEncoding:AFFormURLParameterEncoding];
NSString *path = [NSString stringWithFormat:#"members/%#", str];
NSMutableURLRequest *request = [httpClient requestWithMethod:#"GET" path:path parameters:nil];
AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *innerRequest, NSHTTPURLResponse *response, id reponseJSON) {
dicoNe = reponseJSON;
NSNumber *v = [dicoNe valueForKey:#"id"];
newMember.idMember = v; //And others assignments ..
return newMember; // It's not working
} failure:^(NSURLRequest *innerRequest, NSHTTPURLResponse *response, NSError *error, id reponseJSON) {
NSLog(#"Fail %#", reponseJSON);
}];
[operation start];
return newMember;
}
So , my object newMember which I try to return is null at the end. So my question is, how can I return my object completed by AFN with this function? Many thanks
What you are effectively asking is "How do I make this asynchronous function synchronous?"
The answer is that you don't. Or, you shouldn't.
What you should do is make that method return (void) (or BOOL + an NSError**) and then make whatever call is necessary to process the result of the query from your completion block.
There are a number of issues with that code. The initial [[NSMutableArray alloc] init]; is pointless given that the first thing you do in the completion block is dicoNe = responseJSON;. There is no need to use stringWithFormat: with a static string in this expression: [NSString stringWithFormat:#"http://epnet.fr/"].
Calling valueForKey: on an array will return an array. Something is afoul with the way you are handling that information (is responseJSON really an array?!).
I am trying to post an image to reddit; however, I only kind of know what I am doing. I am using objective c for my iphone app.
Prior to the code listed below I obtain a modhash and cookie by logging in prior to the upload and use NSLog to determine that I truly am receiving them. Then I use a JSON Parser to separate them into separate variables.
I was not sure what all of the POST argument values were supposed to be so I kind of guessed. The necessary arguments are uh, file, formid, header, ing_type, name, and sponsor.
The documentation for reddit api is http://www.reddit.com/dev/api I believe that I want to use the POST /api/upload_sr_img method...
NSURL *url = [NSURL URLWithString:#"http://www.reddit.com/api/upload_sr_img"];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
[request setHTTPMethod:#"POST"];
NSString *httpBody = [NSString stringWithFormat:#"?uh=%#&file=%#&formid=''header=%#&img_type=%#&name=%#&sponsor=%#",modhash,UIImagePNGRepresentation(self.memeImage.image),#"test",#"png",#"Drew",#"Drew'sApp"];
[request setHTTPBody:[httpBody dataUsingEncoding:NSASCIIStringEncoding]];
NSURLResponse *response = NULL;
NSError *imgError = NULL;
NSData *result = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&imgError];
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:result options:NSJSONReadingMutableContainers error:nil];
NSDictionary *responseJson = [json valueForKey:#"json"];
NSLog(#"response is: %#",response);
NSLog(#"imgError is: %#",imgError);
NSLog(#"result is: %#",result);
NSLog(#"json is: %#",json);
NSLog(#"responseJson is: %#",responseJson);
Could use any help I can get.
Also, I was not sure if I needed to send a content-type or even what it would be.
Thanks for your help.
Check this library: https://github.com/MattFoley/MFRedditPostController
You can use the provided UI or create your own.
I created an NSDictionary containing arrays and strings and other client info, using setObject forKey. Everything looks great when I NSLog the data, format is exactly the way its supposed be. I've also converted my NSDictionary to NSData:
NSData *userData = [NSJSONSerialization dataWithJSONObject:userDict options:NSJSONWritingPrettyPrinted error:&error];
What I need to know is how to upload it to the server using POST. I've found the following code snippet to upload a photo. My question is can I simply use my NSDictionary as a parameter (params in request), it's kinda big. If not, how do I send my NSData object userData? I really love AFNetworking and have been using it exclusively for all my download needs. This is my first time uploading an object.
Thanks
NSData *imageData = UIImagePNGRepresentation(pageImage);
AFHTTPClient *client= [AFHTTPClient clientWithBaseURL:[NSURL URLWithString:#"http://www.SERVER.com"]];
//You can add POST parameteres here
NSDictionary *params = [NSDictionary dictionaryWithObjectsAndKeys:
author, #"author",
title, #"title",
nil];
NSMutableURLRequest *request = [client multipartFormRequestWithMethod:#"POST" path:#"/PATH/TO/WEBSERVICE.php" parameters:params constructingBodyWithBlock: ^(id <AFMultipartFormData>formData) {
//This is the image
[formData appendPartWithFileData: imageData name:#"cover_image" fileName:#"temp.png" mimeType:#"image/png"];
}];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
//Setup Upload block to return progress of file upload
[operation setUploadProgressBlock:^(NSInteger bytesWritten, long long totalBytesWritten, long long totalBytesExpectedToWrite) {
float progress = totalBytesWritten / (float)totalBytesExpectedToWrite;
NSLog(#"Upload Percentage: %f %%", progress*100);
}];
//Setup Completeion block to return successful or failure
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSString *response = [operation responseString];
NSLog(#"response: [%#]",response);
//Code to run after webservice returns success response code
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"error: %#", [operation error]);
//Code to Run if Failed
}];
[operation start];
I am not sure I fully understand you question, but I will give it a try anyway.
My question is can I simply use my NSDictionary as a parameter (params in request), it's kinda big.
I think so. Just give it a try... in the end, those array will be converted in data sent to the server, so if the server is able to handle it, there should be no problem.
If not, how do I send my NSData object userData?
The data you send should be provided where the code you posted specifies imageData. Keep in mind that if what you are uploading is not meant to be a file (you mention NSData), then you might need to use appendPartWithFormData:name. This, again, depends on your server side.
Hope this clarifies things a bit.
So, I've ran over and over the web in search for anything about sending XML with POST from iPhone app - no luck so far, none!
I'm using in my app KissXML, which I find very easy and useful when it comes to getting XML out of response - but quite opposite when sending XML to server...
Here is my method for connecting and receiving XML. I tried to put NSString containing simply my XML request into body of POST request, but it doesn't work as planned.
-(void)prepareTransaction{
NSLog(#"FXSecondVC: preparing transaction...");
NSString *login = [[NSUserDefaults standardUserDefaults] stringForKey:#"kUsername"];
NSString *password = [[NSUserDefaults standardUserDefaults] stringForKey:#"kPassword"];
NSString *host = [[NSUserDefaults standardUserDefaults] stringForKey:#"kURLServer"];
NSURL *url = [[NSURL alloc] initWithString:host];
AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:url];
[httpClient setAuthorizationHeaderWithUsername:login password:password];
[httpClient registerHTTPOperationClass:[AFKissXMLRequestOperation class]];
NSString *xmlString = #"<RootEl xmlns=\"http://some.url/goes/here\">"
"<Element1>12678967.543233</Element1>"
"<Element2>"
"<string xmlns=\"bla.bla/url\">"
"String content</string>"
"<string xmlns=\"bla.bla/url\">"
"String content</string>"
"</Element2>"
"<Element3>true</Element3>"
"<Element4>String content</Element4>"
"<Element5>1999-05-31T11:20:00</Element5>"
"<Element6>true</Element6>"
"</RootEl>";
NSMutableURLRequest *request = [httpClient requestWithMethod:#"POST" path:kServerRequestURL parameters:nil];
[request setHTTPBody:[xmlString dataUsingEncoding:NSUTF8StringEncoding]];
AFKissXMLRequestOperation *operation = [AFKissXMLRequestOperation XMLDocumentRequestOperationWithRequest:request success:^(NSURLRequest *req, NSHTTPURLResponse *resp, DDXMLDocument *XMLDocument){
NSLog(#"[SUCCESS]: XMLDocument: %#", XMLDocument);
}failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, DDXMLDocument *XMLDocument) {
NSLog(#"error parsing: %#", [error localizedDescription]);
}];
[operation start];
}
This is what I'm getting in response:
2012-11-21 19:40:09.884 FXApp[19662:707] FXSecondVC: preparing transaction...
2012-11-21 19:40:10.011 FXApp[19662:707] error parsing: Expected status code in (200-299), got 400
Am I missing something here? I want to use KissXML, because it the simplest way (at least known to me) to use already prepared XML document in successful response, but if solution requires changing framework - don't hesitate. The priority is to get it working.
I hit dead end - this is driving me crazy, especially it is really urgent matter.
Mystery solved:
it appears that all I had to do was to set Content-Type for xml - which I wasn't doing. Solution found here
Here you go:
[request setValue:#"application/xml; charset=utf-8" forHTTPHeaderField:#"Content-Type"];
In my case, I had to use setValue:#"text/xml" to get the desired JSON response from the server (PHP server).
i.e. I used the following:
[request addValue:#"text/xml" forHTTPHeaderField:#"Content-Type"];
I am doing a service in our customer company. And I try to get some information from their server by AFNetWorking (Our customer encourage to use AFNetWorking)
I did some sample using AFNetWorking, and it's work.
But when I use one of our customer URLs to get JSON data, it failed and this is error description:
Error Domain=com.alamofire.networking.error Code=-1011
"Expected status code <NSIndexSet: 0x7e274f0>[number of indexes: 100 (in 1 ranges),
indexes: (200-299)], got 403" UserInfo=0x7b64040 {NSErrorFailingURLKey=<url_hidden_for_stackoverflow>,
NSLocalizedDescription=Expected status code <NSIndexSet: 0x7e274f0>[number of indexes: 100 (in 1 ranges), indexes: (200-299)], got 403}
I try to find out some solution, but I can't fix yet. There's my code:
NSURL *url = [NSURL URLWithString:#"http://example.com/"];
AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:url];
//[httpClient setDefaultHeader:#"Accept" value:#"text/json"];
//NSDictionary *params = [NSDictionary dictionaryWithObjectsAndKeys:CONST_KEY_REGISTER_UNIQUE_KEY, CONST_API_KEY_TEXT,nil];
NSMutableURLRequest *request = [httpClient requestWithMethod:#"POST" path:#"path/to/page.json" parameters:nil];
[httpClient release];
AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
NSString *status = [JSON valueForKey:#"status"];
if ([status isEqualToString:#"OK"]) {
NSString *uniqueId = [JSON valueForKey:#"uniqueId"];
[UserSettings setWithKey:CONST_PROGRAM_UNIQUE_KEY value:uniqueId];
}
//NSString *message = [json valueForKey:#"message"];
//NSString *error = [json valueForKey:#"error"];
[[LoadingView instance] performSelectorOnMainThread:#selector(removeLoadingView) withObject:nil waitUntilDone:YES];
}
failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error) {
NSString *errorString = [error description];
[[LoadingView instance] performSelectorOnMainThread:#selector(removeLoadingView) withObject:nil waitUntilDone:YES];
}];
NSOperationQueue *queue = [[[NSOperationQueue alloc] init] autorelease];
[queue addOperation:operation];
Thanks for reading, and any help or reply will be greatly appreciated.
EDIT: As DarkDust said: server deny my access. But I can get data from server by basic connection:
Here is code to get:
NSURL *url = [NSURL URLWithString:#"http://example.com/path/to/page.json"];
NSMutableURLRequest *theRequest = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData timeoutInterval:CONST_CONNECTION_TIMEOUT];
rssConnection = [[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
[self performSelectorOnMainThread:#selector(downloadStarted) withObject:nil waitUntilDone:NO];
if (rssConnection != nil) {
do {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
} while (!done);
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
// I can get text here, but it is not JSON format
NSString *content = [NSString stringWithUTF8String:[data bytes]];
}
I wonder why rssConnection can get JSON text and AFHTTPClient can not ?
As reference because of high search result via google...
For others that are looking for the possible error codes retrieved via AFNetworking, consult the apple documentation for URL Loading System Error Codes as these are the same.
NSURLErrorBadServerResponse = -1011
Returned when the URL Loading system receives bad data from the server.
This is equivalent to the “500 Server Error” message sent by HTTP servers.
The server is responding with the HTTP error code 403 which means Forbidden. It denies you access. You need to find out why, for example by reading the server logs (if you can) or asking the server administrator to help you. It might be access restrictions on the server that need to be lifted/modified.
Edit: A HTTP POST is an operation that wants to save something on the server. While the normal GET seems to work just fine according to your edited question, saving is prohibited right now. First thing to do is still examine the server configuration. Additionally, if your URL points to a script (JSP, ASP, whatever) which is the only thing that would make sense in your case you need to examine that to determine why it denies you access (if the server configuration doesn't already deny it, it must be the script).