objc.ApiClient-body.mustache Maven / Gradle / Ivy
The newest version!
#import "{{classPrefix}}ApiClient.h"
NSString *const {{classPrefix}}ResponseObjectErrorKey = @"{{classPrefix}}ResponseObject";
static NSUInteger requestId = 0;
static bool offlineState = false;
static NSMutableSet * queuedRequests = nil;
static bool cacheEnabled = false;
static AFNetworkReachabilityStatus reachabilityStatus = AFNetworkReachabilityStatusNotReachable;
static void (^reachabilityChangeBlock)(int);
static NSDictionary * {{classPrefix}}__headerFieldsForResponse(NSURLResponse *response) {
if(![response isKindOfClass:[NSHTTPURLResponse class]]) {
return nil;
}
return ((NSHTTPURLResponse*)response).allHeaderFields;
}
static NSString * {{classPrefix}}__fileNameForResponse(NSURLResponse *response) {
NSDictionary * headers = {{classPrefix}}__headerFieldsForResponse(response);
if(!headers[@"Content-Disposition"]) {
return [NSString stringWithFormat:@"%@", [[NSProcessInfo processInfo] globallyUniqueString]];
}
NSString *pattern = @"filename=['\"]?([^'\"\\s]+)['\"]?";
NSRegularExpression *regexp = [NSRegularExpression regularExpressionWithPattern:pattern
options:NSRegularExpressionCaseInsensitive
error:nil];
NSString *contentDispositionHeader = headers[@"Content-Disposition"];
NSTextCheckingResult *match = [regexp firstMatchInString:contentDispositionHeader
options:0
range:NSMakeRange(0, [contentDispositionHeader length])];
return [contentDispositionHeader substringWithRange:[match rangeAtIndex:1]];
}
@interface {{classPrefix}}ApiClient ()
@property (nonatomic, strong) NSDictionary* HTTPResponseHeaders;
@end
@implementation {{classPrefix}}ApiClient
- (instancetype)init {
NSString *baseUrl = [[{{classPrefix}}Configuration sharedConfig] host];
return [self initWithBaseURL:[NSURL URLWithString:baseUrl]];
}
- (instancetype)initWithBaseURL:(NSURL *)url {
self = [super initWithBaseURL:url];
if (self) {
self.timeoutInterval = 60;
self.requestSerializer = [AFJSONRequestSerializer serializer];
self.responseSerializer = [AFJSONResponseSerializer serializer];
self.securityPolicy = [self customSecurityPolicy];
self.responseDeserializer = [[{{classPrefix}}ResponseDeserializer alloc] init];
self.sanitizer = [[{{classPrefix}}Sanitizer alloc] init];
// configure reachability
[self configureCacheReachibility];
}
return self;
}
+ (void)initialize {
if (self == [{{classPrefix}}ApiClient class]) {
queuedRequests = [[NSMutableSet alloc] init];
// initialize URL cache
[self configureCacheWithMemoryAndDiskCapacity:4*1024*1024 diskSize:32*1024*1024];
}
}
#pragma mark - Setter Methods
+ (void) setOfflineState:(BOOL) state {
offlineState = state;
}
+ (void) setCacheEnabled:(BOOL)enabled {
cacheEnabled = enabled;
}
+(void) setReachabilityStatus:(AFNetworkReachabilityStatus)status {
reachabilityStatus = status;
}
- (void)setHeaderValue:(NSString*) value forKey:(NSString*) forKey {
[self.requestSerializer setValue:value forHTTPHeaderField:forKey];
}
- (void)setRequestSerializer:(AFHTTPRequestSerializer *)requestSerializer {
[super setRequestSerializer:requestSerializer];
requestSerializer.timeoutInterval = self.timeoutInterval;
}
#pragma mark - Cache Methods
+(void)clearCache {
[[NSURLCache sharedURLCache] removeAllCachedResponses];
}
+(void)configureCacheWithMemoryAndDiskCapacity: (unsigned long) memorySize
diskSize: (unsigned long) diskSize {
NSAssert(memorySize > 0, @"invalid in-memory cache size");
NSAssert(diskSize >= 0, @"invalid disk cache size");
NSURLCache *cache =
[[NSURLCache alloc]
initWithMemoryCapacity:memorySize
diskCapacity:diskSize
diskPath:@"swagger_url_cache"];
[NSURLCache setSharedURLCache:cache];
}
#pragma mark - Request Methods
+(NSUInteger)requestQueueSize {
return [queuedRequests count];
}
+(NSNumber*) nextRequestId {
@synchronized(self) {
return @(++requestId);
}
}
+(NSNumber*) queueRequest {
NSNumber* requestId = [[self class] nextRequestId];
{{classPrefix}}DebugLog(@"added %@ to request queue", requestId);
[queuedRequests addObject:requestId];
return requestId;
}
+(void) cancelRequest:(NSNumber*)requestId {
[queuedRequests removeObject:requestId];
}
-(Boolean) executeRequestWithId:(NSNumber*) requestId {
NSSet* matchingItems = [queuedRequests objectsPassingTest:^BOOL(id obj, BOOL *stop) {
return [obj intValue] == [requestId intValue];
}];
if (matchingItems.count == 1) {
{{classPrefix}}DebugLog(@"removed request id %@", requestId);
[queuedRequests removeObject:requestId];
return YES;
} else {
return NO;
}
}
#pragma mark - Reachability Methods
+(AFNetworkReachabilityStatus) getReachabilityStatus {
return reachabilityStatus;
}
+(BOOL) getOfflineState {
return offlineState;
}
+(void) setReachabilityChangeBlock:(void(^)(int))changeBlock {
reachabilityChangeBlock = changeBlock;
}
- (void) configureCacheReachibility {
[self.reachabilityManager setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
reachabilityStatus = status;
{{classPrefix}}DebugLog(@"reachability changed to %@",AFStringFromNetworkReachabilityStatus(status));
[{{classPrefix}}ApiClient setOfflineState:status == AFNetworkReachabilityStatusUnknown || status == AFNetworkReachabilityStatusNotReachable];
// call the reachability block, if configured
if (reachabilityChangeBlock != nil) {
reachabilityChangeBlock(status);
}
}];
[self.reachabilityManager startMonitoring];
}
#pragma mark - Operation Methods
- (void) operationWithCompletionBlock: (NSURLRequest *)request
requestId: (NSNumber *) requestId
completionBlock: (void (^)(id, NSError *))completionBlock {
__weak __typeof(self)weakSelf = self;
NSURLSessionDataTask* op = [self dataTaskWithRequest:request completionHandler:^(NSURLResponse *response, id responseObject, NSError *error) {
__strong __typeof(weakSelf)strongSelf = weakSelf;
if (![strongSelf executeRequestWithId:requestId]) {
return;
}
{{classPrefix}}DebugLogResponse(response, responseObject,request,error);
strongSelf.HTTPResponseHeaders = {{classPrefix}}__headerFieldsForResponse(response);
if(!error) {
completionBlock(responseObject, nil);
return;
}
NSMutableDictionary *userInfo = [error.userInfo mutableCopy];
if (responseObject) {
// Add in the (parsed) response body.
userInfo[{{classPrefix}}ResponseObjectErrorKey] = responseObject;
}
NSError *augmentedError = [error initWithDomain:error.domain code:error.code userInfo:userInfo];
completionBlock(nil, augmentedError);
}];
[op resume];
}
- (void) downloadOperationWithCompletionBlock: (NSURLRequest *)request
requestId: (NSNumber *) requestId
completionBlock: (void (^)(id, NSError *))completionBlock {
__weak __typeof(self)weakSelf = self;
NSURLSessionDataTask* op = [self dataTaskWithRequest:request completionHandler:^(NSURLResponse *response, id responseObject, NSError *error) {
__strong __typeof(weakSelf)strongSelf = weakSelf;
if (![strongSelf executeRequestWithId:requestId]) {
return;
}
strongSelf.HTTPResponseHeaders = {{classPrefix}}__headerFieldsForResponse(response);
{{classPrefix}}DebugLogResponse(response, responseObject,request,error);
if(error) {
NSMutableDictionary *userInfo = [error.userInfo mutableCopy];
if (responseObject) {
userInfo[{{classPrefix}}ResponseObjectErrorKey] = responseObject;
}
NSError *augmentedError = [error initWithDomain:error.domain code:error.code userInfo:userInfo];
completionBlock(nil, augmentedError);
}
NSString *directory = [self configuration].tempFolderPath ?: NSTemporaryDirectory();
NSString * filename = {{classPrefix}}__fileNameForResponse(response);
NSString *filepath = [directory stringByAppendingPathComponent:filename];
NSURL *file = [NSURL fileURLWithPath:filepath];
[responseObject writeToURL:file atomically:YES];
completionBlock(file, nil);
}];
[op resume];
}
#pragma mark - Perform Request Methods
-(NSNumber*) requestWithPath: (NSString*) path
method: (NSString*) method
pathParams: (NSDictionary *) pathParams
queryParams: (NSDictionary*) queryParams
formParams: (NSDictionary *) formParams
files: (NSDictionary *) files
body: (id) body
headerParams: (NSDictionary*) headerParams
authSettings: (NSArray *) authSettings
requestContentType: (NSString*) requestContentType
responseContentType: (NSString*) responseContentType
responseType: (NSString *) responseType
completionBlock: (void (^)(id, NSError *))completionBlock {
// setting request serializer
if ([requestContentType isEqualToString:@"application/json"]) {
self.requestSerializer = [{{classPrefix}}JSONRequestSerializer serializer];
}
else if ([requestContentType isEqualToString:@"application/x-www-form-urlencoded"]) {
self.requestSerializer = [AFHTTPRequestSerializer serializer];
}
else if ([requestContentType isEqualToString:@"multipart/form-data"]) {
self.requestSerializer = [AFHTTPRequestSerializer serializer];
}
else {
self.requestSerializer = [AFHTTPRequestSerializer serializer];
NSAssert(NO, @"Unsupported request type %@", requestContentType);
}
// setting response serializer
if ([responseContentType isEqualToString:@"application/json"]) {
self.responseSerializer = [{{classPrefix}}JSONResponseSerializer serializer];
} else {
self.responseSerializer = [AFHTTPResponseSerializer serializer];
}
// sanitize parameters
pathParams = [self.sanitizer sanitizeForSerialization:pathParams];
queryParams = [self.sanitizer sanitizeForSerialization:queryParams];
headerParams = [self.sanitizer sanitizeForSerialization:headerParams];
formParams = [self.sanitizer sanitizeForSerialization:formParams];
if(![body isKindOfClass:[NSData class]]) {
body = [self.sanitizer sanitizeForSerialization:body];
}
// auth setting
[self updateHeaderParams:&headerParams queryParams:&queryParams WithAuthSettings:authSettings];
NSMutableString *resourcePath = [NSMutableString stringWithString:path];
[pathParams enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
NSString * safeString = ([obj isKindOfClass:[NSString class]]) ? obj : [NSString stringWithFormat:@"%@", obj];
safeString = {{classPrefix}}PercentEscapedStringFromString(safeString);
[resourcePath replaceCharactersInRange:[resourcePath rangeOfString:[NSString stringWithFormat:@"{%@}", key]] withString:safeString];
}];
NSMutableURLRequest * request = nil;
NSString* pathWithQueryParams = [self pathWithQueryParamsToString:resourcePath queryParams:queryParams];
if ([pathWithQueryParams hasPrefix:@"/"]) {
pathWithQueryParams = [pathWithQueryParams substringFromIndex:1];
}
NSString* urlString = [[NSURL URLWithString:pathWithQueryParams relativeToURL:self.baseURL] absoluteString];
if (files.count > 0) {
__weak __typeof(self)weakSelf = self;
request = [self.requestSerializer multipartFormRequestWithMethod:@"POST"
URLString:urlString
parameters:nil
constructingBodyWithBlock:^(id formData) {
[formParams enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
NSString *objString = [weakSelf.sanitizer parameterToString:obj];
NSData *data = [objString dataUsingEncoding:NSUTF8StringEncoding];
[formData appendPartWithFormData:data name:key];
}];
[files enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
NSURL *filePath = (NSURL *)obj;
[formData appendPartWithFileURL:filePath name:key error:nil];
}];
} error:nil];
}
else {
if (formParams) {
request = [self.requestSerializer requestWithMethod:method
URLString:urlString
parameters:formParams
error:nil];
}
if (body) {
request = [self.requestSerializer requestWithMethod:method
URLString:urlString
parameters:body
error:nil];
}
}
// request cache
BOOL hasHeaderParams = [headerParams count] > 0;
if (offlineState) {
{{classPrefix}}DebugLog(@"%@ cache forced", resourcePath);
[request setCachePolicy:NSURLRequestReturnCacheDataDontLoad];
}
else if(!hasHeaderParams && [method isEqualToString:@"GET"] && cacheEnabled) {
{{classPrefix}}DebugLog(@"%@ cache enabled", resourcePath);
[request setCachePolicy:NSURLRequestUseProtocolCachePolicy];
}
else {
{{classPrefix}}DebugLog(@"%@ cache disabled", resourcePath);
[request setCachePolicy:NSURLRequestReloadIgnoringLocalCacheData];
}
if (hasHeaderParams){
for(NSString * key in [headerParams keyEnumerator]){
[request setValue:[headerParams valueForKey:key] forHTTPHeaderField:key];
}
}
[self.requestSerializer setValue:responseContentType forHTTPHeaderField:@"Accept"];
[self postProcessRequest:request];
NSNumber* requestId = [{{classPrefix}}ApiClient queueRequest];
if ([responseType isEqualToString:@"NSURL*"] || [responseType isEqualToString:@"NSURL"]) {
[self downloadOperationWithCompletionBlock:request requestId:requestId completionBlock:^(id data, NSError *error) {
completionBlock(data, error);
}];
}
else {
[self operationWithCompletionBlock:request requestId:requestId completionBlock:^(id data, NSError *error) {
NSError * serializationError;
id response = [self.responseDeserializer deserialize:data class:responseType error:&serializationError];
if(!response && !error){
error = serializationError;
}
completionBlock(response, error);
}];
}
return requestId;
}
//Added for easier override to modify request
-(void)postProcessRequest:(NSMutableURLRequest *)request {
// Always disable cookies!
[request setHTTPShouldHandleCookies:NO];
}
#pragma mark -
- (NSString*) pathWithQueryParamsToString:(NSString*) path
queryParams:(NSDictionary*) queryParams {
if(queryParams.count == 0) {
return path;
}
NSString * separator = nil;
NSUInteger counter = 0;
NSMutableString * requestUrl = [NSMutableString stringWithFormat:@"%@", path];
NSDictionary *separatorStyles = @{@"csv" : @",",
@"tsv" : @"\t",
@"pipes": @"|"
};
for(NSString * key in [queryParams keyEnumerator]){
if (counter == 0) {
separator = @"?";
} else {
separator = @"&";
}
id queryParam = [queryParams valueForKey:key];
if(!queryParam) {
continue;
}
NSString *safeKey = {{classPrefix}}PercentEscapedStringFromString(key);
if ([queryParam isKindOfClass:[NSString class]]){
[requestUrl appendString:[NSString stringWithFormat:@"%@%@=%@", separator, safeKey, {{classPrefix}}PercentEscapedStringFromString(queryParam)]];
} else if ([queryParam isKindOfClass:[{{classPrefix}}QueryParamCollection class]]){
{{classPrefix}}QueryParamCollection * coll = ({{classPrefix}}QueryParamCollection*) queryParam;
NSArray* values = [coll values];
NSString* format = [coll format];
if([format isEqualToString:@"multi"]) {
for(id obj in values) {
if (counter > 0) {
separator = @"&";
}
NSString * safeValue = {{classPrefix}}PercentEscapedStringFromString([NSString stringWithFormat:@"%@",obj]);
[requestUrl appendString:[NSString stringWithFormat:@"%@%@=%@", separator, safeKey, safeValue]];
counter += 1;
}
continue;
}
NSString * separatorStyle = separatorStyles[format];
NSString * safeValue = {{classPrefix}}PercentEscapedStringFromString([values componentsJoinedByString:separatorStyle]);
[requestUrl appendString:[NSString stringWithFormat:@"%@%@=%@", separator, safeKey, safeValue]];
} else {
NSString * safeValue = {{classPrefix}}PercentEscapedStringFromString([NSString stringWithFormat:@"%@",queryParam]);
[requestUrl appendString:[NSString stringWithFormat:@"%@%@=%@", separator, safeKey, safeValue]];
}
counter += 1;
}
return requestUrl;
}
/**
* Update header and query params based on authentication settings
*/
- (void) updateHeaderParams:(NSDictionary *__autoreleasing *)headers
queryParams:(NSDictionary *__autoreleasing *)querys
WithAuthSettings:(NSArray *)authSettings {
if ([authSettings count] == 0) {
return;
}
NSMutableDictionary *headersWithAuth = [NSMutableDictionary dictionaryWithDictionary:*headers];
NSMutableDictionary *querysWithAuth = [NSMutableDictionary dictionaryWithDictionary:*querys];
NSDictionary* configurationAuthSettings = [[self configuration] authSettings];
for (NSString *auth in authSettings) {
NSDictionary *authSetting = configurationAuthSettings[auth];
if(!authSetting) { // auth setting is set only if the key is non-empty
continue;
}
NSString *type = authSetting[@"in"];
NSString *key = authSetting[@"key"];
NSString *value = authSetting[@"value"];
if ([type isEqualToString:@"header"] && [key length] > 0 ) {
headersWithAuth[key] = value;
} else if ([type isEqualToString:@"query"] && [key length] != 0) {
querysWithAuth[key] = value;
}
}
*headers = [NSDictionary dictionaryWithDictionary:headersWithAuth];
*querys = [NSDictionary dictionaryWithDictionary:querysWithAuth];
}
- (AFSecurityPolicy *) customSecurityPolicy {
AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeNone];
{{classPrefix}}Configuration *config = [self configuration];
if (config.sslCaCert) {
NSData *certData = [NSData dataWithContentsOfFile:config.sslCaCert];
[securityPolicy setPinnedCertificates:@[certData]];
}
if (config.verifySSL) {
[securityPolicy setAllowInvalidCertificates:NO];
}
else {
[securityPolicy setAllowInvalidCertificates:YES];
[securityPolicy setValidatesDomainName:NO];
}
return securityPolicy;
}
- ({{classPrefix}}Configuration*) configuration {
return [{{classPrefix}}Configuration sharedConfig];
}
@end