I have a quick question.
I want the user to enter his username (email) and password and I want to get an access token from the bit.ly api.
I tried so far:
NSString *authStr = [NSString stringWithFormat:#"%#:%#", #"username", #"password"];
NSData *authData = [authStr dataUsingEncoding:NSUTF8StringEncoding];
NSString *authValue = [NSString stringWithFormat:#"Basic %#", [authData base64Encoding]];
[request setValue:authValue forHTTPHeaderField:#"Authorization"];
However this does not work.
What I need is to get this command of curl to run in objective c:
curl -u "username:password" -X POST "https://api-ssl.bitly.com/oauth/access_token"
I know I can set the method to POST but I am not sure how to set username:password :|
I also tried using
curl -u "CLIENT_ID:CLIENT_SECRET" -d "grant_type=password" -d "username=USERNAME" \
-d "password=PASSWORD" https://api-ssl.bitly.com/oauth/access_token
however I still do not know how ti set the input of client id and client secret.
Any help on how I can set those information into the request would help me much!
Jack
Admittedly, things like AFNetworking do make working with NSURLConnection and the like a bit easier, but if you're doing this from scratch, you're close.
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:#"https://api-ssl.bitly.com/oauth/access_token"]];
The endpoint for Resource Owner Credential Grants. That will get you the access_token you need to access the rest of our API.
The trickiest part of the flow is the "Authorization" header
NSString *authString = [NSString stringWithFormat:#"%#:%#", #"<YOUR CLIENT ID>", #"<YOUR CLIENT SECRET>"];
NSData *authData = [authString dataUsingEncoding:NSUTF8StringEncoding];
NSString *base64 = [authData base64EncodedStringWithOptions:0];
NSString *authHeader = [NSString stringWithFormat:#"Basic %#", base64];
[request setValue:authHeader forHTTPHeaderField:#"Authorization"];
This will set the Authorization field to: Basic clientID:clientSecret correctly base 64'ed
From there you need to set the body to the request
NSString *postBody = [NSString stringWithFormat:#"grant_type=password&username=%#&password=%#", #"<USERNAME>", #"<PASSWORD>"];
[request setHTTPBody:[postBody dataUsingEncoding:NSUTF8StringEncoding]];
Tell the request it's POST
[request setHTTPMethod:#"POST"];
Then open a NSURLConnection and observe the 3 important delegated methods
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
[connection start];
You will want to implement:
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData*)data
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
Source: I write the Bitly for iPhone app. Hope this helps. Let me know if you have any questions about the API, or the example above.
Related
I am trying to execute the following CURL command in a Mac app in Objective-C:
curl -u [USERNAME]:[PASSWORD] -X POST --limit-rate 40000 --header "Content-Type: audio/wav” --header "Transfer-Encoding: chunked" --data-binary #/Users/name/Desktop/test.wav "https://stream.watsonplatform.net/speech-to-text/api/v1/recognize?continuous=true"
I am unsure how to set the various CURL arguments in an NSURLSession. I think I set the HTTP headers correctly, but I don't know how to set the u, limit-rate, and data-binary arguments. This is what I have so far:
NSString* credentials = #"[USERNAME]:[PASSWORD]";
NSString* audioPath = #"#/Users/name/Desktop/test.wav";
NSString* fullPath = #"https://stream.watsonplatform.net/speech-to-text/api/v1/recognize?continuous=true";
NSURL* fullURL = [NSURL URLWithString: fullPath];
NSURLSessionConfiguration* sessionConfig = [NSURLSessionConfiguration
defaultSessionConfiguration];
[sessionConfig setHTTPAdditionalHeaders: #{#"Content-Type" : #"audio/wav",
#"Transfer-Encoding": #"chunked"}];
NSMutableData* body = [[NSMutableData alloc] init];
[body appendData: [[NSString stringWithFormat: #"u: %#", credentials]
dataUsingEncoding: NSUTF8StringEncoding]];
[body appendData: [#"limit-rate: 40000" dataUsingEncoding: NSUTF8StringEncoding]];
[body appendData: [[NSString stringWithFormat: #"data-binary: %#", audioPath]
dataUsingEncoding: NSUTF8StringEncoding]];
NSURLSession* urlSession = [NSURLSession sessionWithConfiguration: sessionConfig];
NSMutableURLRequest* urlRequest = [NSMutableURLRequest requestWithURL: fullURL];
[urlRequest setHTTPBody: body];
[urlRequest setHTTPMethod: #"POST"];
NSURLSessionDataTask* dataTask = [urlSession dataTaskWithRequest: urlRequest
completionHandler: ^(NSData* data,
NSURLResponse* response,
NSError* error) {
if (nil == error)
{
if (0 != [data length])
{
// Do something with the returned JSON
}
else
NSLog(#"Data Error: Data is nil or data length is 0.");
}
else
NSLog(#"%#", error);
}];
[dataTask resume];
The error I am getting when I run this code is:
Error Domain=NSCocoaErrorDomain Code=3840 "JSON text did not start with array or object and option to allow fragments not set." UserInfo={NSDebugDescription=JSON text did not start with array or object and option to allow fragments not set.}
Does anybody have any ideas? I think it's not working because I'm setting the CURL arguments incorrectly.
Thanks in advance!
The NSURL family of APIs has no mechanism for rate limiting. If that's a requirement, you'll have to use libcurl instead. If not, then:
The body should be the contents of the file (use NSData's dataWithContentsOfURL: method) and nothing else.
The authentication is too complicated to explain here.
One approach is using the techniques described Apple's URL Session Programming Guide, which describes how to do HTTP authentication in depth.
However, the easiest way, by far, to do auth with NSURL* APIs is to just add an Internet password into the keychain, as described in APple's Keychain Services Concepts.
I have a little Mac application which should be able to post Data to my web server which saves the data in a database. Now that's the Code I have now:
NSData *postData = [urlString dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
NSString *postLength = [NSString stringWithFormat:#"%d", [postData length]];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:[NSURL URLWithString:#"http://..."]];
[request setHTTPMethod:#"POST"];
[request setValue:postLength forHTTPHeaderField:#"Content-Length"];
[request setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
[request setHTTPBody:postData];
NSURLConnection * connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
if (connection) NSLog(#"Done");
And it works fine. But now I want to check whether the data was correct (and stored in the database) or something (like eMail) is wrong. The PHP file prints e.g. "email incorrect" out if the E-Mail is not correct.
But how can I fetch this data (which PHP prints out) in Xcode that the App knows whether it was successful or not?
Thanks for answers!
You need to implement the NSURLConnectionDelegate methods connection:didReceiveData: and connectionDidFinishLoading:
According to the docs didReceiveData: may be called multiple times per NSURLRequest (i.e. the response will not always arrive all at once) so the recommended method is to append the incoming data to buffer during connection:didReceiveData: and then do any processing on the data in connectionDidFinishLoading:.
You could create a property on your class like this:
#property (nonatomic, strong) NSMutableData *dataBuffer;
And instantiate your buffer during viewDidLoad:
- (void)viewDidLoad
{
[super viewDidLoad];
self.dataBuffer = [[NSMutableData alloc] init];
// do any other setup your class requires...
}
And then implement the delegate methods:
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
// clear the buffer in case it has been used previously
[self.dataBuffer setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[self.dataBuffer appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection*)connection
{
NSString *response = [NSString stringWithUTF8String:[self.dataBuffer bytes]]);
NSLog(#"response from HTTP request=>%#", response);
}
This can all also be done using a third-party networking library like ASIHTTPRequest (which is no longer under active develoment) or AFNetworking, but sometimes those can be overkill depending upon what you are trying to accomplish
Implement the delegate method for the NSURLConnection,
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response.
This method is called by the app when the request finishes. You can access response data using the 'response' parameter.
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data;
Then just convert the 'data' parameter into a string using:
NSString *responseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
Then you can search the response for whatever string you want, e.g., "email incorrect".
PS: I generally don't use NSURLConnection/NSURLRequest for HTTP requests, I'd recommend you check out ASIHTTPRequest for really simple HTTP requests/connections.
Hope this helps.
I am trying to write an iPhone app in Objective-C. I need to POST data using NSURLConnection. Every example I can find deals with JSON; I do not need to use JSON. All I need to do is POST the data and get a simple 1 or 0 (succeed or fail) from a PHP script. Nothing more.
I came across this code but I am not sure how to use it or modify it to not use JSON:
- (void)performRequest {
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:#"http://someplace.com/"]];
[request setValue:#"Some Value" forHTTPHeaderField:#"Some-Header"];
[request setHTTPBody:#"{\"add_json\":\"here\"}"];
[request setHTTPMethod:#"POST"];
[NSURLConnection connectionWithRequest:[request autorelease] delegate:self];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
// Fail..
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
// Request performed.
}
Here's how to create an ordinary post.
First create a request of the right type:
NSURL *URL = [NSURL URLWithString:#"http://example.com/somepath"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL];
request.HTTPMethod = #"POST";
Now format your post data as a URL-encoded string, like this:
NSString *params = #"param1=value1¶m2=value2&etc...";
Remember to encode the individual parameters using percent encoding. You can't entirely rely on the NSString stringByAddingPercentEscapesUsingEncoding method for this (google to find out why) but it's a good start.
Now we add the post data to your request:
NSData *data = [params dataUsingEncoding:NSUTF8StringEncoding];
[request addValue:#"8bit" forHTTPHeaderField:#"Content-Transfer-Encoding"];
[request addValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
[request addValue:[NSString stringWithFormat:#"%i", [data length]] forHTTPHeaderField:#"Content-Length"];
[request setHTTPBody:data];
And that's it, now just send your request as normal using NSURLConnection (or whatever).
To interpret the response that comes back, see Maudicus's answer.
You can use the following NSURLConnection method if you target ios 2.0 - 4.3 (It seems to be deprecated in ios 5)
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
NSString * string = [[NSString alloc] initWithData:data encoding:
NSASCIIStringEncoding];
if (string.intValue == 1) {
} else {
}
}
I've a very similar situation to whitebreadb. I'm not disagreeing with the answers submitted and accepted but would like to post my own as the code provided here didn't work for me (my PHP script reported the submitted parameter as a zero-length string) but I did find this question that helped.
I used this to perform a posting to my PHP script:
NSURL *URL = [NSURL URLWithString:[NSString stringWithFormat:#"http://www.myphpscriptlocation.net/index.php?userID=%#",self.userID_field.stringValue]];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL];
request.HTTPMethod = #"POST";
NSURLConnection *c = [NSURLConnection connectionWithRequest:request delegate:self];
I'm a novice in iOS developing, and have some problems with understanding web service organization. I want to send a Get query to the URL. And I do it so:
-(BOOL) sendLoginRequest{
NSString *getAction = [NSString stringWithFormat:#"action=%#&username=%password=%#",#"login",self.log.text, self.pass.text];
NSString *getUserName = [NSString stringWithFormat:#"username=%#",self.log.text];
NSString *getPassword = [NSString stringWithFormat:#"username=%#",self.pass.text];
NSData *getDataAction = [getAction dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
NSString *getLengthAction = [NSString stringWithFormat:#"%d", [getDataAction length]];
NSMutableURLRequest *request = [[[NSMutableURLRequest alloc] init] autorelease];
[request setURL:[NSURL URLWithString:#"http:http://www.site.fi/api/"]];
[request setHTTPMethod:#"GET"];
[request setValue:getLengthAction forHTTPHeaderField:#"Content-Length"];
[request setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
[request setHTTPBody:getLengthAction];
self.urlConnection = [[[NSURLConnection alloc] initWithRequest:request delegate:self] autorelease];
NSAssert(self.urlConnection != nil, #"Failure to create URL connection.");
// show in the status bar that network activity is starting
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
}
the answer may be "true" or "false"
but how can I take this answer?
You should define next methods to get answer:
Start connection: [self.urlConnection start];
Check server response:
- (void)connection:(NSURLConnection *)theConnection didReceiveResponse:(NSURLResponse *)response
Collect data that servers sends you:
- (void)connection:(NSURLConnection *)theConnection didReceiveData:(NSData *)data
Be sure to manage errors:
- (void)connection:(NSURLConnection *)theConnection didFailWithError:(NSError *)error
Check received data:
- (void)connectionDidFinishLoading:(NSURLConnection *)theConnection
To be more sure that you correctly understood me check NSURLConnection Class Reference
Send [self.urlConnection start]; and implement the NSURLConnectionDelegate methods to receive the response. Alternatively use ASIHTTPRequest and the block handlers, which to my way of thinking are much easier to write for beginners, provided you don't need to run on iOS pre-4.1.
You will gather the data returned as NSData; just convert that to a string, and either call boolValue on the string (check the docs for its rather strange tests), or use a specific set of your own tests.
I used the asihttp library to connect to twitter.
The idea is to send a login request, get the response and extract the session ID/auth code from the response's cookie header. Then you can use that session ID/auth code for consecutive calls.
I don't obtain the auth_code because the authentication fails. how can I fix this?
the code is below:
- (void) login {
NSString *username = #"user";
NSString *password = #"pass";
NSURL *url = [NSURL URLWithString:#"https://twitter.com/sessions?phx=1"];
ASIFormDataRequest *request = [[[ASIFormDataRequest alloc] initWithURL:url] autorelease];
[request addRequestHeader:#"User-Agent" value: #"ASIHTTPRequest"];
[request setPostValue:username forKey:#"session[username_or_email]"];
[request setPostValue:password forKey:#"session[password]"];
[request setDelegate: self];
[request setDidFailSelector: #selector(loginRequestFailed:)];
[request setDidFinishSelector: #selector(loginRequestFinished:)];
[request startAsynchronous];
}
- (void)loginRequestFailed:(ASIHTTPRequest *)request {
NSError *error = [request error];
NSLog(#"login request failed with error: %#", [error localizedDescription]);
}
- (void)loginRequestFinished:(ASIHTTPRequest *)request {
NSString *responseString = [[request responseHeaders] objectForKey:#"Set-Cookie"];
NSLog(#"%#",responseString);
}
I tried to connect from shell and it works.
curl -d 'session[user_or_emai]=user&session[password]=pass' https://twitter.com/sessions
Don't scrape twitter.com. It will end with you getting suspended. Instead use the approved API to integrate with Twitter. You can read about how authentication works with Twitter's API, how you can use xAuth to jumpstart authentication with a users password, and the open source code to help get you started.