how to call API from API using NSURLSession block - ios

I have
NSString* FBAuthoValue= #"TESTINGCONSTANT";
On click of Load Button ,it call HitLoadAPI
I am calling my API like below HitLoadAPI, now if at my server end my FBAuthoValue is change i need to Hit another API to get refresh value of FBAuthoValue, and set in HitLoadAPI.
1) User hit HitLoadAPI with FBAuthoValue= #"TESTINGCONSTANT" value, but as in server now FBAuthoValue= #"NewTestCode", so it return httpresponsecode 909,on 909 i need to call refreshFBAuthValue api, and put this value back to HitLoadAPI, and the api work correctly.
2) if FBAuthoValue token change in server, need to call refreshFBAuthValue API, and its return value need to set and call the HitLoadAPI again,without knowing the user.
NOTE: i have to hit multiple API one after another, suppose API-1,API-2,API-3 and so on, and if FBAuthoValue, if in any api ,changes in server then need to refresh that FBAuthoValue and then the same API need to be call, without effecting or blocking to user.
I will reward 50 bounty for sure.
Overview: API-1 call, in the meanwhile if token expire,need to call token expire api, and the API-1 will recall again, without user press Load Button again.
Here is my code
-(void)HitLoadAPI
{
NSError *error;
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:nil];
NSURL *url = [NSURL URLWithString:#"[JSON SERVER"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
[request addValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
[request addValue:#"application/json" forHTTPHeaderField:#"Accept"];
[request setHTTPMethod:#"POST"];
[request setValue:FBAuthoValue forHTTPHeaderField:FBAUTH];
NSDictionary *mapData = [[NSDictionary alloc] initWithObjectsAndKeys: #"TEST IOS", #"name",
#"IOS TYPE", #"typemap",
nil];
NSData *postData = [NSJSONSerialization dataWithJSONObject:mapData options:0 error:&error];
[request setHTTPBody:postData];
NSURLSessionDataTask *postDataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSDictionary* headers = [(NSHTTPURLResponse *)response allHeaderFields];
//NSLog(#" headers =%#",headers);
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response;
//NSLog(#"response status code: %ld", (long)[httpResponse statusCode]);
if([httpResponse statusCode]==909)
{
FBAuthoValue =[self refreshFBAuthValue];
//what to do here so the current API hit will be call again....
}
}];
[postDataTask resume];
}
-(NSString *) refreshFBAuthValue
{
//hit api to get new refresh token code here need its calling code as well as the block coding cause it response so late which cause return value nil...to HitLoadAPI
return FBaccess_token; //it will return refresh FBaccess_token code
}

You can create a method which you can use to call any api from anywhere in the application, This method takes the parameter specific to an api call, like api url, data which will be included in the body of the request and a completion block which will be called when fbAuthValue is valid.
-(void)HitAPILoadWithFbAuthValue:(NSString*)fbAuthValue apiUrl:(NSString*)apiUrl postData:(NSDictionary*)dict withCompletion:(void (^)(int statusCode,NSURLResponse * apiResponse,NSError * error))completion{
NSError *error;
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:nil];
NSURL *url = [NSURL URLWithString:apiUrl];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
[request addValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
[request addValue:#"application/json" forHTTPHeaderField:#"Accept"];
[request setHTTPMethod:#"POST"];
[request setValue: fbAuthValue forHTTPHeaderField:FBAUTH];
//post body with dictionary passed as a parameter
NSData *postData = [NSJSONSerialization dataWithJSONObject:dict options:0 error:&error];
[request setHTTPBody:postData];
NSURLSessionDataTask *postDataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSDictionary* headers = [(NSHTTPURLResponse *)response allHeaderFields];
//NSLog(#" headers =%#",headers);
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response;
//NSLog(#"response status code: %ld", (long)[httpResponse statusCode]);
if([httpResponse statusCode]==909)
{
FBAuthoValue =[self refreshFBAuthValue];
//what to do here so the current API hit will be call again....
if (FBAuthoValue){
[self HitAPILoadWithFbAuthValue:fbAuthValue apiUrl:apiUrl postData:dict withCompletion:completion];
}else{
}
}
//if FbAuthValue is valid, call completion block
completion((int)[httpResponse statusCode],response, error);
}];
[postDataTask resume];
}
Usage
I assume you write this method in a separate class called APIManager. So to call this method first create an instance of the APIManager and call like this:
APIManager *sharedManager = [APIManager sharedInstance]
//call API_1
[sharedManager HitAPILoadWithFbAuthValue:FBAuthValue apiUrl:#"API_1_URL" postData:dict_for_first_api withCompletion:^(int statusCode, NSURLResponse *apiResponse, NSError *error) {
if(error != nil){
//handle error here
}else{
//call API_2
[sharedManager HitAPILoadWithFbAuthValue:FBAuthValue apiUrl:#"API_2_URL" postData:dict_for_second_api withCompletion:^(int statusCode, NSURLResponse *apiResponse, NSError *error) {
}];
}
}];

