Sunday, November 26, 2006

Sending HTTP GET and POST from Cocoa

Ever wanted to send a form to a webpage from within Cocoa. Here's how.

GET forms are the easiest to do. You just tack on your variables to the end of the URL, like this:
http://www.nowhere.com/sendFormHere.php?key1=val1&key2=val2

Then you could use your standard NSURLDownload to fetch the file.
A POST form is pretty much the same thing, except you need to specify that you are sending a POST, and you need to stick your variables into the http body instead of tacking them onto the end of the URL.

Here's how to setup the URL request for a POST:

NSString *post = @"key1=val1&key2=val2";
NSData *postData = [post dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];

NSString *postLength = [NSString stringWithFormat:@"%d", [postData length]];

NSMutableURLRequest *request = [[[NSMutableURLRequest alloc] init] autorelease];
[request setURL:[NSURL URLWithString:@"http://www.nowhere.com/sendFormHere.php"]];
[request setHTTPMethod:@"POST"];
[request setValue:postLength forHTTPHeaderField:@"Content-Length"];
[request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
[request setHTTPBody:postData];

And you can use this to setup your NSURLDownload. Pretty simple huh?

There is one last thing we need to tackle before you can start using this in your finished product. You need to make sure that the strings you use are properly encoded to go into your string. For example, imagine that one of your keys is called "name" and it's value is "Bob & Cindy". You can't have spaces like that in your URL (or inside the post string), so you'd have to escape the spaces like this "Bob%20&%20Cindy". But that's not all...

You would also need to encode the '&' symbol, because it has special meaning. (To seperate one key,value pair from another). And you'd also need to encode any '?' symbols, and any '=' symbols, and so on. But we don't want to have to write a custom method to do all this. Not when apple has already provided such a huge API for use to use. So what can we use to do this for use in 1 or 2 lines of code?

At first glance it looks like NSString's stringByAddingPercentEscapesUsingEncoding: method might work. But if you try it with the "Bob & Cindy" string above you'll find that it only encodes the spaces, and leaves the '&' symbol. But we see from the method's documentation that it uses Core Foundations CFURLCreateStringByAddingPercentEscapes method to do it's dirty work. And we can use this to do ours as well. Here is a method to do what we want:

- (NSString *)urlEncodeValue:(NSString *)str
{
NSString *result = (NSString *) CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (CFStringRef)str, NULL, CFSTR("?=&+"), kCFStringEncodingUTF8);
return [result autorelease];
}

So to use the method you would write something like this:

NSString *post = [NSString stringWithFormat:@"key1=%@&key2=%@",
[self urlEncodeValue:val1]
[self urlEncodeValue:val2]];

 

11 comments:

Ankur Kothari said...

A simple and excellent guide. I was about to write a post on the exact same thing, but it looks like you beat me to it!

I'm glad you included information on how to encode strings for GET and POST as omitting this can cause frustrating errors if you don't know what's going on.

Richard A. Muscat said...

Very good post. I found a 6-page article split in 3 parts on mactech.com about the same subject but this says exactly the same things in 1/6th the length ... and much simpler too.

Thanks for the tips :-)

Jediknil said...

Nice...although it seems like urlEncodeValue: should really be a category method on NSString...like stringByAddingQueryPercentEscapes. (Or leave in the encoding parameter... stringByAddingQueryPercentEscapesUsingEncoding:)

Or pick a nicer, less corresponding name.

Andrew Paul Simmons said...

Thanks that really helps. I am developing an iPhone app and I couldn't find anything on useful on HTTP POST with Objective-C and COCOA. Thanks again. Andrew Paul Simmons

Johannes Fahrenkrug said...

Thanks a lot for the post info, it was just what I needed for my iPhone app.

inZania said...

Excellent, just what I was looking for. Thanks!

Trevor said...

Typos:
"and it's value" --> "and its value"
"do it's dirty work" --> "do its dirty work"

Panoma said...

Thanks a lot! Just needed for my iPhone app.

Infinity said...

Ugh. I know I had this working but now I've been fighting with it all day and it is broken. Could I send you what I have? I am sure it is just something totally basic that I am missing.

MrRubato said...

Thank you! Just what I'm looking for!

richards said...

You rock man, after 3 years...
Many thanx for the post.