implement Google OAuth 2 - iphone

I'm trying to implement Google OAuth 2 to get access to the Google APIs.
When i try to exchange the code by an access token, it doesn't work.
I use this method to do it.
(void)getAccessTokenwWithCode:(NSString*)code
{
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:[#"https://accounts.google.com/o/oauth2/token" ]];
[request setHTTPMethod:#"POST"];
NSDictionary *postBodyDic = [NSDictionary dictionaryWithObjectsAndKeys:
code, #"code",
#"my_client_id", #"client_id",
#"my_client_secret", #"client_secret",
#"http://localhost", #"redirect_uri",
#"authorization_code", #"grant_type",
nil];
NSString *postBody = [postBodyDic JSONString];
NSData *data = [postBody dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:YES];
[request setHTTPBody:data];
[request setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request
success:^(NSURLRequest *request, NSURLResponse *response, id JSON)
{
NSLog(#"%#", JSON);
}
failure:^(NSURLRequest *request, NSURLResponse *response, NSError *error, id JSON)
{
NSLog(#"ERROR \n%#", error );
}
];
[queue addOperation:operation];
}
I get a 400 error
Anyone can help me to localize the problem?
Thanks in advance.

Since you are using the AFNetworking classes, try using the AFNetworking Extension for OAuth 2 Authentication. I haven't used it, but it looks like what you need.

Related

JSON serialisation in AFNewtorking is failing

I am trying to perform GET requests that returns JSON string from a web-service using AFNetworking but I am receiving the following error from AFNetworking 1.3.3
#"JSON text did not start with array or object and option to allow fragments not set."
and here is my JSON which is a valid JSON string , I used many online validators to make sure
"{\"ErrorCode\":0,\"VerCode\":\"8595\"}"
AFNetworking Code that is not working
NSString *urlString = [BASE_URL stringByAppendingString:paramseters];
AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:[NSURL URLWithString:BASE_URL]];
NSMutableURLRequest *request = [httpClient requestWithMethod:#"GET"
path:urlString
parameters:nil];
AFJSONRequestOperation *operation =
[AFJSONRequestOperation JSONRequestOperationWithRequest:request
success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
NSDictionary *jsonDic = (NSDictionary *)JSON;
success(jsonDic);
}
failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
CPError *cpError = [CPError CPErrorWithErrorCode:error.code errorDesc:error.localizedDescription];
failure(cpError);
}];
[operation start];
I was able to parse the JSON into NSDictionary using the below code but I want to be able to use AFNetworking in order to make use of it's built in features , is there a way to make AFNetworking understands my JSON string ?
NSURL *url = [NSURL URLWithString:#"http://103.1.173.60/ims-mobile-wcf/MobileWCF.svc/AddUpdateMobileClient/123123/443da4444/1/1"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData timeoutInterval:120];
[request setHTTPMethod:#"GET"];
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
NSLog(#"%#",connectionError);
NSError *error = nil;
NSString *JSONString = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:&error];
NSDictionary *JSONDictionary =
[NSJSONSerialization JSONObjectWithData: [JSONString dataUsingEncoding:NSUTF8StringEncoding]
options: NSJSONReadingMutableContainers
error: &error];
}];
I'll take a stab and say the reason is that the response string appears to be in quotes, if this is the case then the error is very clear - the Fragments option is not set. Do a a global search for "JSONReadingOptions" and you'll find the place in AFNetworking where the response is serialized into a foundation object (in version 1.3 it's AFJsonRequestOperation line 79, it looks like your using 2.0) is basically exactly what you are doing manually. If you do as arturdev suggests and set the reading options to be NSJSONReadingAllowFragments it should work.
Try:
AFJSONRequestOperation *operation = ...
operation.JSONReadingOptions = NSJSONReadingAllowFragments;
[operation start];
This is wrong:
NSError *error = nil;
NSString *JSONString = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:&error];
NSDictionary *JSONDictionary =
[NSJSONSerialization JSONObjectWithData: [JSONString dataUsingEncoding:NSUTF8StringEncoding]
options: NSJSONReadingMutableContainers
error: &error];
JSONObjectWithData: does not return an NSString, it returns an object: NSArray or NSDictionary, in your case a NSDictionary
Just use:
NSError *error = nil;
NSDictionary *resultDictionary = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:&error];

How to determine reason for failure with AFNetworking AFJSONRequestOperation