Related

Integrate Digest Authentication in Objective c

I want to integrate digest authentication in my objective c code.
I am using NSURLSessionDataTask.
In first webservice call i fetch the nonce value and then in next call i set the header of the same webservice.
NSDictionary *payload;
payload = #{
#"Username" : #"",
#"Password" : #"",
};
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:#""]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:10.0];
[request setHTTPMethod:#"GET"];
NSError *error = nil;
NSData *data = [NSJSONSerialization dataWithJSONObject:payload
options:0 error:&error];
request.HTTPBody = data;
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (error) {
NSLog(#"%#", error);
} else {
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response;
NSLog(#"%#", httpResponse);
NSDictionary* dictHeaders = [(NSHTTPURLResponse *)response allHeaderFields];
NSLog(#"%#",[dictHeaders objectForKey:#"Www-Authenticate"]);
[self callWSAfterAuthentication:[dictHeaders objectForKey:#"Www-Authenticate"]];
}
}];
[dataTask resume];
You have not said in your question what exact problems you have. Assuming the authentication simply does not work:
Add a NSURLSessionDelegate to your NSURLSession and handle the authentication in the URLSession:didReceiveChallenge:completionHandler: delegate method. Check for NSURLAuthenticationMethodHTTPDigest and respond accordingly. (You can find info on how to implement this)

Request is blank when sending data through iOS to google cloud endpoint

i am working on Google cloud endpoint with datastore. When i am passing data through Android & iOS with method POST , it is getting saved in datastore with empty record. i.e. request is properly working but the way i am sending data is wrong. please help me for this.
For iOS, code is mentioned below :
NSDictionary *headers = #{ #"content-type": #"application/json",
#"cache-control": #"no-cache",
#"postman-token": #"404012ff-722e-c5d8-48db-fa7fb3260841"};
NSLog(#"header %#",headers);
request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:#"enter url here..."]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:10.0];
NSString* strRequest=#"";
strRequest =[[NSString alloc] initWithFormat:#"displayEmail=%#&displayName=%#",#"sonal#gmail.com",#"sonal"];
NSLog(#"url is %# parameter = %#", request , strRequest);
[request setHTTPMethod:#"POST"];
[request setHTTPBody: [strRequest dataUsingEncoding:NSUTF8StringEncoding]];
[request setAllHTTPHeaderFields:headers];
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSString *responseBody = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"responce Body===>%#",responseBody);
if (error) {
NSLog(#"%#", error);
} else {
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response;
NSLog(#"responce%#", httpResponse);
}
}];
[dataTask resume];
You need to set the httpBody property of your request. If you don't provide a body for the POST, of course it's blank.
https://developer.apple.com/reference/foundation/nsmutableurlrequest/1409064-httpbody
Or Objective-C
https://developer.apple.com/reference/foundation/nsmutableurlrequest/1409064-httpbody?language=objc
We got a solution..
we changed the way of passing data..
here is code :
request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:syncURL]
cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60];
NSData *requestData = [NSData dataWithBytes:[serverSyncAPIRequestJSON UTF8String] length:[serverSyncAPIRequestJSON length]];[request setHTTPMethod:#"POST"]; [request setHTTPBody:requestData]; [request setValue:#"application/json" forHTTPHeaderField:#"Content-Type"];

Getting data back from an NSURLSession via POST with JSON

Since NSURLConnection is depreated I need to move to an NSURLSession. I have a URL and some data I need to input as JSON. Then the result should be JSON coming back. I see something like so:
NSError *error;
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:nil];
NSURL *url = [NSURL URLWithString:#"[JSON SERVER"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
[request addValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
[request addValue:#"application/json" forHTTPHeaderField:#"Accept"];
[request setHTTPMethod:#"POST"];
NSDictionary *mapData = [[NSDictionary alloc] initWithObjectsAndKeys: #"TEST IOS", #"name",
#"IOS TYPE", #"typemap",
nil];
NSData *postData = [NSJSONSerialization dataWithJSONObject:mapData options:0 error:&error];
[request setHTTPBody:postData];
NSURLSessionDataTask *postDataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
}];
[postDataTask resume];
I this the correct approach?
My requirements are:
1. Turn my key value pairs into JSON.
2. Pass in the URL and JSON to a reusable function.
3. Get the JSON data returned.
4. Parse the JSON data returned.
Have the callers to your method to provide a completion handler which processes the data returned and update the UI to indicate completion.
You can copy the pattern found in the SDK, as follows:
- (void)makeRequest:(NSString *)param completion:(void (^)(NSDictionary *, NSError *))completion;
Implement it like this:
// in the same scope
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:nil];
- (void)makeRequest:(NSString *)param
completion:(void (^)(NSDictionary *, NSError *))completion {
// your OP code goes here, e.g.
NSError *error;
NSMutableURLRequest *request = // maybe the param is the url for this request
// use the already initialized session
NSURLSessionDataTask *postDataTask = [session dataTaskWithRequest:request
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
// call the completion handler in EVERY code path, so the caller is never left waiting
if (!error) {
// convert the NSData response to a dictionary
NSDictionary *dictionary = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
if (error) {
// there was a parse error...maybe log it here, too
completion(nil, error);
} else {
// success!
completion(dictionary, nil);
}
} else {
// error from the session...maybe log it here, too
completion(nil, error);
}
}];
[postDataTask resume];
}
Code that calls this method will look like this:
// update the UI here to say "I'm busy making a request"
// call your function, which you've given a completion handler
[self makeRequest:#"https://..." completion:^(NSDictionary *someResult, NSError *error) {
// here, update the UI to say "Not busy anymore"
if (!error) {
// update the model, which should cause views that depend on the model to update
// e.g. [self.someUITableView reloadData];
} else {
// handle the error
}
}];
Notice a couple things: (1) the return type is void, the caller expects nothing to be returned from this method, and makes no assignment when calling it. The data "returned" is provided as parameters to the completion handler, which is called later, after the asnych request is complete, (2) the signature of the completion handler matches exactly what the caller declared in the completion block ^(NSDictionary *, NSError *), this is just a suggestion, typical for network requests.
Instantiate the NSURLSession and NSMutableURLRequest object:
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setHTTPMethod:#"POST"];
[request addValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
[request addValue:#"application/json" forHTTPHeaderField:#"Accept"];
Turn your key value pairs into JSON:
// choose the right type for your value.
NSDictionary *postDict = #{#"key1": value1, #"key2": value2};
NSData *postData = [NSJSONSerialization dataWithJSONObject:postDict options:0 error:nil];
Make your POST with with the URL and JSON:
[request setURL:[NSURL URLWithString:#"JSON SERVER"];
[request setHTTPBody:postData];
NSURLSessionDataTask *postDataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
}];
[postDataTask resume];
Parse the JSON data returned within the completionHandler above:
if (!error) {
NSDictionary *responseDict = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
} else {
// error code here
}
responseDict is the parsed data. For example, if the server returns
{
"message":"Your messsage",
"data1":value1,
"data2":value2
}
You can easily get the value for data1 by using
[responseDict objectForKey:#"data1"];
If your want to make another POST with different URL or JSON, just repeat the flow of step 2-4.
Hope my answer helps.

How to add token to a Rest web service request in iOS Objective C

I have a rest web service request to be called in Objective C. How to add token to web service request for authentication ??
Thanks in advance
Add token in request as below
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:yourURL] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];
[request setHTTPMethod:#"GET"]; // Set your method
[request addValue:#"token_value" forHTTPHeaderField:#"Authorization"];
// ...... your code
// ........ add data
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
//HideProcess;
if (error)
{
//NSLog(#"Error : %#\n", error);
return;
}
if (data != nil)
{
NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&error];
NSLog(#"Response :\n%#\n", dict);
}
}];
[task resume];

Always getting back cached data in NSURLSessionDataTask

I'm facing a very strange issue when using NSURLSessionDataTask to post a JSON request to the server.
The first request goes through and I receive the correct JSON response, when I do a second request I'm getting always back the old response and the server never receives the request. Even if I turn on airplane mode the NSURLSessionDataTask does work an I get back the old response again.
That's the code I'm using:
- (void)getJSONFromURL:(NSURL*)url identifierCode:(NSInteger)code
{
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request addValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
[request addValue:#"application/json" forHTTPHeaderField:#"Accept"];
[request addValue:[DataController sharedInstance].currentUser.userToken forHTTPHeaderField:#"User-Token"];
[request setHTTPMethod:#"GET"];
if (![SVProgressHUD isVisible])
[SVProgressHUD show];
NSURLSessionDataTask *postTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error){
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*)response;
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
[self handleResponse:httpResponse withJSON:json identifierCode:code];
dispatch_async(dispatch_get_main_queue(), ^{
[SVProgressHUD dismiss];
});
}];
[postTask resume];
}
I've found the issue, I don't know why this has changed, because I never had to set that property before. Anyway I set configuration.URLCache = NULL; and now everthing works fine again.
you can set
request.cachePolicy = NSURLRequestReloadIgnoringLocalCacheData;
to disable it per request

Resources