How to send POST XML from iOS app? - iphone

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"];

Related

How do I post images to reddit in iOS / Objective C?

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.

AFNetworking JSON request with a boolean

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!

Error code -1011 when I use AFNetWorking

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).

Having problems with uploading photos to TwitPic using OAuth in Objective C on the iPhone

I have been working on an iPhone app that has a feature of uploading photos to TwitPic. I have it working with basic authentication.
I am trying to get it working with OAuth. I am getting authentication errors. I have studied very carefully the TwitPic documentation.
I am authorising the app by displaying a UI Web View and the it returns a PIN value. I enter the PIN value in the app and request the token.
I am able to upload status updates to Twitter but not photos.
My code is based on some example code from here:
Example iPhone app using OAuth
Here is my code:
NSString *url = #"http://api.twitpic.com/2/upload.json";
NSString *oauth_header = [oAuth oAuthHeaderForMethod:#"POST" andUrl:url andParams:nil];
NSLog(#"OAuth header : %#\n\n", oauth_header);
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:[NSURL URLWithString:url]];
[request addRequestHeader:#"User-Agent" value:#"ASIHTTPRequest"];
request.requestMethod = #"POST";
[request addRequestHeader:#"X-Auth-Service-Provider" value:#"https://api.twitter.com/1/account/verify_credentials.json"];
[request addRequestHeader:#"X-Verify-Credentials-Authorization" value:oauth_header];
NSData *imageRepresentation = UIImageJPEGRepresentation(imageToUpload, 0.8);
[request setData:imageRepresentation forKey:#"media"];
[request setPostValue:#"Some Message" forKey:#"message"];
[request setPostValue:TWITPIC_API_KEY forKey:#"key"];
[request setDelegate:self];
[request setDidFinishSelector:#selector(requestDone:)];
[request setDidFailSelector:#selector(requestFailed:)];
[request start];
Here is the OAuth Header:
OAuth realm="http://api.twitter.com/", oauth_timestamp="1275492425", oauth_nonce="b686f20a18ba6763ac52b689b2ac0c421a9e4013", oauth_signature_method="HMAC-SHA1", oauth_consumer_key="zNbW3Xi3MuS7i9cpz6fw", oauth_version="1.0", oauth_token="147275699-jmrjpwk3B6mO2FX2BCc9Ci9CRBbBKYW1bOni2MYs", oauth_signature="d17HImz6VgygZgbcp845CD2qNnI%3D"
HA! I found it!
We should create the header with https://api.twitter.com/1/account/verify_credentials.json and post to http://api.twitpic.com/2/upload.json! (And use GET)
NSString *fakeurl = #"https://api.twitter.com/1/account/verify_credentials.json";
NSString *oauth_header = [oAuth oAuthHeaderForMethod:#"GET" andUrl:fakeurl andParams:nil];
NSLog(#"OAuth header : %#\n\n", oauth_header);
NSString *url = #"http://api.twitpic.com/2/upload.json";
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:[NSURL URLWithString:url]];
request.delegate = self;
[request addRequestHeader:#"User-Agent" value:#"ASIHTTPRequest"];
request.requestMethod = #"GET";
[request addRequestHeader:#"X-Verify-Credentials-Authorization" value:oauth_header];
[request addRequestHeader:#"X-Auth-Service-Provider" value:#"https://api.twitter.com/1/account/verify_credentials.json"];
NSData *imageRepresentation = UIImageJPEGRepresentation([UIImage imageNamed:#"IMG_0717.jpg"], 0.2);
if (imageRepresentation) {
NSLog(#"Pic not nil");
}
[request setData:imageRepresentation forKey:#"media"];
[request setPostValue:#"twitpic, i hate you. die painfully." forKey:#"message"];
[request setPostValue:twitPicKey forKey:#"key"];
[request setDelegate:self];
[request setDidFinishSelector:#selector(requestDone:)];
[request setDidFailSelector:#selector(requestFailed:)];
[request start];
Use GSTwitPicEngine: https://github.com/Gurpartap/GSTwitPicEngine
Using GSTwitPicEngine:
Initialize the engine with class or as needed:
self.twitpicEngine = (GSTwitPicEngine *)[GSTwitPicEngine twitpicEngineWithDelegate:self];
Find the authorization token and supply to twitpicEngine with:
[twitpicEngine setAccessToken:token];
Then to upload image and attach a text message along with it (does not post to twitter):
[twitpicEngine uploadPicture:[UIImage imageNamed:#"mypic.png"] withMessage:#"Hello world!"]; // This message is supplied back in success delegate call in request's userInfo.
To upload image only:
[twitpicEngine uploadPicture:uploadImageView.image];
Upon end of request, one of the delegate methods is called with appropriate data and information.
GSTwitPicEngineDelegate protocol specifies two delegate methods:
- (void)twitpicDidFinishUpload:(NSDictionary *)response {
NSLog(#"TwitPic finished uploading: %#", response);
// [response objectForKey:#"parsedResponse"] gives an NSDictionary of the response one of the parsing libraries was available.
// Otherwise, use [[response objectForKey:#"request"] objectForKey:#"responseString"] to parse yourself.
if ([[[response objectForKey:#"request"] userInfo] objectForKey:#"message"] > 0 && [[response objectForKey:#"parsedResponse"] count] > 0) {
// Uncomment to update status upon successful upload, using MGTwitterEngine's instance.
// [twitterEngine sendUpdate:[NSString stringWithFormat:#"%# %#", [[[response objectForKey:#"request"] userInfo] objectForKey:#"message"], [[response objectForKey:#"parsedResponse"] objectForKey:#"url"]]];
}
}
and
- (void)twitpicDidFailUpload:(NSDictionary *)error {
NSLog(#"TwitPic failed to upload: %#", error);
if ([[error objectForKey:#"request"] responseStatusCode] == 401) {
// UIAlertViewQuick(#"Authentication failed", [error objectForKey:#"errorDescription"], #"OK");
}
}
All set?
OAuth method to generate a header must be GET. Not POST.
Also url must be https://api.twitter.com/1/account/verify_credentials.json
Thanks, this helped me get it working too :) I also updated http://github.com/jaanus/PlainOAuth with working example code.

Parsing Data returned from Twitpic API

I just wanted to ask you if anyone can help me parsing the returned data from the Twitpic API?
I'm creating a HTTPFormRequest using the ASIHTTPRequest Wrapper for Cocoa. This all happens in an iPhone application:
NSURL *url = [NSURL URLWithString:#"http://twitpic.com/api/upload"];
NSString *username = t_user;
NSString *password = t_pass;
NSData *twitpicImage = UIImagePNGRepresentation(imageView.image);
// Now, set up the post data:
ASIFormDataRequest *request = [[[ASIFormDataRequest alloc] initWithURL:url] autorelease];
[request setPostValue:twitpicImage forKey:#"media"];
[request setPostValue:username forKey:#"username"];
[request setPostValue:password forKey:#"password"];
[request setData:twitpicImage forKey:#"media"];
// Initiate the WebService request
[request start];
if ([request error]) {
NSLog(#"%#", [request error]);
} else if ([request responseString]) {
NSLog(#"%#", [request responseString]);
}}
Now comes the hard part, I don't know how to parse the data that is in [request responseString]. I know I need to use NSXMLParser, but I dunno how to use it. All I need is to get the url of the image.
Thx in advance.
Feel free to have a look at my little XML parse classes here http://www.memention.com/blog/2009/10/31/The-XML-Runner.html
I have started to use them for parsing the response from image upload to yfrog.com
Basically I do like this...
In NameValueParser.m I changed the entry tag to rsp like this
entryName = [[NSString stringWithString:#"rsp"] retain];
then where the response has been received I parse it like this
NameValueParser *parser = [NameValueParser parser];
[parser addFieldName:#"statusid"];
[parser addFieldName:#"userid"];
[parser addFieldName:#"mediaid"];
[parser addFieldName:#"mediaurl"];
[parser addFieldName:#"err"];
[parser parseData:responseData]; // the response received by ASIHTTPRequest
NSArray *rspArray = [parser list];
NSLog(#"%#", rspArray); // Have a look at it here
Try it as written at the bottom of this tutorial click here using NSScanner. They are showing exactly what you need, retrieving only the mediaurl = URL of uploaded image.
NSScanner *scanner = [NSScanner scannerWithString:responseString]; ...
GSTwitPicEngine does XML and JSON parsing both: http://github.com/Gurpartap/GSTwitPicEngine
Though, why not use JSON format for the Twitpic API responses? It's easy to parse and deal with using yajl, TouchJSON, json-framework or other Cocoa JSON libraries