I've inherited a project and am implementing AFNetworking and reading the docs it sounds great and much simpler than the current code. I have a url with json data so I'm doing the following, but getting the failure block and no idea why. I'm sure it's there, but how can I dig into AF and log the responses to determine failure reason. I know the url works, but perhaps its hitting the url but having trouble parsing?
NSString *listURL = [NSString stringWithFormat:GET_LIST,BASE_URL];
NSURL *url = [NSURL URLWithString:briefListURL];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest: request
success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
self.list = [NSArray arrayWithArray:(NSArray *)JSON];
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
[self listOperationDidFail];
}];
thanks to #Larme this worked:
failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) { NSLog(#"Error: %#", error); }
also, to answer my own issue above with text/plain. just add this before setting up operation:
[AFJSONRequestOperation addAcceptableContentTypes:[NSSet setWithObject:#"text/plain"]];

AFNetworking Expected content type error

I am getting the json string in failure block
NSURL *url = [[NSURL alloc] initWithString:#"http://www.vinipost.com/Services/Update/UpdateService.asmx/GetPropSubType?"];
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url];
[AFJSONRequestOperation addAcceptableContentTypes:[NSSet setWithObject:#"text/html"]];
AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
NSLog(#"%#", JSON);
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
NSLog(#"Request Failed with Error: %#, %#", error, error.userInfo);
}];
[operation start];
Output:
Request Failed with Error: Error Domain=AFNetworkingErrorDomain Code=-1016 "Expected content type {(
"text/json",
"text/javascript",
"application/json",
"text/html"
)}, got text/plain" UserInfo=0x71521a0 {NSLocalizedRecoverySuggestion=[{"PropTypId":1,"PropCatId":1,"PropTyp":"Flat/ Condo"}.......**
You need to add this line before operation
[AFJSONRequestOperation addAcceptableContentTypes:
[NSSet setWithObject:#"text/plain"]];
The error is clear:
the web service is returning a wrong content type.
The content type should be one of these:
"text/json",
"text/javascript",
"application/json",
"text/html"
But it returns
text/plain
Moreover, if you look at the http response, it returns HTML TAGS inside it, so AFNetworking is not able to parse.
If this page:
http://www.vinipost.com/Services/Update/UpdateService.asmx/GetPropSubType?
is under your control, correct the behavior removing html tags and changing the content type
In AFNetworking, you have to create NSURLRequest with the help of AFHTTPClient(So first you have to create AFHTTPClient and have to set some properties for this object) like below
AFHTTPClient *httpClient = [[httpClient alloc] initWithBaseURL:[NSURL URLWithString:#"http://www.vinipost.com/"]];
[httpClient registerHTTPOperationClass:[AFJSONRequestOperation class]];
[httpClient setDefaultHeader:#"Accept" value:#"application/json"];
httpClient.parameterEncoding = AFJSONParameterEncoding;
now if depends of GET/POST or any other type request you need to set parameter I consider it as POST Request, so set the Parameter dict and set all required Key Value pairs properly.if no parameters required you can pass Parameters as nil
NSURLRequest *request = [httpClient requestWithMethod:#"POST" path:#"Services/Update/UpdateService.asmx/GetPropSubType?" parameters:params];
AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request
success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON)
{
NSLog(#"%#",JSON);
}
failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON)
{
NSLog(#"Error MSG = %#",error);
}];
[operation start];
hope this will work for you :)

Preparing a GET/POST request to fetch data on iPhone

i am trying to fetch data in JSON format for the search word 'cancer'.
But i can't figure out how to call the websvice, i tried a few things but they are not working, can anybody help me in this.
Below is the API i should be calling
https://api.justgiving.com/docs/resources/v1/Search/FundraiserSearch
Clicking the following URL will get desired data in the browser.
https://api.justgiving.com/2be58f97/v1/fundraising/search?q=cancer
apiKey = 2be58f97
Here is the code i am using:
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
NSURL *requestURL = [NSURL URLWithString:#"https://api.justgiving.com/2be58f97/v1/fundraising/search"];
[request setURL:requestURL];
[request setHTTPMethod:#"GET"];
NSString *boundary = #"---------------------------14737809831466499882746641449";
NSString *contentType = [NSString stringWithFormat:#"multipart/form-data; boundary=%#",boundary];
[request addValue:contentType forHTTPHeaderField: #"Content-Type"];
NSMutableData *body = [NSMutableData data];
[body appendData:[[NSString stringWithFormat:#"\r\n--%#\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[#"Content-Disposition: form-data; name=\"q\"\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:#"%#",searchText] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:#"\r\n--%#--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[request setHTTPBody:body];
[NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
NSLog(#"ERROR = %#",error.localizedDescription);
if(error.localizedDescription == NULL)
{
NSString *returnString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"response >>>>>>>>> %#",returnString);
}
else
{
NSString *returnString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"response >>>>>>>>> %#",returnString);
}
}];
-(AFHTTPClient *) getHttpClient{
AFHTTPClient *httpClient = [[AFHTTPClient alloc]initWithBaseURL:[NSURL URLWithString:kBASEURL]];
httpClient.parameterEncoding = AFJSONParameterEncoding;
[httpClient setDefaultHeader:#"Accept" value:#"application/json"];
[httpClient registerHTTPOperationClass:[AFJSONRequestOperation class]];
return httpClient;
}
//This is how you should call
-(void) callAPI{
AFHTTPClient *httpClient = [self getHttpClient];
NSMutableURLRequest *request = [httpClient requestWithMethod:#"GET" path:method parameters:queryStrDictionary];// querystringDictionary contains value of all q=? stuff
AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
//You have Response here do anything you want.
[self processResponseWith:JSON having:successBlock andFailuerBlock:failureBlock];
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
//Your request failed check the error for detail
failureBlock(error);
}];
NSOperationQueue *queue = [[NSOperationQueue alloc] init] ;
[queue addOperation:operation];
}
In your code you setup a multipart/form-data request. While the achievement is creditable, it's not how you talk to the API of the given web service.
In fact, it's simpler:
As you can retrieve from the documentation from that site, "query parameters" go into the URL as a query string: "q=cancer". Then, just specify the Content-Type header as "application/json" - and it should work.
In general, URL query parameters will be prepended to a URL by appending a '?', followed by "non-hierarchical data" comprising the query string and then followed by an optional '#'.
What "non-hierarchical data" means is not exactly specified, but in almost all cases web services require a query string as a list of key/value pairs, whose key and value is separated by a '=', and the pairs are separated by a '&':
param1=value1&param2=value2
Furthermore, in order to disambiguate the query string, say when a value or key itself contains "special characters", like spaces, non-ASCII characters, an ampersand or a equal sign, etc., the query string must be properly "URL encoded" before appended to the url and send to the server.
The details of constructing a URL can be found consulting the corresponding RFC. However, wiki provides a comprehensible definition of the query string in a much more concise form:
http://en.wikipedia.org/wiki/Query_string
For further information how to "URL encode" a query string utilizing a handy method or function please read the NSString documentation, stringByAddingPercentEscapesUsingEncoding: https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/Reference/NSString.html
and Core Foundation: CFURLCreateStringByAddingPercentEscapes: https://developer.apple.com/library/mac/#documentation/CoreFOundation/Reference/CFURLRef/Reference/reference.html
A third party library may make this more convenient, nonetheless you should understand what that API means and how you would have to construct a URL, the HTTP headers and the query string yourself.

AFJSONRequestOperation with JSON encoded as NSISOLatin1StringEncoding crashing

I want to use AFNetworking more specifically AFJSONRequestOperation in a project to allow for easy async calls. I quickly tried using the sample code from AFNetworking GitHub Page
NSURL *url = [NSURL URLWithString:#"https://alpha-api.app.net/stream/0/posts/stream/global"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request
success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
NSLog(#"App.net Global Stream: %#", JSON);
}
failure:nil];
[operation start];
Which works fine, But when I use the URL for MetOffice Datapoint it crashes, I believe this might be because of the encoding type of the JSON feed being NSISOLatin1StringEncoding which causes a problem with NSJSONSerialization
The way I currently handle this is
NSString *string = [NSString stringWithContentsOfURL:kMetOfficeAllSites encoding:NSISOLatin1StringEncoding error:&error];
NSData *metOfficeData = [string dataUsingEncoding:NSUTF8StringEncoding];
id jsonObject = [NSJSONSerialization JSONObjectWithData:metOfficeData options:kNilOptions error:&error]
But how do I handle this situation with AFJSONRequestOperation?
Thanks in Advance