URL GET/POST Request objective-c - objective-c

I have to send get or post request to localhost:
<?php
if(#$_GET['option']) {
echo "You said \"{$_GET['option']}\"";
}else if(#$_POST['option']) {
echo "You said \"{$_POST['option']}\"";
}
?>
ive using this code:
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:#"http://localhost/wsh/index.php?option=Hello"]];
NSData *response = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
NSString *get = [[NSString alloc] initWithData:response encoding:NSUTF8StringEncoding];
it works, but one time in code. if ill do it another one time, application has terminate.
Im try to use ASIFormDataRequest:
ASIFormDataRequest *request = [[[ASIFormDataRequest alloc] initWithURL:#"http://localhost/wsh/index.php"] autorelease];
[request setPostValue:#"option" forKey:#"myFormField1"];
[request start];
NSError *error = [request error];
if (!error) {
NSString *response = [request responseString];
NSLog(response);
}else{
NSLog(#"error");
}
it says:
2010-01-07 13:20:34.964 WSH[3351:903] -[NSCFString absoluteURL]: unrecognized selector sent to instance 0x160f8
2010-01-07 13:20:34.966 WSH[3351:903] error
sry for my english

You are using a plain NSString literal where an NSURL object is expected: [...] initWithURL:#"http://localhost/wsh/index.php" [...]
Change this to initWithURL:[NSURL URLWithString:#"http://localhost/wsh/index.php"].

I wonder if also you should switch the value and key for the post values, ie change the line
[request setPostValue:#"option" forKey:#"myFormField1"];
to
[request setPostValue:#"myFormField1" forKey:#"option"];

Related

Posting JSON data to server

I am trying to post and JSON data to server.
My JSON is:
{
“username”:”sample”,
“password” : “password-1”
}
The way I am sending it to server is:
NSError *error;
NSString *data = [NSString stringWithFormat:#"{\"username\":\"%#\",\"password\":\"%#\"}",_textFieldUserName.text,_textFieldPasssword.text];
NSData *postData = [data dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
NSData *jsonData = [NSJSONSerialization JSONObjectWithData:postData options:0 error:&error];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:[NSURL URLWithString:#"My URL"]];
[request setHTTPMethod:#"POST"];
[request setHTTPBody:jsonData];
NSURLResponse *requestResponse;
NSData *requestHandler = [NSURLConnection sendSynchronousRequest:request returningResponse:&requestResponse error:nil];
NSDictionary *responseDictionary = [NSJSONSerialization JSONObjectWithData:requestHandler options:0 error:&error];
NSLog(#"resposne dicionary is %#",responseDictionary);
NSString *requestReply = [[NSString alloc] initWithBytes:[requestHandler bytes] length:[requestHandler length] encoding:NSASCIIStringEncoding];
NSLog(#"requestReply: %#", requestReply);
The JsonData that is created is a valid JSON accepted by the server.
But the app is crashing and the error is:
-[__NSCFDictionary length]: unrecognized selector sent to instance 0x1702654c0
what is wrong that i am doing here?
I always use this method in my apps to perform API calls. This is the post method. It is asynchronous so you can specify a callback to be called when the server answer.
-(void)placePostRequestWithURL:(NSString *)action withData:(NSDictionary *)dataToSend withHandler:(void (^)(NSURLResponse *response, NSData *data, NSError *error))ourBlock {
NSString *urlString = [NSString stringWithFormat:#"%#", action];
NSLog(#"%#", urlString);
NSURL *url = [NSURL URLWithString:urlString];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dataToSend options:0 error:&error];
NSString *jsonString;
if (! jsonData) {
NSLog(#"Got an error: %#", error);
} else {
jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
NSData *requestData = [NSData dataWithBytes:[jsonString UTF8String] length:[jsonString lengthOfBytesUsingEncoding:NSUTF8StringEncoding]];
[request setHTTPMethod:#"POST"];
[request setValue:#"application/json" forHTTPHeaderField:#"Accept"];
[request setValue:#"application/json; charset=UTF-8" forHTTPHeaderField:#"Content-Type"];
[request setValue:[NSString stringWithFormat:#"%lu", (unsigned long)[requestData length]] forHTTPHeaderField:#"Content-Length"];
[request setHTTPBody: requestData];
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:ourBlock];
}
}
You can easily call it:
- (void) login:(NSDictionary *)data
calledBy:(id)calledBy
withSuccess:(SEL)successCallback
andFailure:(SEL)failureCallback{
[self placePostRequestWithURL:#"yourActionUrl"
withData:data
withHandler:^(NSURLResponse *response, NSData *rawData, NSError *error) {
NSString *string = [[NSString alloc] initWithData:rawData
encoding:NSUTF8StringEncoding];
NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)response;
NSInteger code = [httpResponse statusCode];
NSLog(#"%ld", (long)code);
if (!(code >= 200 && code < 300)) {
NSLog(#"ERROR (%ld): %#", (long)code, string);
[calledBy performSelector:failureCallback withObject:string];
} else {
NSLog(#"OK");
NSDictionary *result = [NSDictionary dictionaryWithObjectsAndKeys:
string, #"id",
nil];
[calledBy performSelector:successCallback withObject:result];
}
}];
}
And finally, you invocation:
NSDictionary *dataToSend = [NSDictionary dictionaryWithObjectsAndKeys:
_textFieldUserName.text, #"username",
_textFieldPasssword.text, #"password", nil];
[self login:dataToSend
calledBy:self
withSuccess:#selector(loginDidEnd:)
andFailure:#selector(loginFailure:)];
Don't forget to define your callbacks:
- (void)loginDidEnd:(id)result{
NSLog(#"loginDidEnd:");
// Do your actions
}
- (void)loginFailure:(id)result{
NSLog(#"loginFailure:");
// Do your actions
}
First you create an NSString* that is supposed to contain JSON data. This doesn't work in general if the username and password contain any unusual characters. For example, I make sure that I have a quotation mark in my password to make sure that stupid software crashes.
You turn that string into an NSData* using ASCII encoding. So if my username contains any characters that are not in the ASCII character set, what you get is nonsense.
You then use the parser to turn this into a dictionary or array, but store the result into an NSData. Chances are that the parse fails and you get nil, otherwise you get an NSDictionary* or an NSArray*, but most definitely not an NSData*.
Here's how you do it properly: You create a dictionary, and then turn it into NSData.
NSDictionary* dict = #{ #"username": _textFieldUserName.text,
#"password": _textFieldPasssword.text };
NSError* error;
NSData* data = [NSJSONSerialization dataWithJSONObject:dict options:0 error:&error];
That's it.
try this:
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:#"My URL"];
if (!request) NSLog(#"Error creating the URL Request");
[request setHTTPMethod:#"POST"];
[request setHTTPBody:[data dataUsingEncoding:NSUTF8StringEncoding]];
[request setValue:#"text/json" forHTTPHeaderField:#"Content-Type"];
NSLog(#"will create connection");
// Send a synchronous request
NSURLResponse * response = nil;
NSError * NSURLRequestError = nil;
NSData * responseData = [NSURLConnection sendSynchronousRequest:request
returningResponse:&response
error:&NSURLRequestError];

Recreate JSON data in Objective-C

I'm trying to build an app on the Feedly API. In order to be able to mark categories as read, I need to post some data to the API. I'm having no success, though.
This is what the API needs as input:
{
"lastReadEntryId": "TSxGHgRh4oAiHxRU9TgPrpYvYVBPjipkmUVSHGYCTY0=_1449255d60a:22c3491:9c6d71ab",
"action": "markAsRead",
"categoryIds": [
"user/c805fcbf-3acf-4302-a97e-d82f9d7c897f/category/design",
"user/c805fcbf-3acf-4302-a97e-d82f9d7c897f/category/photography"
],
"type": "categories"
}
And this is my method:
- (void)markCategoryAsRead: (NSString*)feedID{
NSLog(#"Feed ID is: %#", feedID);
NSUserDefaults *standardUserDefaults = [NSUserDefaults standardUserDefaults];
NSString *accessToken = [standardUserDefaults objectForKey:#"AccessToken"];
NSString *feedUrl = [NSURL URLWithString:#"https://sandbox.feedly.com/v3/markers"];
NSError *error = nil;
NSDictionary *tmp = [[NSDictionary alloc] initWithObjectsAndKeys:
#"markAsRead", #"action",
#"categories", #"type",
#[feedID], #"categoryIds",
#"1367539068016", #"asOf",
nil];
NSData *postdata = [NSJSONSerialization dataWithJSONObject:tmp options:0 error:&error];
NSLog(#"Postdata is: %#", postdata);
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:feedUrl];
[request setHTTPMethod:#"POST"];
[request setValue:#"application/json" forHTTPHeaderField:#"Content-type"];
[request addValue:accessToken forHTTPHeaderField:#"Authorization"];
//[NSURLRequest setAllowsAnyHTTPSCertificate:YES forHost:[url host]];
NSError *errror = [[NSError alloc] init];
NSHTTPURLResponse *response = nil;
NSData *urlData=[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&errror];
NSLog(#"Response code: %ld", (long)[response statusCode]);
if ([response statusCode] >= 200 && [response statusCode] < 300)
{
NSLog(#"It's marked as read.");
} else {
if (error) NSLog(#"Error: %#", errror);
NSLog(#"No success marking this as read. %#", response);
}
}
It keeps throwing a 400 error though, saying bad input. What am I doing wrong?
You're not doing anything with postdata after creating it. Attach it to the request.
[request setHTTPBody:postData];
There are a few problems in your code. Here are some I noticed:
You're not using postData.
The dictionary you make in tmp doesn't look like the dictionary you said you wanted to send. Where's lastReadEntryId, for example?
NSString *feedUrl should be NSURL *feedUrl
Stylistically, you should be using the dictionary literal syntax to create your dictionary. This will make it easier to debug.

NSURLConnection and pointer types bug

Here the problem, i'am using a http request, but when i use NSURLConnection to get my xml file and set a NSString *xml variable with that xml file i get a block pointer error if i return it. But if i take NSString *xml and send it to a method it tells me nothing and the xml variable is well set. Also if i return at the end of my method the variable, i get a nil at the parent calling method. How can i fix this because the return of the variable is needed. Thanks for any help, and here is my code :
The error :
incompatible block pointer types sending 'NSString *(^)NSURLResponse *, NSData *, NSError *)'to parameter of type 'void(^)(NSURLResponse *,NSData *, NSError *)'
- (NSString *)restTestRequester: (NSString *)uriRequested serviceUri:(NSString *)sUri parameters:(NSString *)uriParameters technique:(NSString *)requestTechnique {
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
NSString *l_api_key = [prefs stringForKey:#"globalPublicK"];
NSString *l_secret_key = [prefs stringForKey:#"globalSecretK"];
l_uri = [NSString stringWithFormat:#"%#/%#", uriRequested, sUri];
NSMutableURLRequest *theRequest=[NSMutableURLRequest requestWithURL:[NSURL URLWithString:l_uri]
cachePolicy:NSURLRequestReloadIgnoringLocalCacheData
timeoutInterval:60.0];
[theRequest setHTTPMethod:requestTechnique];
[theRequest setValue:#"application/xml" forHTTPHeaderField:#"Accept"];
[theRequest setValue:#"application/x-www-form-unrlencoded" forHTTPHeaderField: #"Content-Type"];
[theRequest setValue:l_api_key forHTTPHeaderField: #"EMApikey"];
[theRequest setValue:[self hmacsha1:l_uri secret:l_secret_key] forHTTPHeaderField: #"EMRequestHash"];
NSURLConnection *theConnection = [[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
if( theConnection )
{
[NSURLConnection sendAsynchronousRequest:theRequest
queue:[NSOperationQueue mainQueue]
incompatible block pointer types error--> completionHandler:^(NSURLResponse *response, NSData *data, NSError *error)
{
here ---->xml = [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]
autorelease];
works--->[self myMethod:xml];
doesn't work---> return(xml);
}
];
}
else
{
NSLog(#"theConnection is NULL");
}
[theConnection release];
equals nil variable returned-->return xml;
}
I think that the problem is in async call, U still don't have anything in xml when U trie to return it, your method returns before sendAsynchronousRequest finishes.
USE:
NSData* data=[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
NSString* xml = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
It will wait until U get the result back.
You have several major problems. For starters, your block executes after your connection finishes. The code after the block executes after the connection STARTS. This means you releasing the connection before it finishes.
Additionally, you are creating NSURLConnection *theConnection, but never using it. When you call -sendAsynchronousRequest:queue:completionHandler: it creates a completely new handler.
The specific error you are getting is because you cannot return a value from the block. The fact that you are trying indicates that you do not have a full grasp of exactly what is happening. There are many good references around the Internet about blocks and asynchronous programming. I suggest you find one.
NSURL *targetURL = [NSURL URLWithString:l_uri];
NSMutableURLRequest *theRequest = [NSMutableURLRequest requestWithURL:targetUrl
cachePolicy:NSURLRequestReloadIgnoringLocalCacheData
timeoutInterval:60.0];
[theRequest setHTTPMethod:requestTechnique];
[theRequest setValue:#"application/xml" forHTTPHeaderField:#"Accept"];
[theRequest setValue:#"application/x-www-form-unrlencoded" forHTTPHeaderField: #"Content-Type"];
[theRequest setValue:l_api_key forHTTPHeaderField: #"EMApikey"];
[theRequest setValue:[self hmacsha1:l_uri secret:l_secret_key] forHTTPHeaderField: #"EMRequestHash"];
[NSURLConnection sendAsynchronousRequest:theRequest
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse *response, NSData *data, NSError *error)
{
// Here the connection is complete and the data is usable.
NSString *xml = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
[self myMethod:xml];
[xml release];
}];
// Here the Connection has only been queued and no data is available.

NSURLConnection closes early on GET

I'm working on a method to centralize my URL connections for sending and receiving JSON data from a server. It works with POST, but not GET. I'm using a Google App Engine server and on my computer it'll handle the POST requests and return proper results (and log appropriately), but I get the following error when I try the request with a GET method:
Error Domain=kCFErrorDomainCFNetwork Code=303 "The operation couldn’t be completed. (kCFErrorDomainCFNetwork error 303.)" UserInfo=0xd57e400 {NSErrorFailingURLKey=http://localhost:8080/api/login, NSErrorFailingURLStringKey=http://localhost:8080/api/login}
In addition, the GAE dev server shows a "broken pipe" error, indicating that the client closed the connection before the server was finished sending all data.
Here's the method:
/* Connects to a given URL and sends JSON data via HTTP request and returns the result of the request as a dict */
- (id) sendRequestToModule:(NSString*) module ofType:(NSString*) type function:(NSString*) func params:(NSDictionary*) params {
NSString *str_params = [NSDictionary dictionaryWithObjectsAndKeys:func, #"function", params, #"params", nil];
NSString *str_url = [NSString stringWithFormat:#"%#%#", lds_url, module];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:str_url]];
NSData *data = [[NSString stringWithFormat:#"action=%#", [str_params JSONString]] dataUsingEncoding:NSUTF8StringEncoding];
[request setHTTPMethod:type];
[request setHTTPBody:data];
[request setValue:[NSString stringWithFormat:#"%d", [data length]] forHTTPHeaderField:#"Content-Length"];
[request setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
NSError *error = nil;
NSURLResponse *response = nil;
NSData *result = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
NSLog(#"Error: %#", error);
NSLog(#"Result: %#", [[NSString alloc] initWithData:result encoding:NSUTF8StringEncoding]);
return [result objectFromJSONData];
}
A sample call would be:
NSDictionary *response = [fetcher sendRequestToModule:#"login" ofType:#"GET" function:#"validate_email" params:dict];
Again, this works with a POST but not a GET. How can I fix this?
In my case i was not calling [request setHTTPMethod: #"POST" ]
I think the root cause is you have an invalid URL.
JSON encoding will include things like '{', '}', '[' and ']'. All of these need to be URL encoded before being added to a URL.
NSString *query = [NSString stringWithFormat:#"?action=%#", [str_params JSONString]];
query = [query stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSURL *URL = [NSURL URLWithString:[NSString stringWithFormat:#"%#%#", str_url, query]];
To directly answer your question:
According to CFNetwork Error Codes Reference the error is kCFErrorHTTPParseFailure. This means the client failed to correctly parse the HTTP response.
The reason why is that a GET doesn't include a body. Why would you want to submit JSON in a GET anyways?
If the target api returns data only you pass it in the url params.
If you want to send data and "get" a response use a post and examine the body on return.
Sample Post:
NSError *error;
NSString *urlString = [[NSString alloc] initWithFormat:#"http://%#:%#/XXXX/MVC Controller Method/%#",self.ServerName, self.Port, sessionId ];
NSURL *url = [NSURL URLWithString:[urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding ]];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setHTTPMethod:#"POST"];
// hydrate the remote object
NSString *returnString = [rdc JSONRepresentation];
NSData *s10 = [returnString dataUsingEncoding:NSUTF8StringEncoding];
[request setHTTPBody:s10];
NSURLResponse *theResponse = [[NSURLResponse alloc] init];
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&theResponse error:&error];
NSString *message = [[NSString alloc] initWithFormat: #"nothing"];
if (error) {
message = [[NSString alloc] initWithFormat:#"Error: %#", error];
} else {
message = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
}
NSLog(#"%#", message);
return message;

JSON for Objective-C returns error "Illegal start of token [r]"

I am attempting to connect to a web page and return a JSON string. This string simply needs to be parsed in JSON and returned into an NSArray that I have waiting for it. The problem is that JSON doesn't always return the results. Sometimes, it works well. Sometimes, it returns (null), citing the error below.
self.accounts = nil; // Clear the NSArray
NSString *post = [NSString stringWithFormat:#"username=%#", username.text];
NSData *postData = [NSData dataWithBytes: [post UTF8String] length: [post length]];
// Submit login data
NSMutableURLRequest *request = [[[NSMutableURLRequest alloc] init] autorelease];
[request setURL:[NSURL URLWithString: #"http://###.#####.###/app/getaccts.php"]];
[request setHTTPMethod: #"POST"];
[request setValue: #"application/x-www-form-urlencoded" forHTTPHeaderField: #"Content-Type"];
[request setHTTPBody: postData];
// Retreive server response
NSURLResponse *response;
NSError *err;
NSData *returnData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&err];
NSString *content = [NSString stringWithUTF8String:[returnData bytes]];
accounts = [[content JSONValue] allValues]; // Parse JSON string into the array
NSLog(#"Array: %#", accounts);
The page I am submitting to returns this:
{"1":"856069060", "2":"856056407"}
JSON logs the following error:
-JSONValue failed. Error is: Illegal start of token [r]
Can I get a little more info ... specifically, I'd like you to check the return value of your sendSynchronousRequest so can you make this change and rerun your test:
NSData *returnData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&err];
if (returnData == nil) {
NSLog(#"ERROR: %#", err);
} else {
NSLog(#"DATA: %#", returnData);
}