How to implement refresh token in ios - ios

only some api call needs the token. and when 401 occurs refresh token call will be taken place.and for each call the token is refreshing. how to execute more than 1 api synchronously when 401 occurs

This is upto you, how you design the flow but I did almost same problem like following in Objective C
Call method of like in my case userProfileGETRequest
Before calling userProfileGETRequest Check date if token gets expired(in your case may be status code == 401)
If Token not expired simply call API in my case userProfileAPI with last token
If Token Expired then Call Refresh token and with Success and Failure Callback
If successful refresh token, call the userProfileAPI API with updated refresh token.
+ (void) userProfileGETRequest:(NSDictionary *)headerParams urlQuery: (NSString*)action parameters:(NSDictionary*)params docOpenPassword: (NSString*)password docOpenOtp: (NSString*)otp
onComplete:(void (^)(id json, id code, id url))successBlock
onError:(void (^)(id error, id code, id url))errorBlock {if ([[SingletonSDK sharedInstance] isTokenExpired:[NSDate date]]) {[self refereshToken:nil :^(id json, id code) {
[[SingletonSDK sharedInstance] handleLoginResponseObject:json];
[self userProfileAPI:headerParams urlQuery:action parameters:params
onComplete:^(id json, id code, id url) {
successBlock(json, code, url);
} onError:^(id error, id code, id url) {
errorBlock(error, code, url);
}];
} onError:^(id error, id code) {
[[SingletonSDK sharedInstance] hideProgessHud];
return ;
}];
}
} else {
[self userProfileAPI:headerParams urlQuery:action parameters:params
onComplete:^(id json, id code, id url) {
successBlock(json, code, url);
} onError:^(id error, id code, id url) {
errorBlock(error, code, url);
}];
}}
//userProfileAPI Methods
+ (void) userProfileAPI:(NSDictionary *)headerParams urlQuery: (NSString*)action parameters:(NSDictionary*)params
onComplete:(void (^)(id json, id code, id url))successBlock
onError:(void (^)(id error, id code, id url))errorBlock
{
NSString *authorizationValue = [self setAuthorizationValue:action];
NSString *language = [self editedLanguageNameAsApiRequired];
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
//set headers values
[manager.requestSerializer setValue:#"application/json" forHTTPHeaderField:#"Accept"];
[manager.requestSerializer setValue:language forHTTPHeaderField:#"Accept-Language"];
[manager.requestSerializer setValue:authorizationValue forHTTPHeaderField:#"authorization"];
[manager GET:action parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"getRequest response success");
NSString *url = [[[operation response] URL] absoluteString];
NSInteger statusCode = [operation.response statusCode];
NSNumber *statusObject = [NSNumber numberWithInteger:statusCode];
successBlock(responseObject, statusObject, url);
}
failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
NSString *url = [[[operation response] URL] absoluteString];
NSInteger statusCode = [operation.response statusCode];
NSNumber *statusObject = [NSNumber numberWithInteger:statusCode];
if ([self takeDesiredActionIfAccessTokenExpired:statusCode]) {
return ;
}
id responseObject = operation.responseData;
id json = nil;
id errorMessage = nil;
if ([statusObject integerValue] == 404) {
errorMessage = [[SingletonSDK sharedInstance] getStringValueFromLanguageKey: COMMON_ERROR_SHARED_PREFERENCES];//NSLocalizedString(COMMON_ERROR_RESOURCE_NOT_FOUND, nil);
} else {
if (responseObject) {
json = [NSJSONSerialization JSONObjectWithData:responseObject options:kNilOptions error:&error];
errorMessage = [(NSDictionary*)json objectForKey:#"Message"];
}else{
json = [error.userInfo objectForKey:NSLocalizedDescriptionKey];
errorMessage = json;
}
}
if(![errorMessage isKindOfClass:[NSString class]]){
errorMessage = [[SingletonSDK sharedInstance] getStringValueFromLanguageKey: COMMON_ERROR_MSG] ; //NSLocalizedString(COMMON_ERROR_MSG, nil);
}
}];
}

Related

retry request when the internet connection is back - IOS

I am using AFNetworking 3.0 to perform Web request in my application.
Is there a way to automatically retry a request when the internet is back?
This is the request code:
#try {
NSString *urlMuniByGov = [NSString stringWithFormat:#"%#/%#", URL_MUNICIPALITES, selectedGov.govID];
NSURL *url = [NSURL URLWithString:urlMuniByGov];
AFHTTPSessionManager *manager = [[AFHTTPSessionManager alloc] init];
manager.responseSerializer = [AFJSONResponseSerializer serializer];
manager.securityPolicy.allowInvalidCertificates = YES;
[manager GET:url.absoluteString
parameters:nil
progress:nil
success:^(NSURLSessionDataTask * task, id responseObject) {
NSArray *muniNSArray = [responseObject objectForKey:#"municipalites"];
if ([muniNSArray isKindOfClass:[NSArray class]]){
for (NSDictionary *dictionary in muniNSArray) {
Municipality *munModel = [Municipality new] ;
munModel.munID = [dictionary objectForKey:#"id"];
munModel.munNameAr = [[dictionary objectForKey:#"nom"] objectForKey:#"ar"];
munModel.munNameFr = [[dictionary objectForKey:#"nom"] objectForKey:#"fr"];
[self.munsArray addObject:munModel];
[self.munsString addObject:munModel.munNameAr];
}
}
[municipalityText setItemList:[NSArray arrayWithArray:self.munsString]];
} failure:^(NSURLSessionDataTask * task, NSError * error) {
NSLog(#"Error: %#", error);
}];
}
#catch (NSException *exception) {
NSLog(#"Exception: %#", exception);
}
[[AFNetworkReachabilityManager sharedManager]setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
NSLog(#"Reachability: %#", AFStringFromNetworkReachabilityStatus(status));}];
if any changes in the net connection this block will call , so here u can retry a request
for additional information follow the link https://github.com/AFNetworking/AFNetworking#network-reachability-manager

Code=-1016 "Request failed: unacceptable content-type: text/plain" UserInfo=0x7a2da380

AFHTTPRequestOperationManager* manager = [AFHTTPRequestOperationManager manager];
NSLog(#"%#",[urlOfVm class]);
NSMutableString *url = [NSMutableString stringWithString:urlOfVm];
[url appendString:in];
NSLog(#"%#",url);
NSURLRequest* request = [[AFJSONRequestSerializer serializer]requestWithMethod:#"POST" URLString:url parameters:diccp ];
AFHTTPRequestOperation* operation = [manager HTTPRequestOperationWithRequest:request
success:^(AFHTTPRequestOperation *operation, id responseObject) {
if (responseObject != nil) {
NSLog(#"----------------------response:%#",[operation responseString]);
NSLog(#"responseObject:%#",responseObject);
[self create:(NSDictionary *)responseObject];
}
else{
NSLog(#"return null");
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"response:%#",[error description]);
}];
[operation setResponseSerializer:[AFJSONResponseSerializer serializer] ];
[[NSOperationQueue mainQueue] addOperations:#[operation] waitUntilFinished:NO];
below is java interFace:
/**
* user register
* if the method return 0 ,it means the user exists; return 1:it means register success, return 2 means the internet has some problem
*
* #param parameter
* #return
*/
#RequestMapping(value = "/register")
#ResponseBody
public String registerAccount(#RequestBody Account account) {
System.out.println(account.getUserName());
Account account1 = accountManager.isExistAccountByUserName(account
.getUserName());
if (null != account1) {
return "0";
} else {
try {
account.setGenerateTime(DateUtils.formatTime(new Date()));
String id = new SimpleDateFormat("SSSssmmHHddMMyy").format(new Date());
account.setId(id);
account.setIdType("1");
account.setPhoneNumber(account.getUserName());
accountManager.insertAccount(account);
return "3";
} catch (Exception e) {
return "2";
}
}
}
As error refers, you are sending request with wrong content type (text/plain). I suppose, you need to change content type to JSON. To do that, add JSON request serializer:
[operation setRequestSerializer:[AFJSONRequestSerializer serializer]];

How would I send a PUT request with the following information using AFNetWorking?

This is what my server API document shows me to return a successful request.
curl -X PUT -d {"questions":[{"type":"control_head"}]} "https://api.request.com/forms"
{"questions":[{"type":"control_head"}]} this is the parameter.
https://api.request.com/forms this is the URL.
How can I handle this properly handle this using AFNetWorking? This is what I've got so far.
NSString *urlStr = [NSString stringWithFormat:#"https://api.request.com/forms"];
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
[manager PUT:urlStr parameters:parameter success:^(AFHTTPRequestOperation *operation, id responseObject) {
[operation setUserInfo:userinfo];
SBJsonParser *jsonparser = [SBJsonParser new];
id result = [jsonparser objectWithString:[operation responseString]];
if ( self.delegate != nil && [self.delegate respondsToSelector:finishSelector] ) {
[self.delegate performSelector:finishSelector withObject:result];
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
[operation setUserInfo:userinfo];
if ( self.delegate != nil && [self.delegate respondsToSelector:failSelector] ) {
[self.delegate performSelector:failSelector withObject:[operation error]];
}
}];
I am not sure how to handle parameter correctly.
You can construct an NSDictionary equivalent of your parameters with:
NSDictionary *parameters = #{#"questions": #[#{#"type": #"control_head"}]};
Just pass that into PUT, and it should work as expected.

POST with URL parameters and JSON body in AFNetworking

I'd like to make a POST call that has both URL parameters and a JSON body:
URL http://example.com/register?apikey=mykey
JSON { "field" : "value"}
How can I use two different serializers at the same time with AFNNetworking? Here's my code with the URL parameters missing:
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
manager.responseSerializer = [AFJSONResponseSerializer serializer];
[manager POST:#"http://example.com/register" parameters:json success:^(AFHTTPRequestOperation *operation, id responseObject) {
I make a post method
/**
* Services gateway
* Method get response from server
* #parameter -> object: request josn object ,apiName: api endpoint
* #returm -> void
* #compilationHandler -> success: status of api, response: respose from server, error: error handling
*/
+ (void)getDataWithObject:(NSDictionary *)object onAPI:(NSString *)apiName withController:(UIViewController*)controller
:(void(^)(BOOL success,id response,NSError *error))compilationHandler {
controller = controller;
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
// set request type to json
manager.requestSerializer = [AFJSONRequestSerializer serializer];
manager.responseSerializer = [AFHTTPResponseSerializer serializer];
// post request to server
[manager POST:apiName parameters:object success:^(AFHTTPRequestOperation *operation, id responseObject) {
// NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:responseObject
options:0
error:&error];
//NSString *JSONString = [[NSString alloc] initWithBytes:[jsonData bytes] length:[jsonData length] encoding:NSUTF8StringEncoding];
////
// check the status of API
NSDictionary *dict = responseObject;
NSString *statusOfApi = [[NSString alloc]initWithFormat:#"%#"
,[dict objectForKey:#"OK"]];
// IF Status is OK -> 1 so complete the handler
if ([statusOfApi isEqualToString:#"1"] ) {
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
compilationHandler(TRUE,responseObject,nil);
} else {
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
NSArray *errorMessages = [responseObject objectForKey:#"messages"];
NSString *message = [errorMessages objectAtIndex:0];
[Utilities showAlertViewWithTitle:apiName message:message];
compilationHandler(FALSE,responseObject,nil);
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSString *message = [NSString stringWithFormat:#"%#",[error localizedDescription]];
NSLog(#"Message is %#", message);
NSString *errorMessage = [NSString stringWithFormat:#"%#",[error localizedDescription]];
if (!([message rangeOfString:#"The request timed out."].location == NSNotFound)) {
[Utilities showAlertViewWithTitle:apiName message:errorMessage];
}
compilationHandler(FALSE,errorMessage,nil);
}];
// For internet reachibility check if changes its state
[self checkInternetReachibility:manager];
}
**for Example when we call the Service **
// calling service gateway API
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithObjectsAndKeys:
"field",#"value",
nil];
[self getDataWithObject:dict onAPI:KGet_Preferences withController:(UIViewController*)controller :^(BOOL success, id response, NSError *error) {
if( success ) {
NSMutableDictionary *data = [[response valueForKey:#"data"] valueForKey:#"preferences"];
compilationHandler(success,data,error);
} else {
compilationHandler(success,nil,error);
}
}];
I believe there is no automatic way of doing it. However, there is a simple way of achieving it manually:
- (NSMutableURLRequest *)someRequestWithBaseURL:(NSString *)baseUrl
method:(NSString *)method
path:(NSString *)path
uriParameters:(NSDictionary *)uriParameters
bodyParameters:(NSDictionary *)bodyParameters
NSURL *url = [NSURL URLWithString:path relativeToURL:[NSURL URLWithString:baseUrl]];
AFHTTPRequestSerializer *httpRequestSerializer = [AFJSONRequestSerializer serializerWithWritingOptions:0]
NSMutableDictionary *parameters = [NSMutableDictionary dictionaryWithDictionary:bodyParameters];
if ([httpRequestSerializer.HTTPMethodsEncodingParametersInURI containsObject:method]) {
[parameters addEntriesFromDictionary:uriParameters];
} else {
NSURLComponents *urlComponents = [NSURLComponents componentsWithURL:url resolvingAgainstBaseURL:YES];
// For urlEncodedString, check http://stackoverflow.com/a/718480/856549
urlComponents.percentEncodedQuery = [uriParameters urlEncodedString];
url = [urlComponents URL];
}
NSError *error;
NSURLRequest *request = [httpRequestSerializer requestWithMethod:method
URLString:[url absoluteString]
parameters:parameters
error:&error];

AFNetworking retry timeout requests using enqueueBatchOfHTTPRequestOperations

There are few similar questions to mine with answers,but could not find a way to use that solutions on my code. I would be glad, if anyone can help me on code. How to retry timeout request?
while block for pagination purpose:
while(mult < (int)totalCount) {
AFHTTPRequestOperation *opr = [self getRequestForAllRecordsOfClass:className updatedAfterDate:mostRecentUpdatedDate withinPage:page+1];
[pagedOperations addObject:opr];
mult = mult + PAGINATION_SIZE;
page = page + 1;
}
[[SDAFParseAPIClient sharedClient] enqueueBatchOfHTTPRequestOperations:operations progressBlock:^(NSUInteger numberOfCompletedOperations, NSUInteger totalNumberOfOperations) {
NSLog(#"totalNumberOfOperations: %u numberOfCompletedOperations: %u",totalNumberOfOperations,numberOfCompletedOperations);
} completionBlock:^(NSArray *operations) {
...
}];
and building request operation
-(AFHTTPRequestOperation *)getRequestForAllRecordsOfClass:(NSString *)className updatedAfterDate:(NSDate *)mostRecentDate withinPage:(int)page {
NSMutableURLRequest *request = [ZurmoHelper GETRequestForAllRecordsOfClass:className updatedAfterDate:mostRecentDate inPage:page];
AFHTTPRequestOperation *operation = [[SDAFParseAPIClient sharedClient] HTTPRequestOperationWithRequest:request success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"RESPONSE pagination!!! %#:", className);
NSError *error = nil; //error in parsing json
NSDictionary *jsonDict = [NSJSONSerialization JSONObjectWithData:responseObject options:kNilOptions error:&error];
if (!error) {
NSLog(#"json dict paged in : %d",page );
id dataObject = [jsonDict objectForKey:#"data"];
NSArray *itemsObject = [dataObject objectForKey:#"items"];
[self addItems:itemsObject className:className];
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Request for class %# failed with error: %#", className, error);
if (error.code == -1001) {
NSLog(#"for class %# page: %d,",className,page);
//need to retry this operation???
}
}];
return operation;
}

Resources