Make iPhone to send URLEncoded string instead of JSON - objective-c

I have a Symfony2 server that receives HTTP POSTs from JQuery using:
var myJSON = {key1: "value1", key2: ["value2", "value3"]};
$.post(myURL, {myJSON}, function(json){}, "json");
This works perfect and internally converts the json in a Request object that, once in the Controller, I can get straightforward with $this->getRequest()->get('key1') or get('key2') obtaining some well formed PHP objects with no additional work.
So I have a complete application with JQuery and Symfony2 working this way.
Now I need to develop a mobile client using iPhone SDK and Objective C.
But all examples I am finding to do it send the JSON and convert it to PHP objects once in the server using json_decode. Those examples use this piece of code:
NSArray *myArray = [NSArray arrayWithObjects: #"Value2", #"Value3", nil];
NSDictionary *myDict = [NSDictionary dictionaryWithObjectsAndKeys: #"Value1", #"key1", myArray, #"Value2"];
NSData* requestData = [NSJSONSerialization dataWithJSONObject:myDict options:NSJSONWritingPrettyPrinted error:&error];
NSLog(#"JSON string:%#", [[NSString alloc] initWithData:requestData encoding:NSUTF8StringEncoding]); // To check that the conversion to JSON is indeed being performed perfectly!!
[request setValue:#"application/json" forHTTPHeaderField:#"Accept"];
[request setValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
[request setValue:#"XMLHttpRequest" forHTTPHeaderField:#"X-Requested-With"];
[request setValue:[NSString stringWithFormat:#"%d", [requestData length]] forHTTPHeaderField:#"Content-Length"];
[request setHTTPBody: requestData];
This sends directly the JSON data to the server and the $this->getRequest()->get('key1') returns null. This approach expects to receive that JSON thata in the content body of the HTTP Request and do a PHP json_decode to manage the data.
Ok, I can get it modifying my "API" to check what kind of data is coming and json_decoding if it is JSON or the getRequest thing if it is URLEncode.
But before doing that workaround, isn't there an easy way to get a JQuery parallel conversion getting the linked NSDictionaries and NSArrays to be URLEncoded and sent to the server as application/x-www-form-urlencoded to get the data in the server always in the getRequest()->get('key1') style?

This works perfect and internally converts the json in a Request
object that, once in the Controller, I can get straightforward with
$this->getRequest()->get('key1') or get('key2') obtaining some well
formed PHP objects with no additional work.
Symfony does not internally convert your json in a Request object!
If you want one way for working with data you need to send data with only one type (json or x-www-url-encoded). I wrote you in the previous question that you can encode iOS to send data with x-www-url-encoded but you can also send JSON in jQuery.post and from iOS. And then you must implement only:
$data = json_decode($this->getRequest()->getContent());
To send JSON data in your JS you need next code:
$.ajax({
type: "POST",
url: myURL,
data: JSON.stringify(myJSON),
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function(json){},
});

Related

Objective-C UNIRest has no response to GET Request

I am attempting the use the UNIRest API to run this get request in an iPhone application
https://api.guildwars2.com/v1/guild_details.json?guild_name=The%20Legacy
The code I am running is this
NSDictionary* headers = #{#"accept": #"application/json"};
NSDictionary* parameters = #{#"guild_name": #"The Legacy"};
UNIHTTPJsonResponse* response = [[UNIRest post:^(UNISimpleRequest* request) {
[request setUrl:#"https://api.guildwars2.com/v1/guild_details.json"];
[request setHeaders:headers];
[request setParameters:parameters];
}] asJson];
NSDictionary *guildInformation = response.body.JSONObject;
NSLog(#"response length: %lu", (unsigned long)[guildInformation.allValues count]);
for(NSString *key in [guildInformation allKeys]) {
NSLog(#"key: %# object: %#", key, [guildInformation objectForKey:key]);
}
I had hoped the for loop would display the response. But it seems I get no response at all when you see that the only output is,
response length: 0
I don't know the UNIRest API well enough to fix this and cannot find any good documentation for it. What am I doing wrong?
The problem seems to be that the parameters values are not correctly encoded.
As a fast workaround you can simply pass the entire constructed URL.
UNIHTTPJsonResponse* response = [[UNIRest post:^(UNISimpleRequest* request) {
[request setUrl:#"https://api.guildwars2.com/v1/guild_details.json?guild_name=The%20Legacy"];
[request setHeaders:#{#"accept": #"application/json"}];
}] asJson];
Probably the space in #"The Legacy" doesn't translate to "The%20Legacy", will do a test case before adding issue to https://github.com/Mashape/unirest-obj-c
UPDATE
Only while I was adding a TestCase for spaced values (which do work correctly) I spotted that you where using POST while you should have used GET.
UNIHTTPJsonResponse* response = [[UNIRest get:^(UNISimpleRequest* request) {

AFNetworking Overload a Post Parameter

I am migrating from ASIHTTPRequest to AFNetworking and have run into an issue.
I am trying to hit an API with a request that overloads the post parameter. I was previously using ASIFormDataRequest for this and used this code to update 3 ids at the same time.
// ASIHTTPRequestCode
[request addPostValue:#"value1" forKey:#"id"];
[request addPostValue:#"value2" forKey:#"id"];
[request addPostValue:#"value3" forKey:#"id"];
Since AFNetworking uses an NSDictionary to store key value pairs, it doesn't seem straight forward how to do this. Any ideas?
I can't immediately see a direct way to do this with AFNetworking, but it is possible to do.
If you look at the code for AFHTTPClient requestWithMethod, you'll see this line, which is the one that sets up the request body to contain the parameters:
[request setHTTPBody:[AFQueryStringFromParametersWithEncoding(parameters, self.stringEncoding) dataUsingEncoding:self.stringEncoding]];
Basically you could pass an empty dictionary to requestWithMethod for the parameters, then it returns, call request setHTTPBody yourself, making up the query string yourself in a similar way to the way AFQueryStringFromParametersWithEncoding does it.
You can build the request this way:
NSURL *url = [NSURL URLWithString:#"http://www.mydomain.com/"];
AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:url];
NSDictionary *postValues = [NSDictionary dictionaryWithObject:[NSString stringWithFormat:#"%#,%#,%#",#"value1",#"value2",#"value3"] forKey:#"id"];
NSMutableURLRequest *request = [httpClient requestWithMethod:#"POST" path:#"/path/to/your/page.php" postValues];
I was facing a similar issue but solved it by updating the url. I added the parameters i need to send with the url and set the "parameters to nil"
so the url became something like
server\url.htm?data=param1&data=param2&data=param3
and sent nil as paramDictionary
[request setHTTPBody:[AFQueryStringFromParametersWithEncoding(nil, self.stringEncoding) dataUsingEncoding:self.stringEncoding]];

How to use the token given from google reader api to view unread list in objective c

I am making a Google Reader App and so far I have been able to receive the sid, auth, and use those to get a token from http://www.google.com/reader/api/0/token?client=clientName.
My next step if I am correct is to send a GET request using this token to a url that will return me a list of unread messages.
Problem is I do not know what url to use or how to send this GET request using the ID's i have.
Can someone please show me some code that actually does this correctly in objective c.
Assuming you're using a NSURLRequest in Objective-C you can set a custom header like this:
NSMutableURLRequest* request = [[[NSMutableURLRequest alloc] initWithURL:url]
autorelease];
[request setValue:[NSString stringWithFormat:#"GoogleLogin auth=#%", token]
forHTTPHeaderField:#"Authorization"];
This is assuming you have two strings defined already, the URL and the token.
The URL you want is http://www.google.com/reader/atom/user/-/state/com.google/read
I've written a PHP library to interact with Google Reader's API feel free to dig around there. Specifically line 523 is relevent to this question. The library is up to date with their latest authorization changes.
NSMutableURLRequest* request = [[[NSMutableURLRequest alloc] initWithURL:url]autorelease];
[request setValue:[NSString stringWithFormat:#"GoogleLogin auth=#%", token]
forHTTPHeaderField:#"Authorization"];
[request setHTTPMethod:#"GET"];
responseStr = [[NSString alloc]initWithData:recieveData encoding:NSASCIIStringEncoding];
NSLog(#"message %#", responseStr);

Getting SHOUTcast metadata on the Mac

I'm creating an application in Objective-C and I need to get the metadata from a SHOUTcast stream. I tried this:
NSURL *URL = [NSURL URLWithString:#"http://202.4.100.2:8000/"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL];
[request addValue:#"1" forHTTPHeaderField:#"icy-metadata"];
[request addValue:#"Winamp 5/3" forHTTPHeaderField:#"User-Agent"];
[request addValue:#"audio/mpeg" forHTTPHeaderField:#"Content-Type"];
[NSURLConnection connectionWithRequest:request delegate:self];
I would have to get the headers from this request in order to get the information, right? Unfortunately it keeps returning these headers:
Date = "17 Apr 2010 21:57:14 -0200";
"Max-Age" = 0;
What I'm doing wrong?
I found an answer to this question. Simply append a 7.html at the end of the URL and parse the file.
I.E.
http://38.96.148.138:7534/7.html
Fernando Valente's solution for this problem
http://www.fvalente.org/blog/2012/03/15/shoutcast-metadata-the-easy-way/
It seems that shoutcast does not follow HTTP exchange standards and its response headers and body are not separated by two newlines. NSURLConnection/NSURLResponse are unable to parse out the headers; however, connection:didReceiveResponse: is still fired, just with an empty NSURLResponse. This becomes clear if we take a look at data coming in connection:didReceiveData:. The first chunk received will contain metadata headers.

Generate JSON object with transactionReceipt

I've been the past days trying to test my first in-app purchse iphone application. Unfortunately I can't find the way to talk to iTunes server to verify the transactionReceipt.
Because it's my first try with this technology I chose to verify the receipt directly from the iPhone instead using server support. But after trying to send the POST request with a JSON onbject created using the JSON api from google code, itunes always returns a strange response (instead the "status = 0" string I wait for).
Here's the code that I use to verify the receipt:
- (void)recordTransaction:(SKPaymentTransaction *)transaction {
NSString *receiptStr = [[NSString alloc] initWithData:transaction.transactionReceipt encoding:NSUTF8StringEncoding];
NSDictionary *jsonDictionary = [NSDictionary dictionaryWithObjectsAndKeys:#"algo mas",#"receipt-data",nil];
NSString *jsonString = [jsonDictionary JSONRepresentation];
NSLog(#"string to send: %#",jsonString);
NSLog(#"JSON Created");
urlData = [[NSMutableData data] retain];
//NSURL *sandboxStoreURL = [[NSURL alloc] initWithString:#"https://sandbox.itunes.apple.com/verifyReceipt"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:#"https://sandbox.itunes.apple.com/verifyReceipt"]];
[request setHTTPMethod:#"POST"];
[request setHTTPBody:[jsonString dataUsingEncoding:NSUTF8StringEncoding]];
NSLog(#"will create connection");
[[NSURLConnection alloc] initWithRequest:request delegate:self];
}
maybe I'm forgetting something in the request's headers but I think that the problem is in the method I use to create the JSON object.
HEre's how the JSON object looks like before I add it to the HTTPBody :
string to send: {"receipt-data":"{\n\t\"signature\" = \"AUYMbhY
...........
D0gIjEuMCI7Cn0=\";\n\t\"pod\" = \"100\";\n\t\"signing-status\" = \"0\";\n}"}
The responses I've got:
complete response {
exception = "java.lang.IllegalArgumentException: Property list parsing failed while attempting to read unquoted string. No allowable characters were found. At line number: 1, column: 0.";
status = 21002;
}
Thanks a lot for your guidance.
I have just fixed that after 2 days of struggling. You have to encode receipt using Base64 before inserting into json object. Like that (Ruby):
dataForVerification = {"receipt-data" => Base64.encode64(receipt)}.to_json
Base64 is not mentioned anywhere in the official docs (at least for SDK 3.0), only on a couple of blogs.
For instance, here the guy encodes the receipt in Base64 before passing it to the PHP server, but does not decode it back in PHP, thus sending Base64-encoded string to iTunes.
Re: "21002: java.lang.IllegalArgumentException: propertyListFromString parsed an object, but there's still more text in the string.:"
I fixed a similar issue in my code by wrapping the receipt data in {} before encoding.
The resulting receipt looks like:
{
"signature" = "A[...]OSzQ==";
"purchase-info" = "ew[...]fQ==";
"pod" = "100";
"signing-status" = "0";
}
Here's the code I use:
receipt = "{%s}" % receipt // This step was not specified - trial and error
encoded = base64.b64encode(receipt)
fullpost = '{ "receipt-data" : "%s" }' % encoded
req = urllib2.Request(url, fullpost)
response = urllib2.urlopen(req)
Apple's Response:
{"receipt":{"item_id":"371235", "original_transaction_id":"1012307", "bvrs":"1.0", "product_id":"com.foo.cup", "purchase_date":"2010-05-25 21:05:36 Etc/GMT", "quantity":"1", "bid":"com.foo.messenger", "original_purchase_date":"2010-05-25 21:05:36 Etc/GMT", "transaction_id":"11237"}, "status":0}
Good luck!