From fa7d3c9bad8a559973cc40bca52d01321b996110 Mon Sep 17 00:00:00 2001 From: Mateusz Mackowiak Date: Tue, 10 May 2016 22:06:50 +0200 Subject: [PATCH 1/3] [Objc] - Moved Logging to separate Logger file - Moved selectHeaderAccept and selectHeaderContentType to sanitizer - little optimizations --- .../codegen/languages/ObjcClientCodegen.java | 2 + .../resources/objc/ApiClient-body.mustache | 240 +++++------------- .../resources/objc/ApiClient-header.mustache | 52 +--- .../objc/Configuration-body.mustache | 39 ++- .../objc/Configuration-header.mustache | 24 +- .../main/resources/objc/Logger-body.mustache | 74 ++++++ .../resources/objc/Logger-header.mustache | 54 ++++ .../resources/objc/Sanitizer-body.mustache | 80 ++++++ .../resources/objc/Sanitizer-header.mustache | 20 ++ .../src/main/resources/objc/api-body.mustache | 24 +- .../main/resources/objc/git_push.sh.mustache | 0 samples/client/petstore/objc/README.md | 4 +- .../petstore/objc/SwaggerClient.podspec | 2 +- .../objc/SwaggerClient/SWGApiClient.h | 52 +--- .../objc/SwaggerClient/SWGApiClient.m | 240 +++++------------- .../objc/SwaggerClient/SWGConfiguration.h | 24 +- .../objc/SwaggerClient/SWGConfiguration.m | 39 ++- .../petstore/objc/SwaggerClient/SWGLogger.h | 54 ++++ .../petstore/objc/SwaggerClient/SWGLogger.m | 74 ++++++ .../petstore/objc/SwaggerClient/SWGPetApi.m | 164 ++++-------- .../objc/SwaggerClient/SWGSanitizer.h | 20 ++ .../objc/SwaggerClient/SWGSanitizer.m | 80 ++++++ .../petstore/objc/SwaggerClient/SWGStoreApi.m | 84 ++---- .../petstore/objc/SwaggerClient/SWGUserApi.m | 164 ++++-------- .../SwaggerClientTests/Tests/PetApiTest.m | 11 +- .../Tests/SWGApiClientTest.m | 24 +- 26 files changed, 797 insertions(+), 848 deletions(-) create mode 100644 modules/swagger-codegen/src/main/resources/objc/Logger-body.mustache create mode 100644 modules/swagger-codegen/src/main/resources/objc/Logger-header.mustache mode change 100755 => 100644 modules/swagger-codegen/src/main/resources/objc/git_push.sh.mustache create mode 100644 samples/client/petstore/objc/SwaggerClient/SWGLogger.h create mode 100644 samples/client/petstore/objc/SwaggerClient/SWGLogger.m diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/ObjcClientCodegen.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/ObjcClientCodegen.java index 46b6083e2e4..6bb05deb233 100644 --- a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/ObjcClientCodegen.java +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/ObjcClientCodegen.java @@ -242,6 +242,8 @@ public class ObjcClientCodegen extends DefaultCodegen implements CodegenConfig { supportingFiles.add(new SupportingFile("ResponseDeserializer-header.mustache", swaggerFolder, classPrefix + "ResponseDeserializer.h")); supportingFiles.add(new SupportingFile("Sanitizer-body.mustache", swaggerFolder, classPrefix + "Sanitizer.m")); supportingFiles.add(new SupportingFile("Sanitizer-header.mustache", swaggerFolder, classPrefix + "Sanitizer.h")); + supportingFiles.add(new SupportingFile("Logger-body.mustache", swaggerFolder, classPrefix + "Logger.m")); + supportingFiles.add(new SupportingFile("Logger-header.mustache", swaggerFolder, classPrefix + "Logger.h")); supportingFiles.add(new SupportingFile("JSONValueTransformer+ISO8601.m", swaggerFolder, "JSONValueTransformer+ISO8601.m")); supportingFiles.add(new SupportingFile("JSONValueTransformer+ISO8601.h", swaggerFolder, "JSONValueTransformer+ISO8601.h")); supportingFiles.add(new SupportingFile("Configuration-body.mustache", swaggerFolder, classPrefix + "Configuration.m")); diff --git a/modules/swagger-codegen/src/main/resources/objc/ApiClient-body.mustache b/modules/swagger-codegen/src/main/resources/objc/ApiClient-body.mustache index 5afc917e228..6b9d3e841bb 100644 --- a/modules/swagger-codegen/src/main/resources/objc/ApiClient-body.mustache +++ b/modules/swagger-codegen/src/main/resources/objc/ApiClient-body.mustache @@ -2,7 +2,7 @@ NSString *const {{classPrefix}}ResponseObjectErrorKey = @"{{classPrefix}}ResponseObject"; -static long requestId = 0; +static NSUInteger requestId = 0; static bool offlineState = false; static NSMutableSet * queuedRequests = nil; static bool cacheEnabled = false; @@ -36,7 +36,7 @@ static NSString * {{classPrefix}}__fileNameForResponse(NSURLResponse *response) @interface {{classPrefix}}ApiClient () -@property (readwrite, nonatomic) NSDictionary *HTTPResponseHeaders; +@property (nonatomic, strong) NSDictionary* HTTPResponseHeaders; @end @@ -88,49 +88,6 @@ static NSString * {{classPrefix}}__fileNameForResponse(NSURLResponse *response) [self.requestSerializer setValue:value forHTTPHeaderField:forKey]; } -#pragma mark - Log Methods - -+ (void)debugLog:(NSString *)method - message:(NSString *)format, ... { - {{classPrefix}}Configuration *config = [{{classPrefix}}Configuration sharedConfig]; - if (!config.debug) { - return; - } - - NSMutableString *message = [NSMutableString stringWithCapacity:1]; - - if (method) { - [message appendString:[NSString stringWithFormat:@"%@: ", method]]; - } - - va_list args; - va_start(args, format); - - [message appendString:[[NSString alloc] initWithFormat:format arguments:args]]; - - // If set logging file handler, log into file, - // otherwise log into console. - if (config.loggingFileHanlder) { - [config.loggingFileHanlder seekToEndOfFile]; - [config.loggingFileHanlder writeData:[message dataUsingEncoding:NSUTF8StringEncoding]]; - } - else { - NSLog(@"%@", message); - } - - va_end(args); -} - -- (void)logResponse:(NSURLResponse *)response responseObject:(id)responseObject request:(NSURLRequest *)request error:(NSError *)error { - - NSString *message = [NSString stringWithFormat:@"\n[DEBUG] HTTP request body \n~BEGIN~\n %@\n~END~\n"\ - "[DEBUG] HTTP response body \n~BEGIN~\n %@\n~END~\n", - [[NSString alloc] initWithData:request.HTTPBody encoding:NSUTF8StringEncoding], - responseObject]; - - {{classPrefix}}DebugLog(message); -} - #pragma mark - Cache Methods +(void)clearCache { @@ -151,70 +108,6 @@ static NSString * {{classPrefix}}__fileNameForResponse(NSURLResponse *response) [NSURLCache setSharedURLCache:cache]; } -#pragma mark - Utility Methods - -/* - * Detect `Accept` from accepts - */ -+ (NSString *) selectHeaderAccept:(NSArray *)accepts { - if (accepts == nil || [accepts count] == 0) { - return @""; - } - - NSMutableArray *lowerAccepts = [[NSMutableArray alloc] initWithCapacity:[accepts count]]; - for (NSString *string in accepts) { - NSString * lowerAccept = [string lowercaseString]; - // use rangeOfString instead of containsString for iOS 7 support - if ([lowerAccept rangeOfString:@"application/json"].location != NSNotFound) { - return @"application/json"; - } - [lowerAccepts addObject:lowerAccept]; - } - - if (lowerAccepts.count == 1) { - return [lowerAccepts firstObject]; - } - - return [lowerAccepts componentsJoinedByString:@", "]; -} - -/* - * Detect `Content-Type` from contentTypes - */ -+ (NSString *) selectHeaderContentType:(NSArray *)contentTypes -{ - if (contentTypes == nil || [contentTypes count] == 0) { - return @"application/json"; - } - - NSMutableArray *lowerContentTypes = [[NSMutableArray alloc] initWithCapacity:[contentTypes count]]; - [contentTypes enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { - [lowerContentTypes addObject:[obj lowercaseString]]; - }]; - - if ([lowerContentTypes containsObject:@"application/json"]) { - return @"application/json"; - } - else { - return lowerContentTypes[0]; - } -} - -+ (NSString*)escape:(id)unescaped { - if ([unescaped isKindOfClass:[NSString class]]){ - return (NSString *)CFBridgingRelease - (CFURLCreateStringByAddingPercentEscapes( - NULL, - (__bridge CFStringRef) unescaped, - NULL, - (CFStringRef)@"!*'();:@&=+$,/?%#[]", - kCFStringEncodingUTF8)); - } - else { - return [NSString stringWithFormat:@"%@", unescaped]; - } -} - #pragma mark - Request Methods +(unsigned long)requestQueueSize { @@ -223,14 +116,12 @@ static NSString * {{classPrefix}}__fileNameForResponse(NSURLResponse *response) +(NSNumber*) nextRequestId { @synchronized(self) { - long nextId = ++requestId; - {{classPrefix}}DebugLog(@"got id %ld", nextId); - return [NSNumber numberWithLong:nextId]; + return @(++requestId); } } +(NSNumber*) queueRequest { - NSNumber* requestId = [{{classPrefix}}ApiClient nextRequestId]; + NSNumber* requestId = [[self class] nextRequestId]; {{classPrefix}}DebugLog(@"added %@ to request queue", requestId); [queuedRequests addObject:requestId]; return requestId; @@ -294,7 +185,7 @@ static NSString * {{classPrefix}}__fileNameForResponse(NSURLResponse *response) if (![strongSelf executeRequestWithId:requestId]) { return; } - [strongSelf logResponse:response responseObject:responseObject request:request error:error]; + {{classPrefix}}DebugLogResponse(response, responseObject,request,error); strongSelf.HTTPResponseHeaders = {{classPrefix}}__headerFieldsForResponse(response); if(!error) { completionBlock(responseObject, nil); @@ -321,7 +212,7 @@ static NSString * {{classPrefix}}__fileNameForResponse(NSURLResponse *response) return; } strongSelf.HTTPResponseHeaders = {{classPrefix}}__headerFieldsForResponse(response); - [strongSelf logResponse:response responseObject:responseObject request:request error:error]; + {{classPrefix}}DebugLogResponse(response, responseObject,request,error); if(error) { NSMutableDictionary *userInfo = [error.userInfo mutableCopy]; if (responseObject) { @@ -370,14 +261,13 @@ static NSString * {{classPrefix}}__fileNameForResponse(NSURLResponse *response) self.requestSerializer = [AFHTTPRequestSerializer serializer]; } else { - NSAssert(false, @"unsupport request type %@", requestContentType); + NSAssert(NO, @"Unsupported request type %@", requestContentType); } // setting response serializer if ([responseContentType isEqualToString:@"application/json"]) { self.responseSerializer = [{{classPrefix}}JSONResponseSerializer serializer]; - } - else { + } else { self.responseSerializer = [AFHTTPResponseSerializer serializer]; } @@ -393,8 +283,9 @@ static NSString * {{classPrefix}}__fileNameForResponse(NSURLResponse *response) NSMutableString *resourcePath = [NSMutableString stringWithString:path]; [pathParams enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { - [resourcePath replaceCharactersInRange:[resourcePath rangeOfString:[NSString stringWithFormat:@"%@%@%@", @"{", key, @"}"]] - withString:[{{classPrefix}}ApiClient escape:obj]]; + 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; @@ -489,55 +380,56 @@ static NSString * {{classPrefix}}__fileNameForResponse(NSURLResponse *response) - (NSString*) pathWithQueryParamsToString:(NSString*) path queryParams:(NSDictionary*) queryParams { + if(queryParams.count == 0) { + return path; + } NSString * separator = nil; - int counter = 0; + NSUInteger counter = 0; NSMutableString * requestUrl = [NSMutableString stringWithFormat:@"%@", path]; - if (queryParams != nil){ - for(NSString * key in [queryParams keyEnumerator]){ - if (counter == 0) separator = @"?"; - else separator = @"&"; - id queryParam = [queryParams valueForKey:key]; - if ([queryParam isKindOfClass:[NSString class]]){ - [requestUrl appendString:[NSString stringWithFormat:@"%@%@=%@", separator, - [{{classPrefix}}ApiClient escape:key], [{{classPrefix}}ApiClient escape:[queryParams valueForKey:key]]]]; - } - else if ([queryParam isKindOfClass:[{{classPrefix}}QueryParamCollection class]]){ - {{classPrefix}}QueryParamCollection * coll = ({{classPrefix}}QueryParamCollection*) queryParam; - NSArray* values = [coll values]; - NSString* format = [coll format]; - if ([format isEqualToString:@"csv"]) { - [requestUrl appendString:[NSString stringWithFormat:@"%@%@=%@", separator, - [{{classPrefix}}ApiClient escape:key], [NSString stringWithFormat:@"%@", [values componentsJoinedByString:@","]]]]; - - } - else if ([format isEqualToString:@"tsv"]) { - [requestUrl appendString:[NSString stringWithFormat:@"%@%@=%@", separator, - [{{classPrefix}}ApiClient escape:key], [NSString stringWithFormat:@"%@", [values componentsJoinedByString:@"\t"]]]]; - - } - else if ([format isEqualToString:@"pipes"]) { - [requestUrl appendString:[NSString stringWithFormat:@"%@%@=%@", separator, - [{{classPrefix}}ApiClient escape:key], [NSString stringWithFormat:@"%@", [values componentsJoinedByString:@"|"]]]]; - - } - else if ([format isEqualToString:@"multi"]) { - for(id obj in values) { - [requestUrl appendString:[NSString stringWithFormat:@"%@%@=%@", separator, - [{{classPrefix}}ApiClient escape:key], [NSString stringWithFormat:@"%@", obj]]]; - counter += 1; - } - - } - } - else { - [requestUrl appendString:[NSString stringWithFormat:@"%@%@=%@", separator, - [{{classPrefix}}ApiClient escape:key], [NSString stringWithFormat:@"%@", [queryParams valueForKey:key]]]]; - } - - counter += 1; + 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; } @@ -558,15 +450,17 @@ static NSString * {{classPrefix}}__fileNameForResponse(NSURLResponse *response) {{classPrefix}}Configuration *config = [{{classPrefix}}Configuration sharedConfig]; for (NSString *auth in authSettings) { - NSDictionary *authSetting = [[config authSettings] objectForKey:auth]; - - if (authSetting) { // auth setting is set only if the key is non-empty - if ([authSetting[@"in"] isEqualToString:@"header"] && [authSetting[@"key"] length] != 0) { - [headersWithAuth setObject:authSetting[@"value"] forKey:authSetting[@"key"]]; - } - else if ([authSetting[@"in"] isEqualToString:@"query"] && [authSetting[@"key"] length] != 0) { - [querysWithAuth setObject:authSetting[@"value"] forKey:authSetting[@"key"]]; - } + NSDictionary *authSetting = [config authSettings][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; } } diff --git a/modules/swagger-codegen/src/main/resources/objc/ApiClient-header.mustache b/modules/swagger-codegen/src/main/resources/objc/ApiClient-header.mustache index b08112ba445..28d5b92f628 100644 --- a/modules/swagger-codegen/src/main/resources/objc/ApiClient-header.mustache +++ b/modules/swagger-codegen/src/main/resources/objc/ApiClient-header.mustache @@ -7,6 +7,7 @@ #import "{{classPrefix}}Configuration.h" #import "{{classPrefix}}ResponseDeserializer.h" #import "{{classPrefix}}Sanitizer.h" +#import "{{classPrefix}}Logger.h" /** * NOTE: This class is auto generated by the swagger code generator program. * https://github.com/swagger-api/swagger-codegen @@ -26,13 +27,6 @@ */ extern NSString *const {{classPrefix}}ResponseObjectErrorKey; -/** - * Log debug message macro - */ -#ifndef {{classPrefix}}DebugLog - #define {{classPrefix}}DebugLog(format, ...) [{{classPrefix}}ApiClient debugLog:[NSString stringWithFormat:@"%s", __PRETTY_FUNCTION__] message: format, ##__VA_ARGS__]; -#endif - @interface {{classPrefix}}ApiClient : AFHTTPSessionManager @property(nonatomic, assign) NSURLRequestCachePolicy cachePolicy; @@ -113,15 +107,6 @@ extern NSString *const {{classPrefix}}ResponseObjectErrorKey; */ +(void) cancelRequest:(NSNumber*)requestId; -/** - * Gets URL encoded NSString - * - * @param unescaped The string which will be escaped. - * - * @return The escaped string. - */ -+(NSString*) escape:(id)unescaped; - /** * Customizes the behavior when the reachability changed * @@ -134,24 +119,6 @@ extern NSString *const {{classPrefix}}ResponseObjectErrorKey; */ - (void)configureCacheReachibility; -/** - * Detects Accept header from accepts NSArray - * - * @param accepts NSArray of header - * - * @return The Accept header - */ -+(NSString *) selectHeaderAccept:(NSArray *)accepts; - -/** - * Detects Content-Type header from contentTypes NSArray - * - * @param contentTypes NSArray of header - * - * @return The Content-Type header - */ -+(NSString *) selectHeaderContentType:(NSArray *)contentTypes; - /** * Sets header for request * @@ -172,19 +139,6 @@ extern NSString *const {{classPrefix}}ResponseObjectErrorKey; queryParams:(NSDictionary **)querys WithAuthSettings:(NSArray *)authSettings; -/** - * Logs request and response - * - * @param response NSURLResponse for the HTTP request. - * @param responseObject response object of the HTTP request. - * @param request The HTTP request. - * @param error The error of the HTTP request. - */ -- (void)logResponse:(NSURLResponse *)response - responseObject:(id)responseObject - request:(NSURLRequest *)request - error:(NSError *)error; - /** * Performs request * @@ -222,9 +176,5 @@ extern NSString *const {{classPrefix}}ResponseObjectErrorKey; */ - (AFSecurityPolicy *) customSecurityPolicy; -/** - * Log debug message - */ -+(void)debugLog:(NSString *)method message:(NSString *)format, ...; @end diff --git a/modules/swagger-codegen/src/main/resources/objc/Configuration-body.mustache b/modules/swagger-codegen/src/main/resources/objc/Configuration-body.mustache index 527e16c2b91..99708408d4e 100644 --- a/modules/swagger-codegen/src/main/resources/objc/Configuration-body.mustache +++ b/modules/swagger-codegen/src/main/resources/objc/Configuration-body.mustache @@ -30,12 +30,10 @@ self.username = @""; self.password = @""; self.accessToken= @""; - self.tempFolderPath = nil; - self.debug = NO; self.verifySSL = YES; - self.loggingFile = nil; self.mutableApiKey = [NSMutableDictionary dictionary]; self.mutableApiKeyPrefix = [NSMutableDictionary dictionary]; + self.logger = [{{classPrefix}}Logger sharedLogger]; } return self; } @@ -43,11 +41,13 @@ #pragma mark - Instance Methods - (NSString *) getApiKeyWithPrefix:(NSString *)key { - if ([self.apiKeyPrefix objectForKey:key] && [self.apiKey objectForKey:key] != (id)[NSNull null] && [[self.apiKey objectForKey:key] length] != 0) { // both api key prefix and api key are set - return [NSString stringWithFormat:@"%@ %@", [self.apiKeyPrefix objectForKey:key], [self.apiKey objectForKey:key]]; + NSString *prefix = self.apiKeyPrefix[key]; + NSString *apiKey = self.apiKey[key]; + if (prefix && apiKey != (id)[NSNull null] && apiKey.length > 0) { // both api key prefix and api key are set + return [NSString stringWithFormat:@"%@ %@", prefix, apiKey]; } - else if ([self.apiKey objectForKey:key] != (id)[NSNull null] && [[self.apiKey objectForKey:key] length] != 0) { // only api key, no api key prefix - return [NSString stringWithFormat:@"%@", [self.apiKey objectForKey:key]]; + else if (apiKey != (id)[NSNull null] && apiKey.length > 0) { // only api key, no api key prefix + return [NSString stringWithFormat:@"%@", self.apiKey[key]]; } else { // return empty string if nothing is set return @""; @@ -70,8 +70,7 @@ - (NSString *) getAccessToken { if (self.accessToken.length == 0) { // token not set, return empty string return @""; - } - else { + } else { return [NSString stringWithFormat:@"Bearer %@", self.accessToken]; } } @@ -94,20 +93,6 @@ [self.mutableApiKeyPrefix removeObjectForKey:identifier]; } -- (void) setLoggingFile:(NSString *)loggingFile { - // close old file handler - if ([self.loggingFileHanlder isKindOfClass:[NSFileHandle class]]) { - [self.loggingFileHanlder closeFile]; - } - - _loggingFile = loggingFile; - _loggingFileHanlder = [NSFileHandle fileHandleForWritingAtPath:_loggingFile]; - if (_loggingFileHanlder == nil) { - [[NSFileManager defaultManager] createFileAtPath:_loggingFile contents:nil attributes:nil]; - _loggingFileHanlder = [NSFileHandle fileHandleForWritingAtPath:_loggingFile]; - } -} - #pragma mark - Getter Methods - (NSDictionary *) apiKey { @@ -154,4 +139,12 @@ }; } +-(BOOL)debug { + return self.logger.isEnabled; +} + +-(void)setDebug:(BOOL)debug { + self.logger.enabled = debug; +} + @end diff --git a/modules/swagger-codegen/src/main/resources/objc/Configuration-header.mustache b/modules/swagger-codegen/src/main/resources/objc/Configuration-header.mustache index b77ddfe5dee..c00c7175d2a 100644 --- a/modules/swagger-codegen/src/main/resources/objc/Configuration-header.mustache +++ b/modules/swagger-codegen/src/main/resources/objc/Configuration-header.mustache @@ -1,5 +1,6 @@ #import #import "{{classPrefix}}ApiClient.h" +#import "{{classPrefix}}Logger.h" /** The `{{classPrefix}}Configuration` class manages the configurations for the sdk. * @@ -12,6 +13,11 @@ @interface {{classPrefix}}Configuration : NSObject +/** + * Default api logger + */ +@property (nonatomic, strong) {{classPrefix}}Logger * logger; + /** * Default api client */ @@ -37,7 +43,7 @@ @property (readonly, nonatomic, strong) NSDictionary *apiKeyPrefix; /** - * Usename for HTTP Basic Authentication + * Username for HTTP Basic Authentication */ @property (nonatomic) NSString *username; @@ -56,25 +62,11 @@ */ @property (nonatomic) NSString *tempFolderPath; -/** - * Logging Settings - */ - /** * Debug switch, default false */ @property (nonatomic) BOOL debug; -/** - * Debug file location, default log in console - */ -@property (nonatomic) NSString *loggingFile; - -/** - * Log file handler, this property is used by sdk internally. - */ -@property (nonatomic, readonly) NSFileHandle *loggingFileHanlder; - /** * Gets configuration singleton instance */ @@ -143,7 +135,7 @@ - (NSString *) getAccessToken; /** - * Gets Authentication Setings + * Gets Authentication Settings */ - (NSDictionary *) authSettings; diff --git a/modules/swagger-codegen/src/main/resources/objc/Logger-body.mustache b/modules/swagger-codegen/src/main/resources/objc/Logger-body.mustache new file mode 100644 index 00000000000..9a8f7de2418 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/objc/Logger-body.mustache @@ -0,0 +1,74 @@ +#import "{{classPrefix}}Logger.h" + +@interface {{classPrefix}}Logger () + +@end + +@implementation {{classPrefix}}Logger + ++ (instancetype) sharedLogger { + static {{classPrefix}}Logger *shardLogger = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + shardLogger = [[self alloc] init]; + }); + return shardLogger; +} + +#pragma mark - Log Methods + +- (void)debugLog:(NSString *)method + message:(NSString *)format, ... { + if (!self.isEnabled) { + return; + } + + NSMutableString *message = [NSMutableString stringWithCapacity:1]; + + if (method) { + [message appendFormat:@"%@: ", method]; + } + + va_list args; + va_start(args, format); + + [message appendString:[[NSString alloc] initWithFormat:format arguments:args]]; + + // If set logging file handler, log into file, + // otherwise log into console. + if (self.loggingFileHandler) { + [self.loggingFileHandler seekToEndOfFile]; + [self.loggingFileHandler writeData:[message dataUsingEncoding:NSUTF8StringEncoding]]; + } else { + NSLog(@"%@", message); + } + + va_end(args); +} + +- (void)logResponse:(NSURLResponse *)response responseObject:(id)responseObject request:(NSURLRequest *)request error:(NSError *)error { + NSString *message = [NSString stringWithFormat:@"\n[DEBUG] HTTP request body \n~BEGIN~\n %@\n~END~\n"\ + "[DEBUG] HTTP response body \n~BEGIN~\n %@\n~END~\n", + [[NSString alloc] initWithData:request.HTTPBody encoding:NSUTF8StringEncoding], + responseObject]; + + {{classPrefix}}DebugLog(message); +} + +- (void) setLoggingFile:(NSString *)loggingFile { + if(_loggingFile == loggingFile) { + return; + } + // close old file handler + if ([self.loggingFileHandler isKindOfClass:[NSFileHandle class]]) { + [self.loggingFileHandler closeFile]; + } + _loggingFile = loggingFile; + _loggingFileHandler = [NSFileHandle fileHandleForWritingAtPath:_loggingFile]; + if (_loggingFileHandler == nil) { + [[NSFileManager defaultManager] createFileAtPath:_loggingFile contents:nil attributes:nil]; + _loggingFileHandler = [NSFileHandle fileHandleForWritingAtPath:_loggingFile]; + } +} + +@end diff --git a/modules/swagger-codegen/src/main/resources/objc/Logger-header.mustache b/modules/swagger-codegen/src/main/resources/objc/Logger-header.mustache new file mode 100644 index 00000000000..2070f95ae9f --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/objc/Logger-header.mustache @@ -0,0 +1,54 @@ +#import + +/** + * NOTE: This class is auto generated by the swagger code generator program. + * https://github.com/swagger-api/swagger-codegen + * Do not edit the class manually. + */ + +#ifndef {{classPrefix}}DebugLogResponse +#define {{classPrefix}}DebugLogResponse(response, responseObject,request, error) [[{{classPrefix}}Logger sharedLogger] logResponse:response responseObject:responseObject request:request error:error]; +#endif + +/** + * Log debug message macro + */ +#ifndef {{classPrefix}}DebugLog +#define {{classPrefix}}DebugLog(format, ...) [[{{classPrefix}}Logger sharedLogger] debugLog:[NSString stringWithFormat:@"%s", __PRETTY_FUNCTION__] message: format, ##__VA_ARGS__]; +#endif + +@interface {{classPrefix}}Logger : NSObject + ++(instancetype)sharedLogger; + +/** + * Enabled switch, default NO - default set by {{classPrefix}}Configuration debug property + */ +@property (nonatomic, assign, getter=isEnabled) BOOL enabled; + +/** + * Debug file location, default log in console + */ +@property (nonatomic, strong) NSString *loggingFile; + +/** + * Log file handler, this property is used by sdk internally. + */ +@property (nonatomic, strong, readonly) NSFileHandle *loggingFileHandler; + +/** + * Log debug message + */ +-(void)debugLog:(NSString *)method message:(NSString *)format, ...; + +/** + * Logs request and response + * + * @param response NSURLResponse for the HTTP request. + * @param responseObject response object of the HTTP request. + * @param request The HTTP request. + * @param error The error of the HTTP request. + */ +- (void)logResponse:(NSURLResponse *)response responseObject:(id)responseObject request:(NSURLRequest *)request error:(NSError *)error; + +@end diff --git a/modules/swagger-codegen/src/main/resources/objc/Sanitizer-body.mustache b/modules/swagger-codegen/src/main/resources/objc/Sanitizer-body.mustache index 74b166d75e9..f43e6493d75 100644 --- a/modules/swagger-codegen/src/main/resources/objc/Sanitizer-body.mustache +++ b/modules/swagger-codegen/src/main/resources/objc/Sanitizer-body.mustache @@ -3,6 +3,38 @@ #import "{{classPrefix}}QueryParamCollection.h" #import +NSString * {{classPrefix}}PercentEscapedStringFromString(NSString *string) { + static NSString * const k{{classPrefix}}CharactersGeneralDelimitersToEncode = @":#[]@"; + static NSString * const k{{classPrefix}}CharactersSubDelimitersToEncode = @"!$&'()*+,;="; + + NSMutableCharacterSet * allowedCharacterSet = [[NSCharacterSet URLQueryAllowedCharacterSet] mutableCopy]; + [allowedCharacterSet removeCharactersInString:[k{{classPrefix}}CharactersGeneralDelimitersToEncode stringByAppendingString:k{{classPrefix}}CharactersSubDelimitersToEncode]]; + + static NSUInteger const batchSize = 50; + + NSUInteger index = 0; + NSMutableString *escaped = @"".mutableCopy; + + while (index < string.length) { + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wgnu" + NSUInteger length = MIN(string.length - index, batchSize); + #pragma GCC diagnostic pop + NSRange range = NSMakeRange(index, length); + + // To avoid breaking up character sequences such as 👴🏻👮🏽 + range = [string rangeOfComposedCharacterSequencesForRange:range]; + + NSString *substring = [string substringWithRange:range]; + NSString *encoded = [substring stringByAddingPercentEncodingWithAllowedCharacters:allowedCharacterSet]; + [escaped appendString:encoded]; + + index += range.length; + } + + return escaped; +} + @interface {{classPrefix}}Sanitizer () @end @@ -79,4 +111,52 @@ } } +#pragma mark - Utility Methods + +/* + * Detect `Accept` from accepts + */ +- (NSString *) selectHeaderAccept:(NSArray *)accepts { + if (accepts == nil || [accepts count] == 0) { + return @""; + } + + NSMutableArray *lowerAccepts = [[NSMutableArray alloc] initWithCapacity:[accepts count]]; + for (NSString *string in accepts) { + NSString * lowerAccept = [string lowercaseString]; + // use rangeOfString instead of containsString for iOS 7 support + if ([lowerAccept rangeOfString:@"application/json"].location != NSNotFound) { + return @"application/json"; + } + [lowerAccepts addObject:lowerAccept]; + } + + if (lowerAccepts.count == 1) { + return [lowerAccepts firstObject]; + } + + return [lowerAccepts componentsJoinedByString:@", "]; +} + +/* + * Detect `Content-Type` from contentTypes + */ +- (NSString *) selectHeaderContentType:(NSArray *)contentTypes { + if (contentTypes == nil || [contentTypes count] == 0) { + return @"application/json"; + } + + NSMutableArray *lowerContentTypes = [[NSMutableArray alloc] initWithCapacity:[contentTypes count]]; + [contentTypes enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { + [lowerContentTypes addObject:[obj lowercaseString]]; + }]; + + if ([lowerContentTypes containsObject:@"application/json"]) { + return @"application/json"; + } + else { + return lowerContentTypes[0]; + } +} + @end diff --git a/modules/swagger-codegen/src/main/resources/objc/Sanitizer-header.mustache b/modules/swagger-codegen/src/main/resources/objc/Sanitizer-header.mustache index 706a94c1d0e..cd946661615 100644 --- a/modules/swagger-codegen/src/main/resources/objc/Sanitizer-header.mustache +++ b/modules/swagger-codegen/src/main/resources/objc/Sanitizer-header.mustache @@ -6,6 +6,8 @@ * Do not edit the class manually. */ +extern NSString * {{classPrefix}}PercentEscapedStringFromString(NSString *string); + @protocol {{classPrefix}}Sanitizer /** @@ -20,6 +22,24 @@ */ - (NSString *) parameterToString: (id) param; +/** + * Detects Accept header from accepts NSArray + * + * @param accepts NSArray of header + * + * @return The Accept header + */ +-(NSString *) selectHeaderAccept:(NSArray *)accepts; + +/** + * Detects Content-Type header from contentTypes NSArray + * + * @param contentTypes NSArray of header + * + * @return The Content-Type header + */ +-(NSString *) selectHeaderContentType:(NSArray *)contentTypes; + @end @interface {{classPrefix}}Sanitizer : NSObject <{{classPrefix}}Sanitizer> diff --git a/modules/swagger-codegen/src/main/resources/objc/api-body.mustache b/modules/swagger-codegen/src/main/resources/objc/api-body.mustache index 2a7880d8367..807acc8ed76 100644 --- a/modules/swagger-codegen/src/main/resources/objc/api-body.mustache +++ b/modules/swagger-codegen/src/main/resources/objc/api-body.mustache @@ -15,7 +15,7 @@ static {{classname}}* singletonAPI = nil; #pragma mark - Initialize methods -- (id) init { +- (instancetype) init { self = [super init]; if (self) { {{classPrefix}}Configuration *config = [{{classPrefix}}Configuration sharedConfig]; @@ -28,7 +28,7 @@ static {{classname}}* singletonAPI = nil; return self; } -- (id) initWithApiClient:({{classPrefix}}ApiClient *)apiClient { +- (instancetype) initWithApiClient:({{classPrefix}}ApiClient *)apiClient { self = [super init]; if (self) { self.apiClient = apiClient; @@ -92,9 +92,7 @@ static {{classname}}* singletonAPI = nil; NSMutableString* resourcePath = [NSMutableString stringWithFormat:@"{{path}}"]; // remove format in URL if needed - if ([resourcePath rangeOfString:@".{format}"].location != NSNotFound) { - [resourcePath replaceCharactersInRange: [resourcePath rangeOfString:@".{format}"] withString:@".json"]; - } + [resourcePath replaceOccurrencesOfString:@".{format}" withString:@".json" options:0 range:NSMakeRange(0,resourcePath.length)]; NSMutableDictionary *pathParams = [[NSMutableDictionary alloc] init]; {{#pathParams}} @@ -121,22 +119,16 @@ static {{classname}}* singletonAPI = nil; {{/headerParams}} // HTTP header `Accept` - headerParams[@"Accept"] = [{{classPrefix}}ApiClient selectHeaderAccept:@[{{#produces}}@"{{mediaType}}"{{#hasMore}}, {{/hasMore}}{{/produces}}]]; - if ([headerParams[@"Accept"] length] == 0) { - [headerParams removeObjectForKey:@"Accept"]; + NSString *acceptHeader = [self.apiClient.sanitizer selectHeaderAccept:@[{{#produces}}@"{{mediaType}}"{{#hasMore}}, {{/hasMore}}{{/produces}}]]; + if(acceptHeader.length > 0) { + headerParams[@"Accept"] = acceptHeader; } // response content type - NSString *responseContentType; - if ([headerParams objectForKey:@"Accept"]) { - responseContentType = [headerParams[@"Accept"] componentsSeparatedByString:@", "][0]; - } - else { - responseContentType = @""; - } + NSString *responseContentType = [[acceptHeader componentsSeparatedByString:@", "] firstObject] ?: @""; // request content type - NSString *requestContentType = [{{classPrefix}}ApiClient selectHeaderContentType:@[{{#consumes}}@"{{mediaType}}"{{#hasMore}}, {{/hasMore}}{{/consumes}}]]; + NSString *requestContentType = [self.apiClient.sanitizer selectHeaderContentType:@[{{#consumes}}@"{{mediaType}}"{{#hasMore}}, {{/hasMore}}{{/consumes}}]]; // Authentication setting NSArray *authSettings = @[{{#authMethods}}@"{{name}}"{{#hasMore}}, {{/hasMore}}{{/authMethods}}]; diff --git a/modules/swagger-codegen/src/main/resources/objc/git_push.sh.mustache b/modules/swagger-codegen/src/main/resources/objc/git_push.sh.mustache old mode 100755 new mode 100644 diff --git a/samples/client/petstore/objc/README.md b/samples/client/petstore/objc/README.md index f4b3f2f2f76..d0ae437a93c 100644 --- a/samples/client/petstore/objc/README.md +++ b/samples/client/petstore/objc/README.md @@ -1,12 +1,12 @@ # SwaggerClient -This is a sample server Petstore server. You can find out more about Swagger at http://swagger.io or on irc.freenode.net, #swagger. For this sample, you can use the api key \"special-key\" to test the authorization filters +This is a sample server Petstore server. You can find out more about Swagger at http://swagger.io or on irc.freenode.net, #swagger. For this sample, you can use the api key "special-key" to test the authorization filters This ObjC package is automatically generated by the [Swagger Codegen](https://github.com/swagger-api/swagger-codegen) project: - API version: 1.0.0 - Package version: -- Build date: 2016-05-08T12:06:01.121+02:00 +- Build date: 2016-05-10T17:16:13.387+02:00 - Build package: class io.swagger.codegen.languages.ObjcClientCodegen ## Requirements diff --git a/samples/client/petstore/objc/SwaggerClient.podspec b/samples/client/petstore/objc/SwaggerClient.podspec index 740680eb9e2..87fb2f6e494 100644 --- a/samples/client/petstore/objc/SwaggerClient.podspec +++ b/samples/client/petstore/objc/SwaggerClient.podspec @@ -13,7 +13,7 @@ Pod::Spec.new do |s| s.summary = "Swagger Petstore" s.description = <<-DESC - This is a sample server Petstore server. You can find out more about Swagger at <a href=\"http://swagger.io\">http://swagger.io</a> or on irc.freenode.net, #swagger. For this sample, you can use the api key \"special-key\" to test the authorization filters + This is a sample server Petstore server. You can find out more about Swagger at <a href="http://swagger.io">http://swagger.io</a> or on irc.freenode.net, #swagger. For this sample, you can use the api key "special-key" to test the authorization filters DESC s.platform = :ios, '7.0' diff --git a/samples/client/petstore/objc/SwaggerClient/SWGApiClient.h b/samples/client/petstore/objc/SwaggerClient/SWGApiClient.h index 82472ab20bf..adbb8f15a62 100644 --- a/samples/client/petstore/objc/SwaggerClient/SWGApiClient.h +++ b/samples/client/petstore/objc/SwaggerClient/SWGApiClient.h @@ -7,6 +7,7 @@ #import "SWGConfiguration.h" #import "SWGResponseDeserializer.h" #import "SWGSanitizer.h" +#import "SWGLogger.h" /** * NOTE: This class is auto generated by the swagger code generator program. * https://github.com/swagger-api/swagger-codegen @@ -30,13 +31,6 @@ */ extern NSString *const SWGResponseObjectErrorKey; -/** - * Log debug message macro - */ -#ifndef SWGDebugLog - #define SWGDebugLog(format, ...) [SWGApiClient debugLog:[NSString stringWithFormat:@"%s", __PRETTY_FUNCTION__] message: format, ##__VA_ARGS__]; -#endif - @interface SWGApiClient : AFHTTPSessionManager @property(nonatomic, assign) NSURLRequestCachePolicy cachePolicy; @@ -117,15 +111,6 @@ extern NSString *const SWGResponseObjectErrorKey; */ +(void) cancelRequest:(NSNumber*)requestId; -/** - * Gets URL encoded NSString - * - * @param unescaped The string which will be escaped. - * - * @return The escaped string. - */ -+(NSString*) escape:(id)unescaped; - /** * Customizes the behavior when the reachability changed * @@ -138,24 +123,6 @@ extern NSString *const SWGResponseObjectErrorKey; */ - (void)configureCacheReachibility; -/** - * Detects Accept header from accepts NSArray - * - * @param accepts NSArray of header - * - * @return The Accept header - */ -+(NSString *) selectHeaderAccept:(NSArray *)accepts; - -/** - * Detects Content-Type header from contentTypes NSArray - * - * @param contentTypes NSArray of header - * - * @return The Content-Type header - */ -+(NSString *) selectHeaderContentType:(NSArray *)contentTypes; - /** * Sets header for request * @@ -176,19 +143,6 @@ extern NSString *const SWGResponseObjectErrorKey; queryParams:(NSDictionary **)querys WithAuthSettings:(NSArray *)authSettings; -/** - * Logs request and response - * - * @param response NSURLResponse for the HTTP request. - * @param responseObject response object of the HTTP request. - * @param request The HTTP request. - * @param error The error of the HTTP request. - */ -- (void)logResponse:(NSURLResponse *)response - responseObject:(id)responseObject - request:(NSURLRequest *)request - error:(NSError *)error; - /** * Performs request * @@ -226,9 +180,5 @@ extern NSString *const SWGResponseObjectErrorKey; */ - (AFSecurityPolicy *) customSecurityPolicy; -/** - * Log debug message - */ -+(void)debugLog:(NSString *)method message:(NSString *)format, ...; @end diff --git a/samples/client/petstore/objc/SwaggerClient/SWGApiClient.m b/samples/client/petstore/objc/SwaggerClient/SWGApiClient.m index 1246dff7fca..a6745932320 100644 --- a/samples/client/petstore/objc/SwaggerClient/SWGApiClient.m +++ b/samples/client/petstore/objc/SwaggerClient/SWGApiClient.m @@ -2,7 +2,7 @@ NSString *const SWGResponseObjectErrorKey = @"SWGResponseObject"; -static long requestId = 0; +static NSUInteger requestId = 0; static bool offlineState = false; static NSMutableSet * queuedRequests = nil; static bool cacheEnabled = false; @@ -36,7 +36,7 @@ static NSString * SWG__fileNameForResponse(NSURLResponse *response) { @interface SWGApiClient () -@property (readwrite, nonatomic) NSDictionary *HTTPResponseHeaders; +@property (nonatomic, strong) NSDictionary* HTTPResponseHeaders; @end @@ -88,49 +88,6 @@ static NSString * SWG__fileNameForResponse(NSURLResponse *response) { [self.requestSerializer setValue:value forHTTPHeaderField:forKey]; } -#pragma mark - Log Methods - -+ (void)debugLog:(NSString *)method - message:(NSString *)format, ... { - SWGConfiguration *config = [SWGConfiguration sharedConfig]; - if (!config.debug) { - return; - } - - NSMutableString *message = [NSMutableString stringWithCapacity:1]; - - if (method) { - [message appendString:[NSString stringWithFormat:@"%@: ", method]]; - } - - va_list args; - va_start(args, format); - - [message appendString:[[NSString alloc] initWithFormat:format arguments:args]]; - - // If set logging file handler, log into file, - // otherwise log into console. - if (config.loggingFileHanlder) { - [config.loggingFileHanlder seekToEndOfFile]; - [config.loggingFileHanlder writeData:[message dataUsingEncoding:NSUTF8StringEncoding]]; - } - else { - NSLog(@"%@", message); - } - - va_end(args); -} - -- (void)logResponse:(NSURLResponse *)response responseObject:(id)responseObject request:(NSURLRequest *)request error:(NSError *)error { - - NSString *message = [NSString stringWithFormat:@"\n[DEBUG] HTTP request body \n~BEGIN~\n %@\n~END~\n"\ - "[DEBUG] HTTP response body \n~BEGIN~\n %@\n~END~\n", - [[NSString alloc] initWithData:request.HTTPBody encoding:NSUTF8StringEncoding], - responseObject]; - - SWGDebugLog(message); -} - #pragma mark - Cache Methods +(void)clearCache { @@ -151,70 +108,6 @@ static NSString * SWG__fileNameForResponse(NSURLResponse *response) { [NSURLCache setSharedURLCache:cache]; } -#pragma mark - Utility Methods - -/* - * Detect `Accept` from accepts - */ -+ (NSString *) selectHeaderAccept:(NSArray *)accepts { - if (accepts == nil || [accepts count] == 0) { - return @""; - } - - NSMutableArray *lowerAccepts = [[NSMutableArray alloc] initWithCapacity:[accepts count]]; - for (NSString *string in accepts) { - NSString * lowerAccept = [string lowercaseString]; - // use rangeOfString instead of containsString for iOS 7 support - if ([lowerAccept rangeOfString:@"application/json"].location != NSNotFound) { - return @"application/json"; - } - [lowerAccepts addObject:lowerAccept]; - } - - if (lowerAccepts.count == 1) { - return [lowerAccepts firstObject]; - } - - return [lowerAccepts componentsJoinedByString:@", "]; -} - -/* - * Detect `Content-Type` from contentTypes - */ -+ (NSString *) selectHeaderContentType:(NSArray *)contentTypes -{ - if (contentTypes == nil || [contentTypes count] == 0) { - return @"application/json"; - } - - NSMutableArray *lowerContentTypes = [[NSMutableArray alloc] initWithCapacity:[contentTypes count]]; - [contentTypes enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { - [lowerContentTypes addObject:[obj lowercaseString]]; - }]; - - if ([lowerContentTypes containsObject:@"application/json"]) { - return @"application/json"; - } - else { - return lowerContentTypes[0]; - } -} - -+ (NSString*)escape:(id)unescaped { - if ([unescaped isKindOfClass:[NSString class]]){ - return (NSString *)CFBridgingRelease - (CFURLCreateStringByAddingPercentEscapes( - NULL, - (__bridge CFStringRef) unescaped, - NULL, - (CFStringRef)@"!*'();:@&=+$,/?%#[]", - kCFStringEncodingUTF8)); - } - else { - return [NSString stringWithFormat:@"%@", unescaped]; - } -} - #pragma mark - Request Methods +(unsigned long)requestQueueSize { @@ -223,14 +116,12 @@ static NSString * SWG__fileNameForResponse(NSURLResponse *response) { +(NSNumber*) nextRequestId { @synchronized(self) { - long nextId = ++requestId; - SWGDebugLog(@"got id %ld", nextId); - return [NSNumber numberWithLong:nextId]; + return @(++requestId); } } +(NSNumber*) queueRequest { - NSNumber* requestId = [SWGApiClient nextRequestId]; + NSNumber* requestId = [[self class] nextRequestId]; SWGDebugLog(@"added %@ to request queue", requestId); [queuedRequests addObject:requestId]; return requestId; @@ -294,7 +185,7 @@ static NSString * SWG__fileNameForResponse(NSURLResponse *response) { if (![strongSelf executeRequestWithId:requestId]) { return; } - [strongSelf logResponse:response responseObject:responseObject request:request error:error]; + SWGDebugLogResponse(response, responseObject,request,error); strongSelf.HTTPResponseHeaders = SWG__headerFieldsForResponse(response); if(!error) { completionBlock(responseObject, nil); @@ -321,7 +212,7 @@ static NSString * SWG__fileNameForResponse(NSURLResponse *response) { return; } strongSelf.HTTPResponseHeaders = SWG__headerFieldsForResponse(response); - [strongSelf logResponse:response responseObject:responseObject request:request error:error]; + SWGDebugLogResponse(response, responseObject,request,error); if(error) { NSMutableDictionary *userInfo = [error.userInfo mutableCopy]; if (responseObject) { @@ -370,14 +261,13 @@ static NSString * SWG__fileNameForResponse(NSURLResponse *response) { self.requestSerializer = [AFHTTPRequestSerializer serializer]; } else { - NSAssert(false, @"unsupport request type %@", requestContentType); + NSAssert(NO, @"Unsupported request type %@", requestContentType); } // setting response serializer if ([responseContentType isEqualToString:@"application/json"]) { self.responseSerializer = [SWGJSONResponseSerializer serializer]; - } - else { + } else { self.responseSerializer = [AFHTTPResponseSerializer serializer]; } @@ -393,8 +283,9 @@ static NSString * SWG__fileNameForResponse(NSURLResponse *response) { NSMutableString *resourcePath = [NSMutableString stringWithString:path]; [pathParams enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { - [resourcePath replaceCharactersInRange:[resourcePath rangeOfString:[NSString stringWithFormat:@"%@%@%@", @"{", key, @"}"]] - withString:[SWGApiClient escape:obj]]; + NSString * safeString = ([obj isKindOfClass:[NSString class]]) ? obj : [NSString stringWithFormat:@"%@", obj]; + safeString = SWGPercentEscapedStringFromString(safeString); + [resourcePath replaceCharactersInRange:[resourcePath rangeOfString:[NSString stringWithFormat:@"{%@}", key]] withString:safeString]; }]; NSMutableURLRequest * request = nil; @@ -489,55 +380,56 @@ static NSString * SWG__fileNameForResponse(NSURLResponse *response) { - (NSString*) pathWithQueryParamsToString:(NSString*) path queryParams:(NSDictionary*) queryParams { + if(queryParams.count == 0) { + return path; + } NSString * separator = nil; - int counter = 0; + NSUInteger counter = 0; NSMutableString * requestUrl = [NSMutableString stringWithFormat:@"%@", path]; - if (queryParams != nil){ - for(NSString * key in [queryParams keyEnumerator]){ - if (counter == 0) separator = @"?"; - else separator = @"&"; - id queryParam = [queryParams valueForKey:key]; - if ([queryParam isKindOfClass:[NSString class]]){ - [requestUrl appendString:[NSString stringWithFormat:@"%@%@=%@", separator, - [SWGApiClient escape:key], [SWGApiClient escape:[queryParams valueForKey:key]]]]; - } - else if ([queryParam isKindOfClass:[SWGQueryParamCollection class]]){ - SWGQueryParamCollection * coll = (SWGQueryParamCollection*) queryParam; - NSArray* values = [coll values]; - NSString* format = [coll format]; - if ([format isEqualToString:@"csv"]) { - [requestUrl appendString:[NSString stringWithFormat:@"%@%@=%@", separator, - [SWGApiClient escape:key], [NSString stringWithFormat:@"%@", [values componentsJoinedByString:@","]]]]; - - } - else if ([format isEqualToString:@"tsv"]) { - [requestUrl appendString:[NSString stringWithFormat:@"%@%@=%@", separator, - [SWGApiClient escape:key], [NSString stringWithFormat:@"%@", [values componentsJoinedByString:@"\t"]]]]; - - } - else if ([format isEqualToString:@"pipes"]) { - [requestUrl appendString:[NSString stringWithFormat:@"%@%@=%@", separator, - [SWGApiClient escape:key], [NSString stringWithFormat:@"%@", [values componentsJoinedByString:@"|"]]]]; - - } - else if ([format isEqualToString:@"multi"]) { - for(id obj in values) { - [requestUrl appendString:[NSString stringWithFormat:@"%@%@=%@", separator, - [SWGApiClient escape:key], [NSString stringWithFormat:@"%@", obj]]]; - counter += 1; - } - - } - } - else { - [requestUrl appendString:[NSString stringWithFormat:@"%@%@=%@", separator, - [SWGApiClient escape:key], [NSString stringWithFormat:@"%@", [queryParams valueForKey:key]]]]; - } - - counter += 1; + 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 = SWGPercentEscapedStringFromString(key); + if ([queryParam isKindOfClass:[NSString class]]){ + [requestUrl appendString:[NSString stringWithFormat:@"%@%@=%@", separator, safeKey, SWGPercentEscapedStringFromString(queryParam)]]; + + } else if ([queryParam isKindOfClass:[SWGQueryParamCollection class]]){ + SWGQueryParamCollection * coll = (SWGQueryParamCollection*) queryParam; + NSArray* values = [coll values]; + NSString* format = [coll format]; + + if([format isEqualToString:@"multi"]) { + for(id obj in values) { + if (counter > 0) { + separator = @"&"; + } + NSString * safeValue = SWGPercentEscapedStringFromString([NSString stringWithFormat:@"%@",obj]); + [requestUrl appendString:[NSString stringWithFormat:@"%@%@=%@", separator, safeKey, safeValue]]; + counter += 1; + } + continue; + } + NSString * separatorStyle = separatorStyles[format]; + NSString * safeValue = SWGPercentEscapedStringFromString([values componentsJoinedByString:separatorStyle]); + [requestUrl appendString:[NSString stringWithFormat:@"%@%@=%@", separator, safeKey, safeValue]]; + } else { + NSString * safeValue = SWGPercentEscapedStringFromString([NSString stringWithFormat:@"%@",queryParam]); + [requestUrl appendString:[NSString stringWithFormat:@"%@%@=%@", separator, safeKey, safeValue]]; + } + counter += 1; } return requestUrl; } @@ -558,15 +450,17 @@ static NSString * SWG__fileNameForResponse(NSURLResponse *response) { SWGConfiguration *config = [SWGConfiguration sharedConfig]; for (NSString *auth in authSettings) { - NSDictionary *authSetting = [[config authSettings] objectForKey:auth]; - - if (authSetting) { // auth setting is set only if the key is non-empty - if ([authSetting[@"in"] isEqualToString:@"header"] && [authSetting[@"key"] length] != 0) { - [headersWithAuth setObject:authSetting[@"value"] forKey:authSetting[@"key"]]; - } - else if ([authSetting[@"in"] isEqualToString:@"query"] && [authSetting[@"key"] length] != 0) { - [querysWithAuth setObject:authSetting[@"value"] forKey:authSetting[@"key"]]; - } + NSDictionary *authSetting = [config authSettings][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; } } diff --git a/samples/client/petstore/objc/SwaggerClient/SWGConfiguration.h b/samples/client/petstore/objc/SwaggerClient/SWGConfiguration.h index 27cfe5d6d24..056175019a4 100644 --- a/samples/client/petstore/objc/SwaggerClient/SWGConfiguration.h +++ b/samples/client/petstore/objc/SwaggerClient/SWGConfiguration.h @@ -1,5 +1,6 @@ #import #import "SWGApiClient.h" +#import "SWGLogger.h" /** The `SWGConfiguration` class manages the configurations for the sdk. * @@ -12,6 +13,11 @@ @interface SWGConfiguration : NSObject +/** + * Default api logger + */ +@property (nonatomic, strong) SWGLogger * logger; + /** * Default api client */ @@ -37,7 +43,7 @@ @property (readonly, nonatomic, strong) NSDictionary *apiKeyPrefix; /** - * Usename for HTTP Basic Authentication + * Username for HTTP Basic Authentication */ @property (nonatomic) NSString *username; @@ -56,25 +62,11 @@ */ @property (nonatomic) NSString *tempFolderPath; -/** - * Logging Settings - */ - /** * Debug switch, default false */ @property (nonatomic) BOOL debug; -/** - * Debug file location, default log in console - */ -@property (nonatomic) NSString *loggingFile; - -/** - * Log file handler, this property is used by sdk internally. - */ -@property (nonatomic, readonly) NSFileHandle *loggingFileHanlder; - /** * Gets configuration singleton instance */ @@ -143,7 +135,7 @@ - (NSString *) getAccessToken; /** - * Gets Authentication Setings + * Gets Authentication Settings */ - (NSDictionary *) authSettings; diff --git a/samples/client/petstore/objc/SwaggerClient/SWGConfiguration.m b/samples/client/petstore/objc/SwaggerClient/SWGConfiguration.m index dd1596bf8ce..b2430daaecd 100644 --- a/samples/client/petstore/objc/SwaggerClient/SWGConfiguration.m +++ b/samples/client/petstore/objc/SwaggerClient/SWGConfiguration.m @@ -30,12 +30,10 @@ self.username = @""; self.password = @""; self.accessToken= @""; - self.tempFolderPath = nil; - self.debug = NO; self.verifySSL = YES; - self.loggingFile = nil; self.mutableApiKey = [NSMutableDictionary dictionary]; self.mutableApiKeyPrefix = [NSMutableDictionary dictionary]; + self.logger = [SWGLogger sharedLogger]; } return self; } @@ -43,11 +41,13 @@ #pragma mark - Instance Methods - (NSString *) getApiKeyWithPrefix:(NSString *)key { - if ([self.apiKeyPrefix objectForKey:key] && [self.apiKey objectForKey:key] != (id)[NSNull null] && [[self.apiKey objectForKey:key] length] != 0) { // both api key prefix and api key are set - return [NSString stringWithFormat:@"%@ %@", [self.apiKeyPrefix objectForKey:key], [self.apiKey objectForKey:key]]; + NSString *prefix = self.apiKeyPrefix[key]; + NSString *apiKey = self.apiKey[key]; + if (prefix && apiKey != (id)[NSNull null] && apiKey.length > 0) { // both api key prefix and api key are set + return [NSString stringWithFormat:@"%@ %@", prefix, apiKey]; } - else if ([self.apiKey objectForKey:key] != (id)[NSNull null] && [[self.apiKey objectForKey:key] length] != 0) { // only api key, no api key prefix - return [NSString stringWithFormat:@"%@", [self.apiKey objectForKey:key]]; + else if (apiKey != (id)[NSNull null] && apiKey.length > 0) { // only api key, no api key prefix + return [NSString stringWithFormat:@"%@", self.apiKey[key]]; } else { // return empty string if nothing is set return @""; @@ -70,8 +70,7 @@ - (NSString *) getAccessToken { if (self.accessToken.length == 0) { // token not set, return empty string return @""; - } - else { + } else { return [NSString stringWithFormat:@"Bearer %@", self.accessToken]; } } @@ -94,20 +93,6 @@ [self.mutableApiKeyPrefix removeObjectForKey:identifier]; } -- (void) setLoggingFile:(NSString *)loggingFile { - // close old file handler - if ([self.loggingFileHanlder isKindOfClass:[NSFileHandle class]]) { - [self.loggingFileHanlder closeFile]; - } - - _loggingFile = loggingFile; - _loggingFileHanlder = [NSFileHandle fileHandleForWritingAtPath:_loggingFile]; - if (_loggingFileHanlder == nil) { - [[NSFileManager defaultManager] createFileAtPath:_loggingFile contents:nil attributes:nil]; - _loggingFileHanlder = [NSFileHandle fileHandleForWritingAtPath:_loggingFile]; - } -} - #pragma mark - Getter Methods - (NSDictionary *) apiKey { @@ -139,4 +124,12 @@ }; } +-(BOOL)debug { + return self.logger.isEnabled; +} + +-(void)setDebug:(BOOL)debug { + self.logger.enabled = debug; +} + @end diff --git a/samples/client/petstore/objc/SwaggerClient/SWGLogger.h b/samples/client/petstore/objc/SwaggerClient/SWGLogger.h new file mode 100644 index 00000000000..19c1e509dfa --- /dev/null +++ b/samples/client/petstore/objc/SwaggerClient/SWGLogger.h @@ -0,0 +1,54 @@ +#import + +/** + * NOTE: This class is auto generated by the swagger code generator program. + * https://github.com/swagger-api/swagger-codegen + * Do not edit the class manually. + */ + +#ifndef SWGDebugLogResponse +#define SWGDebugLogResponse(response, responseObject,request, error) [[SWGLogger sharedLogger] logResponse:response responseObject:responseObject request:request error:error]; +#endif + +/** + * Log debug message macro + */ +#ifndef SWGDebugLog +#define SWGDebugLog(format, ...) [[SWGLogger sharedLogger] debugLog:[NSString stringWithFormat:@"%s", __PRETTY_FUNCTION__] message: format, ##__VA_ARGS__]; +#endif + +@interface SWGLogger : NSObject + ++(instancetype)sharedLogger; + +/** + * Enabled switch, default NO - default set by SWGConfiguration debug property + */ +@property (nonatomic, assign, getter=isEnabled) BOOL enabled; + +/** + * Debug file location, default log in console + */ +@property (nonatomic, strong) NSString *loggingFile; + +/** + * Log file handler, this property is used by sdk internally. + */ +@property (nonatomic, strong, readonly) NSFileHandle *loggingFileHandler; + +/** + * Log debug message + */ +-(void)debugLog:(NSString *)method message:(NSString *)format, ...; + +/** + * Logs request and response + * + * @param response NSURLResponse for the HTTP request. + * @param responseObject response object of the HTTP request. + * @param request The HTTP request. + * @param error The error of the HTTP request. + */ +- (void)logResponse:(NSURLResponse *)response responseObject:(id)responseObject request:(NSURLRequest *)request error:(NSError *)error; + +@end diff --git a/samples/client/petstore/objc/SwaggerClient/SWGLogger.m b/samples/client/petstore/objc/SwaggerClient/SWGLogger.m new file mode 100644 index 00000000000..322ae9678d7 --- /dev/null +++ b/samples/client/petstore/objc/SwaggerClient/SWGLogger.m @@ -0,0 +1,74 @@ +#import "SWGLogger.h" + +@interface SWGLogger () + +@end + +@implementation SWGLogger + ++ (instancetype) sharedLogger { + static SWGLogger *shardLogger = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + shardLogger = [[self alloc] init]; + }); + return shardLogger; +} + +#pragma mark - Log Methods + +- (void)debugLog:(NSString *)method + message:(NSString *)format, ... { + if (!self.isEnabled) { + return; + } + + NSMutableString *message = [NSMutableString stringWithCapacity:1]; + + if (method) { + [message appendFormat:@"%@: ", method]; + } + + va_list args; + va_start(args, format); + + [message appendString:[[NSString alloc] initWithFormat:format arguments:args]]; + + // If set logging file handler, log into file, + // otherwise log into console. + if (self.loggingFileHandler) { + [self.loggingFileHandler seekToEndOfFile]; + [self.loggingFileHandler writeData:[message dataUsingEncoding:NSUTF8StringEncoding]]; + } else { + NSLog(@"%@", message); + } + + va_end(args); +} + +- (void)logResponse:(NSURLResponse *)response responseObject:(id)responseObject request:(NSURLRequest *)request error:(NSError *)error { + NSString *message = [NSString stringWithFormat:@"\n[DEBUG] HTTP request body \n~BEGIN~\n %@\n~END~\n"\ + "[DEBUG] HTTP response body \n~BEGIN~\n %@\n~END~\n", + [[NSString alloc] initWithData:request.HTTPBody encoding:NSUTF8StringEncoding], + responseObject]; + + SWGDebugLog(message); +} + +- (void) setLoggingFile:(NSString *)loggingFile { + if(_loggingFile == loggingFile) { + return; + } + // close old file handler + if ([self.loggingFileHandler isKindOfClass:[NSFileHandle class]]) { + [self.loggingFileHandler closeFile]; + } + _loggingFile = loggingFile; + _loggingFileHandler = [NSFileHandle fileHandleForWritingAtPath:_loggingFile]; + if (_loggingFileHandler == nil) { + [[NSFileManager defaultManager] createFileAtPath:_loggingFile contents:nil attributes:nil]; + _loggingFileHandler = [NSFileHandle fileHandleForWritingAtPath:_loggingFile]; + } +} + +@end diff --git a/samples/client/petstore/objc/SwaggerClient/SWGPetApi.m b/samples/client/petstore/objc/SwaggerClient/SWGPetApi.m index b3ebc31bf68..37b0f9407f7 100644 --- a/samples/client/petstore/objc/SwaggerClient/SWGPetApi.m +++ b/samples/client/petstore/objc/SwaggerClient/SWGPetApi.m @@ -13,7 +13,7 @@ static SWGPetApi* singletonAPI = nil; #pragma mark - Initialize methods -- (id) init { +- (instancetype) init { self = [super init]; if (self) { SWGConfiguration *config = [SWGConfiguration sharedConfig]; @@ -26,7 +26,7 @@ static SWGPetApi* singletonAPI = nil; return self; } -- (id) initWithApiClient:(SWGApiClient *)apiClient { +- (instancetype) initWithApiClient:(SWGApiClient *)apiClient { self = [super init]; if (self) { self.apiClient = apiClient; @@ -79,31 +79,23 @@ static SWGPetApi* singletonAPI = nil; NSMutableString* resourcePath = [NSMutableString stringWithFormat:@"/pet"]; // remove format in URL if needed - if ([resourcePath rangeOfString:@".{format}"].location != NSNotFound) { - [resourcePath replaceCharactersInRange: [resourcePath rangeOfString:@".{format}"] withString:@".json"]; - } + [resourcePath replaceOccurrencesOfString:@".{format}" withString:@".json" options:0 range:NSMakeRange(0,resourcePath.length)]; NSMutableDictionary *pathParams = [[NSMutableDictionary alloc] init]; NSMutableDictionary* queryParams = [[NSMutableDictionary alloc] init]; NSMutableDictionary* headerParams = [NSMutableDictionary dictionaryWithDictionary:self.defaultHeaders]; // HTTP header `Accept` - headerParams[@"Accept"] = [SWGApiClient selectHeaderAccept:@[@"application/json", @"application/xml"]]; - if ([headerParams[@"Accept"] length] == 0) { - [headerParams removeObjectForKey:@"Accept"]; + NSString *acceptHeader = [self.apiClient.sanitizer selectHeaderAccept:@[@"application/json", @"application/xml"]]; + if(acceptHeader.length > 0) { + headerParams[@"Accept"] = acceptHeader; } // response content type - NSString *responseContentType; - if ([headerParams objectForKey:@"Accept"]) { - responseContentType = [headerParams[@"Accept"] componentsSeparatedByString:@", "][0]; - } - else { - responseContentType = @""; - } + NSString *responseContentType = [[acceptHeader componentsSeparatedByString:@", "] firstObject] ?: @""; // request content type - NSString *requestContentType = [SWGApiClient selectHeaderContentType:@[@"application/json", @"application/xml"]]; + NSString *requestContentType = [self.apiClient.sanitizer selectHeaderContentType:@[@"application/json", @"application/xml"]]; // Authentication setting NSArray *authSettings = @[@"petstore_auth"]; @@ -151,9 +143,7 @@ static SWGPetApi* singletonAPI = nil; NSMutableString* resourcePath = [NSMutableString stringWithFormat:@"/pet/{petId}"]; // remove format in URL if needed - if ([resourcePath rangeOfString:@".{format}"].location != NSNotFound) { - [resourcePath replaceCharactersInRange: [resourcePath rangeOfString:@".{format}"] withString:@".json"]; - } + [resourcePath replaceOccurrencesOfString:@".{format}" withString:@".json" options:0 range:NSMakeRange(0,resourcePath.length)]; NSMutableDictionary *pathParams = [[NSMutableDictionary alloc] init]; if (petId != nil) { @@ -168,22 +158,16 @@ static SWGPetApi* singletonAPI = nil; } // HTTP header `Accept` - headerParams[@"Accept"] = [SWGApiClient selectHeaderAccept:@[@"application/json", @"application/xml"]]; - if ([headerParams[@"Accept"] length] == 0) { - [headerParams removeObjectForKey:@"Accept"]; + NSString *acceptHeader = [self.apiClient.sanitizer selectHeaderAccept:@[@"application/json", @"application/xml"]]; + if(acceptHeader.length > 0) { + headerParams[@"Accept"] = acceptHeader; } // response content type - NSString *responseContentType; - if ([headerParams objectForKey:@"Accept"]) { - responseContentType = [headerParams[@"Accept"] componentsSeparatedByString:@", "][0]; - } - else { - responseContentType = @""; - } + NSString *responseContentType = [[acceptHeader componentsSeparatedByString:@", "] firstObject] ?: @""; // request content type - NSString *requestContentType = [SWGApiClient selectHeaderContentType:@[]]; + NSString *requestContentType = [self.apiClient.sanitizer selectHeaderContentType:@[]]; // Authentication setting NSArray *authSettings = @[@"petstore_auth"]; @@ -222,9 +206,7 @@ static SWGPetApi* singletonAPI = nil; NSMutableString* resourcePath = [NSMutableString stringWithFormat:@"/pet/findByStatus"]; // remove format in URL if needed - if ([resourcePath rangeOfString:@".{format}"].location != NSNotFound) { - [resourcePath replaceCharactersInRange: [resourcePath rangeOfString:@".{format}"] withString:@".json"]; - } + [resourcePath replaceOccurrencesOfString:@".{format}" withString:@".json" options:0 range:NSMakeRange(0,resourcePath.length)]; NSMutableDictionary *pathParams = [[NSMutableDictionary alloc] init]; @@ -235,22 +217,16 @@ static SWGPetApi* singletonAPI = nil; } NSMutableDictionary* headerParams = [NSMutableDictionary dictionaryWithDictionary:self.defaultHeaders]; // HTTP header `Accept` - headerParams[@"Accept"] = [SWGApiClient selectHeaderAccept:@[@"application/json", @"application/xml"]]; - if ([headerParams[@"Accept"] length] == 0) { - [headerParams removeObjectForKey:@"Accept"]; + NSString *acceptHeader = [self.apiClient.sanitizer selectHeaderAccept:@[@"application/json", @"application/xml"]]; + if(acceptHeader.length > 0) { + headerParams[@"Accept"] = acceptHeader; } // response content type - NSString *responseContentType; - if ([headerParams objectForKey:@"Accept"]) { - responseContentType = [headerParams[@"Accept"] componentsSeparatedByString:@", "][0]; - } - else { - responseContentType = @""; - } + NSString *responseContentType = [[acceptHeader componentsSeparatedByString:@", "] firstObject] ?: @""; // request content type - NSString *requestContentType = [SWGApiClient selectHeaderContentType:@[]]; + NSString *requestContentType = [self.apiClient.sanitizer selectHeaderContentType:@[]]; // Authentication setting NSArray *authSettings = @[@"petstore_auth"]; @@ -289,9 +265,7 @@ static SWGPetApi* singletonAPI = nil; NSMutableString* resourcePath = [NSMutableString stringWithFormat:@"/pet/findByTags"]; // remove format in URL if needed - if ([resourcePath rangeOfString:@".{format}"].location != NSNotFound) { - [resourcePath replaceCharactersInRange: [resourcePath rangeOfString:@".{format}"] withString:@".json"]; - } + [resourcePath replaceOccurrencesOfString:@".{format}" withString:@".json" options:0 range:NSMakeRange(0,resourcePath.length)]; NSMutableDictionary *pathParams = [[NSMutableDictionary alloc] init]; @@ -302,22 +276,16 @@ static SWGPetApi* singletonAPI = nil; } NSMutableDictionary* headerParams = [NSMutableDictionary dictionaryWithDictionary:self.defaultHeaders]; // HTTP header `Accept` - headerParams[@"Accept"] = [SWGApiClient selectHeaderAccept:@[@"application/json", @"application/xml"]]; - if ([headerParams[@"Accept"] length] == 0) { - [headerParams removeObjectForKey:@"Accept"]; + NSString *acceptHeader = [self.apiClient.sanitizer selectHeaderAccept:@[@"application/json", @"application/xml"]]; + if(acceptHeader.length > 0) { + headerParams[@"Accept"] = acceptHeader; } // response content type - NSString *responseContentType; - if ([headerParams objectForKey:@"Accept"]) { - responseContentType = [headerParams[@"Accept"] componentsSeparatedByString:@", "][0]; - } - else { - responseContentType = @""; - } + NSString *responseContentType = [[acceptHeader componentsSeparatedByString:@", "] firstObject] ?: @""; // request content type - NSString *requestContentType = [SWGApiClient selectHeaderContentType:@[]]; + NSString *requestContentType = [self.apiClient.sanitizer selectHeaderContentType:@[]]; // Authentication setting NSArray *authSettings = @[@"petstore_auth"]; @@ -361,9 +329,7 @@ static SWGPetApi* singletonAPI = nil; NSMutableString* resourcePath = [NSMutableString stringWithFormat:@"/pet/{petId}"]; // remove format in URL if needed - if ([resourcePath rangeOfString:@".{format}"].location != NSNotFound) { - [resourcePath replaceCharactersInRange: [resourcePath rangeOfString:@".{format}"] withString:@".json"]; - } + [resourcePath replaceOccurrencesOfString:@".{format}" withString:@".json" options:0 range:NSMakeRange(0,resourcePath.length)]; NSMutableDictionary *pathParams = [[NSMutableDictionary alloc] init]; if (petId != nil) { @@ -373,22 +339,16 @@ static SWGPetApi* singletonAPI = nil; NSMutableDictionary* queryParams = [[NSMutableDictionary alloc] init]; NSMutableDictionary* headerParams = [NSMutableDictionary dictionaryWithDictionary:self.defaultHeaders]; // HTTP header `Accept` - headerParams[@"Accept"] = [SWGApiClient selectHeaderAccept:@[@"application/json", @"application/xml"]]; - if ([headerParams[@"Accept"] length] == 0) { - [headerParams removeObjectForKey:@"Accept"]; + NSString *acceptHeader = [self.apiClient.sanitizer selectHeaderAccept:@[@"application/json", @"application/xml"]]; + if(acceptHeader.length > 0) { + headerParams[@"Accept"] = acceptHeader; } // response content type - NSString *responseContentType; - if ([headerParams objectForKey:@"Accept"]) { - responseContentType = [headerParams[@"Accept"] componentsSeparatedByString:@", "][0]; - } - else { - responseContentType = @""; - } + NSString *responseContentType = [[acceptHeader componentsSeparatedByString:@", "] firstObject] ?: @""; // request content type - NSString *requestContentType = [SWGApiClient selectHeaderContentType:@[]]; + NSString *requestContentType = [self.apiClient.sanitizer selectHeaderContentType:@[]]; // Authentication setting NSArray *authSettings = @[@"petstore_auth", @"api_key"]; @@ -427,31 +387,23 @@ static SWGPetApi* singletonAPI = nil; NSMutableString* resourcePath = [NSMutableString stringWithFormat:@"/pet"]; // remove format in URL if needed - if ([resourcePath rangeOfString:@".{format}"].location != NSNotFound) { - [resourcePath replaceCharactersInRange: [resourcePath rangeOfString:@".{format}"] withString:@".json"]; - } + [resourcePath replaceOccurrencesOfString:@".{format}" withString:@".json" options:0 range:NSMakeRange(0,resourcePath.length)]; NSMutableDictionary *pathParams = [[NSMutableDictionary alloc] init]; NSMutableDictionary* queryParams = [[NSMutableDictionary alloc] init]; NSMutableDictionary* headerParams = [NSMutableDictionary dictionaryWithDictionary:self.defaultHeaders]; // HTTP header `Accept` - headerParams[@"Accept"] = [SWGApiClient selectHeaderAccept:@[@"application/json", @"application/xml"]]; - if ([headerParams[@"Accept"] length] == 0) { - [headerParams removeObjectForKey:@"Accept"]; + NSString *acceptHeader = [self.apiClient.sanitizer selectHeaderAccept:@[@"application/json", @"application/xml"]]; + if(acceptHeader.length > 0) { + headerParams[@"Accept"] = acceptHeader; } // response content type - NSString *responseContentType; - if ([headerParams objectForKey:@"Accept"]) { - responseContentType = [headerParams[@"Accept"] componentsSeparatedByString:@", "][0]; - } - else { - responseContentType = @""; - } + NSString *responseContentType = [[acceptHeader componentsSeparatedByString:@", "] firstObject] ?: @""; // request content type - NSString *requestContentType = [SWGApiClient selectHeaderContentType:@[@"application/json", @"application/xml"]]; + NSString *requestContentType = [self.apiClient.sanitizer selectHeaderContentType:@[@"application/json", @"application/xml"]]; // Authentication setting NSArray *authSettings = @[@"petstore_auth"]; @@ -502,9 +454,7 @@ static SWGPetApi* singletonAPI = nil; NSMutableString* resourcePath = [NSMutableString stringWithFormat:@"/pet/{petId}"]; // remove format in URL if needed - if ([resourcePath rangeOfString:@".{format}"].location != NSNotFound) { - [resourcePath replaceCharactersInRange: [resourcePath rangeOfString:@".{format}"] withString:@".json"]; - } + [resourcePath replaceOccurrencesOfString:@".{format}" withString:@".json" options:0 range:NSMakeRange(0,resourcePath.length)]; NSMutableDictionary *pathParams = [[NSMutableDictionary alloc] init]; if (petId != nil) { @@ -514,22 +464,16 @@ static SWGPetApi* singletonAPI = nil; NSMutableDictionary* queryParams = [[NSMutableDictionary alloc] init]; NSMutableDictionary* headerParams = [NSMutableDictionary dictionaryWithDictionary:self.defaultHeaders]; // HTTP header `Accept` - headerParams[@"Accept"] = [SWGApiClient selectHeaderAccept:@[@"application/json", @"application/xml"]]; - if ([headerParams[@"Accept"] length] == 0) { - [headerParams removeObjectForKey:@"Accept"]; + NSString *acceptHeader = [self.apiClient.sanitizer selectHeaderAccept:@[@"application/json", @"application/xml"]]; + if(acceptHeader.length > 0) { + headerParams[@"Accept"] = acceptHeader; } // response content type - NSString *responseContentType; - if ([headerParams objectForKey:@"Accept"]) { - responseContentType = [headerParams[@"Accept"] componentsSeparatedByString:@", "][0]; - } - else { - responseContentType = @""; - } + NSString *responseContentType = [[acceptHeader componentsSeparatedByString:@", "] firstObject] ?: @""; // request content type - NSString *requestContentType = [SWGApiClient selectHeaderContentType:@[@"application/x-www-form-urlencoded"]]; + NSString *requestContentType = [self.apiClient.sanitizer selectHeaderContentType:@[@"application/x-www-form-urlencoded"]]; // Authentication setting NSArray *authSettings = @[@"petstore_auth"]; @@ -585,9 +529,7 @@ static SWGPetApi* singletonAPI = nil; NSMutableString* resourcePath = [NSMutableString stringWithFormat:@"/pet/{petId}/uploadImage"]; // remove format in URL if needed - if ([resourcePath rangeOfString:@".{format}"].location != NSNotFound) { - [resourcePath replaceCharactersInRange: [resourcePath rangeOfString:@".{format}"] withString:@".json"]; - } + [resourcePath replaceOccurrencesOfString:@".{format}" withString:@".json" options:0 range:NSMakeRange(0,resourcePath.length)]; NSMutableDictionary *pathParams = [[NSMutableDictionary alloc] init]; if (petId != nil) { @@ -597,22 +539,16 @@ static SWGPetApi* singletonAPI = nil; NSMutableDictionary* queryParams = [[NSMutableDictionary alloc] init]; NSMutableDictionary* headerParams = [NSMutableDictionary dictionaryWithDictionary:self.defaultHeaders]; // HTTP header `Accept` - headerParams[@"Accept"] = [SWGApiClient selectHeaderAccept:@[@"application/json", @"application/xml"]]; - if ([headerParams[@"Accept"] length] == 0) { - [headerParams removeObjectForKey:@"Accept"]; + NSString *acceptHeader = [self.apiClient.sanitizer selectHeaderAccept:@[@"application/json", @"application/xml"]]; + if(acceptHeader.length > 0) { + headerParams[@"Accept"] = acceptHeader; } // response content type - NSString *responseContentType; - if ([headerParams objectForKey:@"Accept"]) { - responseContentType = [headerParams[@"Accept"] componentsSeparatedByString:@", "][0]; - } - else { - responseContentType = @""; - } + NSString *responseContentType = [[acceptHeader componentsSeparatedByString:@", "] firstObject] ?: @""; // request content type - NSString *requestContentType = [SWGApiClient selectHeaderContentType:@[@"multipart/form-data"]]; + NSString *requestContentType = [self.apiClient.sanitizer selectHeaderContentType:@[@"multipart/form-data"]]; // Authentication setting NSArray *authSettings = @[@"petstore_auth"]; diff --git a/samples/client/petstore/objc/SwaggerClient/SWGSanitizer.h b/samples/client/petstore/objc/SwaggerClient/SWGSanitizer.h index 5803999f362..aa2c6f85163 100644 --- a/samples/client/petstore/objc/SwaggerClient/SWGSanitizer.h +++ b/samples/client/petstore/objc/SwaggerClient/SWGSanitizer.h @@ -6,6 +6,8 @@ * Do not edit the class manually. */ +extern NSString * SWGPercentEscapedStringFromString(NSString *string); + @protocol SWGSanitizer /** @@ -20,6 +22,24 @@ */ - (NSString *) parameterToString: (id) param; +/** + * Detects Accept header from accepts NSArray + * + * @param accepts NSArray of header + * + * @return The Accept header + */ +-(NSString *) selectHeaderAccept:(NSArray *)accepts; + +/** + * Detects Content-Type header from contentTypes NSArray + * + * @param contentTypes NSArray of header + * + * @return The Content-Type header + */ +-(NSString *) selectHeaderContentType:(NSArray *)contentTypes; + @end @interface SWGSanitizer : NSObject diff --git a/samples/client/petstore/objc/SwaggerClient/SWGSanitizer.m b/samples/client/petstore/objc/SwaggerClient/SWGSanitizer.m index 3f1dea7726e..673904d6a83 100644 --- a/samples/client/petstore/objc/SwaggerClient/SWGSanitizer.m +++ b/samples/client/petstore/objc/SwaggerClient/SWGSanitizer.m @@ -3,6 +3,38 @@ #import "SWGQueryParamCollection.h" #import +NSString * SWGPercentEscapedStringFromString(NSString *string) { + static NSString * const kSWGCharactersGeneralDelimitersToEncode = @":#[]@"; + static NSString * const kSWGCharactersSubDelimitersToEncode = @"!$&'()*+,;="; + + NSMutableCharacterSet * allowedCharacterSet = [[NSCharacterSet URLQueryAllowedCharacterSet] mutableCopy]; + [allowedCharacterSet removeCharactersInString:[kSWGCharactersGeneralDelimitersToEncode stringByAppendingString:kSWGCharactersSubDelimitersToEncode]]; + + static NSUInteger const batchSize = 50; + + NSUInteger index = 0; + NSMutableString *escaped = @"".mutableCopy; + + while (index < string.length) { + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wgnu" + NSUInteger length = MIN(string.length - index, batchSize); + #pragma GCC diagnostic pop + NSRange range = NSMakeRange(index, length); + + // To avoid breaking up character sequences such as 👴🏻👮🏽 + range = [string rangeOfComposedCharacterSequencesForRange:range]; + + NSString *substring = [string substringWithRange:range]; + NSString *encoded = [substring stringByAddingPercentEncodingWithAllowedCharacters:allowedCharacterSet]; + [escaped appendString:encoded]; + + index += range.length; + } + + return escaped; +} + @interface SWGSanitizer () @end @@ -79,4 +111,52 @@ } } +#pragma mark - Utility Methods + +/* + * Detect `Accept` from accepts + */ +- (NSString *) selectHeaderAccept:(NSArray *)accepts { + if (accepts == nil || [accepts count] == 0) { + return @""; + } + + NSMutableArray *lowerAccepts = [[NSMutableArray alloc] initWithCapacity:[accepts count]]; + for (NSString *string in accepts) { + NSString * lowerAccept = [string lowercaseString]; + // use rangeOfString instead of containsString for iOS 7 support + if ([lowerAccept rangeOfString:@"application/json"].location != NSNotFound) { + return @"application/json"; + } + [lowerAccepts addObject:lowerAccept]; + } + + if (lowerAccepts.count == 1) { + return [lowerAccepts firstObject]; + } + + return [lowerAccepts componentsJoinedByString:@", "]; +} + +/* + * Detect `Content-Type` from contentTypes + */ +- (NSString *) selectHeaderContentType:(NSArray *)contentTypes { + if (contentTypes == nil || [contentTypes count] == 0) { + return @"application/json"; + } + + NSMutableArray *lowerContentTypes = [[NSMutableArray alloc] initWithCapacity:[contentTypes count]]; + [contentTypes enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { + [lowerContentTypes addObject:[obj lowercaseString]]; + }]; + + if ([lowerContentTypes containsObject:@"application/json"]) { + return @"application/json"; + } + else { + return lowerContentTypes[0]; + } +} + @end diff --git a/samples/client/petstore/objc/SwaggerClient/SWGStoreApi.m b/samples/client/petstore/objc/SwaggerClient/SWGStoreApi.m index 336258c3c5b..91e5e495af2 100644 --- a/samples/client/petstore/objc/SwaggerClient/SWGStoreApi.m +++ b/samples/client/petstore/objc/SwaggerClient/SWGStoreApi.m @@ -13,7 +13,7 @@ static SWGStoreApi* singletonAPI = nil; #pragma mark - Initialize methods -- (id) init { +- (instancetype) init { self = [super init]; if (self) { SWGConfiguration *config = [SWGConfiguration sharedConfig]; @@ -26,7 +26,7 @@ static SWGStoreApi* singletonAPI = nil; return self; } -- (id) initWithApiClient:(SWGApiClient *)apiClient { +- (instancetype) initWithApiClient:(SWGApiClient *)apiClient { self = [super init]; if (self) { self.apiClient = apiClient; @@ -84,9 +84,7 @@ static SWGStoreApi* singletonAPI = nil; NSMutableString* resourcePath = [NSMutableString stringWithFormat:@"/store/order/{orderId}"]; // remove format in URL if needed - if ([resourcePath rangeOfString:@".{format}"].location != NSNotFound) { - [resourcePath replaceCharactersInRange: [resourcePath rangeOfString:@".{format}"] withString:@".json"]; - } + [resourcePath replaceOccurrencesOfString:@".{format}" withString:@".json" options:0 range:NSMakeRange(0,resourcePath.length)]; NSMutableDictionary *pathParams = [[NSMutableDictionary alloc] init]; if (orderId != nil) { @@ -96,22 +94,16 @@ static SWGStoreApi* singletonAPI = nil; NSMutableDictionary* queryParams = [[NSMutableDictionary alloc] init]; NSMutableDictionary* headerParams = [NSMutableDictionary dictionaryWithDictionary:self.defaultHeaders]; // HTTP header `Accept` - headerParams[@"Accept"] = [SWGApiClient selectHeaderAccept:@[@"application/json", @"application/xml"]]; - if ([headerParams[@"Accept"] length] == 0) { - [headerParams removeObjectForKey:@"Accept"]; + NSString *acceptHeader = [self.apiClient.sanitizer selectHeaderAccept:@[@"application/json", @"application/xml"]]; + if(acceptHeader.length > 0) { + headerParams[@"Accept"] = acceptHeader; } // response content type - NSString *responseContentType; - if ([headerParams objectForKey:@"Accept"]) { - responseContentType = [headerParams[@"Accept"] componentsSeparatedByString:@", "][0]; - } - else { - responseContentType = @""; - } + NSString *responseContentType = [[acceptHeader componentsSeparatedByString:@", "] firstObject] ?: @""; // request content type - NSString *requestContentType = [SWGApiClient selectHeaderContentType:@[]]; + NSString *requestContentType = [self.apiClient.sanitizer selectHeaderContentType:@[]]; // Authentication setting NSArray *authSettings = @[]; @@ -148,31 +140,23 @@ static SWGStoreApi* singletonAPI = nil; NSMutableString* resourcePath = [NSMutableString stringWithFormat:@"/store/inventory"]; // remove format in URL if needed - if ([resourcePath rangeOfString:@".{format}"].location != NSNotFound) { - [resourcePath replaceCharactersInRange: [resourcePath rangeOfString:@".{format}"] withString:@".json"]; - } + [resourcePath replaceOccurrencesOfString:@".{format}" withString:@".json" options:0 range:NSMakeRange(0,resourcePath.length)]; NSMutableDictionary *pathParams = [[NSMutableDictionary alloc] init]; NSMutableDictionary* queryParams = [[NSMutableDictionary alloc] init]; NSMutableDictionary* headerParams = [NSMutableDictionary dictionaryWithDictionary:self.defaultHeaders]; // HTTP header `Accept` - headerParams[@"Accept"] = [SWGApiClient selectHeaderAccept:@[@"application/json", @"application/xml"]]; - if ([headerParams[@"Accept"] length] == 0) { - [headerParams removeObjectForKey:@"Accept"]; + NSString *acceptHeader = [self.apiClient.sanitizer selectHeaderAccept:@[@"application/json", @"application/xml"]]; + if(acceptHeader.length > 0) { + headerParams[@"Accept"] = acceptHeader; } // response content type - NSString *responseContentType; - if ([headerParams objectForKey:@"Accept"]) { - responseContentType = [headerParams[@"Accept"] componentsSeparatedByString:@", "][0]; - } - else { - responseContentType = @""; - } + NSString *responseContentType = [[acceptHeader componentsSeparatedByString:@", "] firstObject] ?: @""; // request content type - NSString *requestContentType = [SWGApiClient selectHeaderContentType:@[]]; + NSString *requestContentType = [self.apiClient.sanitizer selectHeaderContentType:@[]]; // Authentication setting NSArray *authSettings = @[@"api_key"]; @@ -216,9 +200,7 @@ static SWGStoreApi* singletonAPI = nil; NSMutableString* resourcePath = [NSMutableString stringWithFormat:@"/store/order/{orderId}"]; // remove format in URL if needed - if ([resourcePath rangeOfString:@".{format}"].location != NSNotFound) { - [resourcePath replaceCharactersInRange: [resourcePath rangeOfString:@".{format}"] withString:@".json"]; - } + [resourcePath replaceOccurrencesOfString:@".{format}" withString:@".json" options:0 range:NSMakeRange(0,resourcePath.length)]; NSMutableDictionary *pathParams = [[NSMutableDictionary alloc] init]; if (orderId != nil) { @@ -228,22 +210,16 @@ static SWGStoreApi* singletonAPI = nil; NSMutableDictionary* queryParams = [[NSMutableDictionary alloc] init]; NSMutableDictionary* headerParams = [NSMutableDictionary dictionaryWithDictionary:self.defaultHeaders]; // HTTP header `Accept` - headerParams[@"Accept"] = [SWGApiClient selectHeaderAccept:@[@"application/json", @"application/xml"]]; - if ([headerParams[@"Accept"] length] == 0) { - [headerParams removeObjectForKey:@"Accept"]; + NSString *acceptHeader = [self.apiClient.sanitizer selectHeaderAccept:@[@"application/json", @"application/xml"]]; + if(acceptHeader.length > 0) { + headerParams[@"Accept"] = acceptHeader; } // response content type - NSString *responseContentType; - if ([headerParams objectForKey:@"Accept"]) { - responseContentType = [headerParams[@"Accept"] componentsSeparatedByString:@", "][0]; - } - else { - responseContentType = @""; - } + NSString *responseContentType = [[acceptHeader componentsSeparatedByString:@", "] firstObject] ?: @""; // request content type - NSString *requestContentType = [SWGApiClient selectHeaderContentType:@[]]; + NSString *requestContentType = [self.apiClient.sanitizer selectHeaderContentType:@[]]; // Authentication setting NSArray *authSettings = @[]; @@ -282,31 +258,23 @@ static SWGStoreApi* singletonAPI = nil; NSMutableString* resourcePath = [NSMutableString stringWithFormat:@"/store/order"]; // remove format in URL if needed - if ([resourcePath rangeOfString:@".{format}"].location != NSNotFound) { - [resourcePath replaceCharactersInRange: [resourcePath rangeOfString:@".{format}"] withString:@".json"]; - } + [resourcePath replaceOccurrencesOfString:@".{format}" withString:@".json" options:0 range:NSMakeRange(0,resourcePath.length)]; NSMutableDictionary *pathParams = [[NSMutableDictionary alloc] init]; NSMutableDictionary* queryParams = [[NSMutableDictionary alloc] init]; NSMutableDictionary* headerParams = [NSMutableDictionary dictionaryWithDictionary:self.defaultHeaders]; // HTTP header `Accept` - headerParams[@"Accept"] = [SWGApiClient selectHeaderAccept:@[@"application/json", @"application/xml"]]; - if ([headerParams[@"Accept"] length] == 0) { - [headerParams removeObjectForKey:@"Accept"]; + NSString *acceptHeader = [self.apiClient.sanitizer selectHeaderAccept:@[@"application/json", @"application/xml"]]; + if(acceptHeader.length > 0) { + headerParams[@"Accept"] = acceptHeader; } // response content type - NSString *responseContentType; - if ([headerParams objectForKey:@"Accept"]) { - responseContentType = [headerParams[@"Accept"] componentsSeparatedByString:@", "][0]; - } - else { - responseContentType = @""; - } + NSString *responseContentType = [[acceptHeader componentsSeparatedByString:@", "] firstObject] ?: @""; // request content type - NSString *requestContentType = [SWGApiClient selectHeaderContentType:@[]]; + NSString *requestContentType = [self.apiClient.sanitizer selectHeaderContentType:@[]]; // Authentication setting NSArray *authSettings = @[]; diff --git a/samples/client/petstore/objc/SwaggerClient/SWGUserApi.m b/samples/client/petstore/objc/SwaggerClient/SWGUserApi.m index 914d1822402..ecb5aa7ba53 100644 --- a/samples/client/petstore/objc/SwaggerClient/SWGUserApi.m +++ b/samples/client/petstore/objc/SwaggerClient/SWGUserApi.m @@ -13,7 +13,7 @@ static SWGUserApi* singletonAPI = nil; #pragma mark - Initialize methods -- (id) init { +- (instancetype) init { self = [super init]; if (self) { SWGConfiguration *config = [SWGConfiguration sharedConfig]; @@ -26,7 +26,7 @@ static SWGUserApi* singletonAPI = nil; return self; } -- (id) initWithApiClient:(SWGApiClient *)apiClient { +- (instancetype) initWithApiClient:(SWGApiClient *)apiClient { self = [super init]; if (self) { self.apiClient = apiClient; @@ -79,31 +79,23 @@ static SWGUserApi* singletonAPI = nil; NSMutableString* resourcePath = [NSMutableString stringWithFormat:@"/user"]; // remove format in URL if needed - if ([resourcePath rangeOfString:@".{format}"].location != NSNotFound) { - [resourcePath replaceCharactersInRange: [resourcePath rangeOfString:@".{format}"] withString:@".json"]; - } + [resourcePath replaceOccurrencesOfString:@".{format}" withString:@".json" options:0 range:NSMakeRange(0,resourcePath.length)]; NSMutableDictionary *pathParams = [[NSMutableDictionary alloc] init]; NSMutableDictionary* queryParams = [[NSMutableDictionary alloc] init]; NSMutableDictionary* headerParams = [NSMutableDictionary dictionaryWithDictionary:self.defaultHeaders]; // HTTP header `Accept` - headerParams[@"Accept"] = [SWGApiClient selectHeaderAccept:@[@"application/json", @"application/xml"]]; - if ([headerParams[@"Accept"] length] == 0) { - [headerParams removeObjectForKey:@"Accept"]; + NSString *acceptHeader = [self.apiClient.sanitizer selectHeaderAccept:@[@"application/json", @"application/xml"]]; + if(acceptHeader.length > 0) { + headerParams[@"Accept"] = acceptHeader; } // response content type - NSString *responseContentType; - if ([headerParams objectForKey:@"Accept"]) { - responseContentType = [headerParams[@"Accept"] componentsSeparatedByString:@", "][0]; - } - else { - responseContentType = @""; - } + NSString *responseContentType = [[acceptHeader componentsSeparatedByString:@", "] firstObject] ?: @""; // request content type - NSString *requestContentType = [SWGApiClient selectHeaderContentType:@[]]; + NSString *requestContentType = [self.apiClient.sanitizer selectHeaderContentType:@[]]; // Authentication setting NSArray *authSettings = @[]; @@ -143,31 +135,23 @@ static SWGUserApi* singletonAPI = nil; NSMutableString* resourcePath = [NSMutableString stringWithFormat:@"/user/createWithArray"]; // remove format in URL if needed - if ([resourcePath rangeOfString:@".{format}"].location != NSNotFound) { - [resourcePath replaceCharactersInRange: [resourcePath rangeOfString:@".{format}"] withString:@".json"]; - } + [resourcePath replaceOccurrencesOfString:@".{format}" withString:@".json" options:0 range:NSMakeRange(0,resourcePath.length)]; NSMutableDictionary *pathParams = [[NSMutableDictionary alloc] init]; NSMutableDictionary* queryParams = [[NSMutableDictionary alloc] init]; NSMutableDictionary* headerParams = [NSMutableDictionary dictionaryWithDictionary:self.defaultHeaders]; // HTTP header `Accept` - headerParams[@"Accept"] = [SWGApiClient selectHeaderAccept:@[@"application/json", @"application/xml"]]; - if ([headerParams[@"Accept"] length] == 0) { - [headerParams removeObjectForKey:@"Accept"]; + NSString *acceptHeader = [self.apiClient.sanitizer selectHeaderAccept:@[@"application/json", @"application/xml"]]; + if(acceptHeader.length > 0) { + headerParams[@"Accept"] = acceptHeader; } // response content type - NSString *responseContentType; - if ([headerParams objectForKey:@"Accept"]) { - responseContentType = [headerParams[@"Accept"] componentsSeparatedByString:@", "][0]; - } - else { - responseContentType = @""; - } + NSString *responseContentType = [[acceptHeader componentsSeparatedByString:@", "] firstObject] ?: @""; // request content type - NSString *requestContentType = [SWGApiClient selectHeaderContentType:@[]]; + NSString *requestContentType = [self.apiClient.sanitizer selectHeaderContentType:@[]]; // Authentication setting NSArray *authSettings = @[]; @@ -207,31 +191,23 @@ static SWGUserApi* singletonAPI = nil; NSMutableString* resourcePath = [NSMutableString stringWithFormat:@"/user/createWithList"]; // remove format in URL if needed - if ([resourcePath rangeOfString:@".{format}"].location != NSNotFound) { - [resourcePath replaceCharactersInRange: [resourcePath rangeOfString:@".{format}"] withString:@".json"]; - } + [resourcePath replaceOccurrencesOfString:@".{format}" withString:@".json" options:0 range:NSMakeRange(0,resourcePath.length)]; NSMutableDictionary *pathParams = [[NSMutableDictionary alloc] init]; NSMutableDictionary* queryParams = [[NSMutableDictionary alloc] init]; NSMutableDictionary* headerParams = [NSMutableDictionary dictionaryWithDictionary:self.defaultHeaders]; // HTTP header `Accept` - headerParams[@"Accept"] = [SWGApiClient selectHeaderAccept:@[@"application/json", @"application/xml"]]; - if ([headerParams[@"Accept"] length] == 0) { - [headerParams removeObjectForKey:@"Accept"]; + NSString *acceptHeader = [self.apiClient.sanitizer selectHeaderAccept:@[@"application/json", @"application/xml"]]; + if(acceptHeader.length > 0) { + headerParams[@"Accept"] = acceptHeader; } // response content type - NSString *responseContentType; - if ([headerParams objectForKey:@"Accept"]) { - responseContentType = [headerParams[@"Accept"] componentsSeparatedByString:@", "][0]; - } - else { - responseContentType = @""; - } + NSString *responseContentType = [[acceptHeader componentsSeparatedByString:@", "] firstObject] ?: @""; // request content type - NSString *requestContentType = [SWGApiClient selectHeaderContentType:@[]]; + NSString *requestContentType = [self.apiClient.sanitizer selectHeaderContentType:@[]]; // Authentication setting NSArray *authSettings = @[]; @@ -276,9 +252,7 @@ static SWGUserApi* singletonAPI = nil; NSMutableString* resourcePath = [NSMutableString stringWithFormat:@"/user/{username}"]; // remove format in URL if needed - if ([resourcePath rangeOfString:@".{format}"].location != NSNotFound) { - [resourcePath replaceCharactersInRange: [resourcePath rangeOfString:@".{format}"] withString:@".json"]; - } + [resourcePath replaceOccurrencesOfString:@".{format}" withString:@".json" options:0 range:NSMakeRange(0,resourcePath.length)]; NSMutableDictionary *pathParams = [[NSMutableDictionary alloc] init]; if (username != nil) { @@ -288,22 +262,16 @@ static SWGUserApi* singletonAPI = nil; NSMutableDictionary* queryParams = [[NSMutableDictionary alloc] init]; NSMutableDictionary* headerParams = [NSMutableDictionary dictionaryWithDictionary:self.defaultHeaders]; // HTTP header `Accept` - headerParams[@"Accept"] = [SWGApiClient selectHeaderAccept:@[@"application/json", @"application/xml"]]; - if ([headerParams[@"Accept"] length] == 0) { - [headerParams removeObjectForKey:@"Accept"]; + NSString *acceptHeader = [self.apiClient.sanitizer selectHeaderAccept:@[@"application/json", @"application/xml"]]; + if(acceptHeader.length > 0) { + headerParams[@"Accept"] = acceptHeader; } // response content type - NSString *responseContentType; - if ([headerParams objectForKey:@"Accept"]) { - responseContentType = [headerParams[@"Accept"] componentsSeparatedByString:@", "][0]; - } - else { - responseContentType = @""; - } + NSString *responseContentType = [[acceptHeader componentsSeparatedByString:@", "] firstObject] ?: @""; // request content type - NSString *requestContentType = [SWGApiClient selectHeaderContentType:@[]]; + NSString *requestContentType = [self.apiClient.sanitizer selectHeaderContentType:@[]]; // Authentication setting NSArray *authSettings = @[]; @@ -347,9 +315,7 @@ static SWGUserApi* singletonAPI = nil; NSMutableString* resourcePath = [NSMutableString stringWithFormat:@"/user/{username}"]; // remove format in URL if needed - if ([resourcePath rangeOfString:@".{format}"].location != NSNotFound) { - [resourcePath replaceCharactersInRange: [resourcePath rangeOfString:@".{format}"] withString:@".json"]; - } + [resourcePath replaceOccurrencesOfString:@".{format}" withString:@".json" options:0 range:NSMakeRange(0,resourcePath.length)]; NSMutableDictionary *pathParams = [[NSMutableDictionary alloc] init]; if (username != nil) { @@ -359,22 +325,16 @@ static SWGUserApi* singletonAPI = nil; NSMutableDictionary* queryParams = [[NSMutableDictionary alloc] init]; NSMutableDictionary* headerParams = [NSMutableDictionary dictionaryWithDictionary:self.defaultHeaders]; // HTTP header `Accept` - headerParams[@"Accept"] = [SWGApiClient selectHeaderAccept:@[@"application/json", @"application/xml"]]; - if ([headerParams[@"Accept"] length] == 0) { - [headerParams removeObjectForKey:@"Accept"]; + NSString *acceptHeader = [self.apiClient.sanitizer selectHeaderAccept:@[@"application/json", @"application/xml"]]; + if(acceptHeader.length > 0) { + headerParams[@"Accept"] = acceptHeader; } // response content type - NSString *responseContentType; - if ([headerParams objectForKey:@"Accept"]) { - responseContentType = [headerParams[@"Accept"] componentsSeparatedByString:@", "][0]; - } - else { - responseContentType = @""; - } + NSString *responseContentType = [[acceptHeader componentsSeparatedByString:@", "] firstObject] ?: @""; // request content type - NSString *requestContentType = [SWGApiClient selectHeaderContentType:@[]]; + NSString *requestContentType = [self.apiClient.sanitizer selectHeaderContentType:@[]]; // Authentication setting NSArray *authSettings = @[]; @@ -416,9 +376,7 @@ static SWGUserApi* singletonAPI = nil; NSMutableString* resourcePath = [NSMutableString stringWithFormat:@"/user/login"]; // remove format in URL if needed - if ([resourcePath rangeOfString:@".{format}"].location != NSNotFound) { - [resourcePath replaceCharactersInRange: [resourcePath rangeOfString:@".{format}"] withString:@".json"]; - } + [resourcePath replaceOccurrencesOfString:@".{format}" withString:@".json" options:0 range:NSMakeRange(0,resourcePath.length)]; NSMutableDictionary *pathParams = [[NSMutableDictionary alloc] init]; @@ -431,22 +389,16 @@ static SWGUserApi* singletonAPI = nil; } NSMutableDictionary* headerParams = [NSMutableDictionary dictionaryWithDictionary:self.defaultHeaders]; // HTTP header `Accept` - headerParams[@"Accept"] = [SWGApiClient selectHeaderAccept:@[@"application/json", @"application/xml"]]; - if ([headerParams[@"Accept"] length] == 0) { - [headerParams removeObjectForKey:@"Accept"]; + NSString *acceptHeader = [self.apiClient.sanitizer selectHeaderAccept:@[@"application/json", @"application/xml"]]; + if(acceptHeader.length > 0) { + headerParams[@"Accept"] = acceptHeader; } // response content type - NSString *responseContentType; - if ([headerParams objectForKey:@"Accept"]) { - responseContentType = [headerParams[@"Accept"] componentsSeparatedByString:@", "][0]; - } - else { - responseContentType = @""; - } + NSString *responseContentType = [[acceptHeader componentsSeparatedByString:@", "] firstObject] ?: @""; // request content type - NSString *requestContentType = [SWGApiClient selectHeaderContentType:@[]]; + NSString *requestContentType = [self.apiClient.sanitizer selectHeaderContentType:@[]]; // Authentication setting NSArray *authSettings = @[]; @@ -483,31 +435,23 @@ static SWGUserApi* singletonAPI = nil; NSMutableString* resourcePath = [NSMutableString stringWithFormat:@"/user/logout"]; // remove format in URL if needed - if ([resourcePath rangeOfString:@".{format}"].location != NSNotFound) { - [resourcePath replaceCharactersInRange: [resourcePath rangeOfString:@".{format}"] withString:@".json"]; - } + [resourcePath replaceOccurrencesOfString:@".{format}" withString:@".json" options:0 range:NSMakeRange(0,resourcePath.length)]; NSMutableDictionary *pathParams = [[NSMutableDictionary alloc] init]; NSMutableDictionary* queryParams = [[NSMutableDictionary alloc] init]; NSMutableDictionary* headerParams = [NSMutableDictionary dictionaryWithDictionary:self.defaultHeaders]; // HTTP header `Accept` - headerParams[@"Accept"] = [SWGApiClient selectHeaderAccept:@[@"application/json", @"application/xml"]]; - if ([headerParams[@"Accept"] length] == 0) { - [headerParams removeObjectForKey:@"Accept"]; + NSString *acceptHeader = [self.apiClient.sanitizer selectHeaderAccept:@[@"application/json", @"application/xml"]]; + if(acceptHeader.length > 0) { + headerParams[@"Accept"] = acceptHeader; } // response content type - NSString *responseContentType; - if ([headerParams objectForKey:@"Accept"]) { - responseContentType = [headerParams[@"Accept"] componentsSeparatedByString:@", "][0]; - } - else { - responseContentType = @""; - } + NSString *responseContentType = [[acceptHeader componentsSeparatedByString:@", "] firstObject] ?: @""; // request content type - NSString *requestContentType = [SWGApiClient selectHeaderContentType:@[]]; + NSString *requestContentType = [self.apiClient.sanitizer selectHeaderContentType:@[]]; // Authentication setting NSArray *authSettings = @[]; @@ -554,9 +498,7 @@ static SWGUserApi* singletonAPI = nil; NSMutableString* resourcePath = [NSMutableString stringWithFormat:@"/user/{username}"]; // remove format in URL if needed - if ([resourcePath rangeOfString:@".{format}"].location != NSNotFound) { - [resourcePath replaceCharactersInRange: [resourcePath rangeOfString:@".{format}"] withString:@".json"]; - } + [resourcePath replaceOccurrencesOfString:@".{format}" withString:@".json" options:0 range:NSMakeRange(0,resourcePath.length)]; NSMutableDictionary *pathParams = [[NSMutableDictionary alloc] init]; if (username != nil) { @@ -566,22 +508,16 @@ static SWGUserApi* singletonAPI = nil; NSMutableDictionary* queryParams = [[NSMutableDictionary alloc] init]; NSMutableDictionary* headerParams = [NSMutableDictionary dictionaryWithDictionary:self.defaultHeaders]; // HTTP header `Accept` - headerParams[@"Accept"] = [SWGApiClient selectHeaderAccept:@[@"application/json", @"application/xml"]]; - if ([headerParams[@"Accept"] length] == 0) { - [headerParams removeObjectForKey:@"Accept"]; + NSString *acceptHeader = [self.apiClient.sanitizer selectHeaderAccept:@[@"application/json", @"application/xml"]]; + if(acceptHeader.length > 0) { + headerParams[@"Accept"] = acceptHeader; } // response content type - NSString *responseContentType; - if ([headerParams objectForKey:@"Accept"]) { - responseContentType = [headerParams[@"Accept"] componentsSeparatedByString:@", "][0]; - } - else { - responseContentType = @""; - } + NSString *responseContentType = [[acceptHeader componentsSeparatedByString:@", "] firstObject] ?: @""; // request content type - NSString *requestContentType = [SWGApiClient selectHeaderContentType:@[]]; + NSString *requestContentType = [self.apiClient.sanitizer selectHeaderContentType:@[]]; // Authentication setting NSArray *authSettings = @[]; diff --git a/samples/client/petstore/objc/SwaggerClientTests/Tests/PetApiTest.m b/samples/client/petstore/objc/SwaggerClientTests/Tests/PetApiTest.m index 7ddc817e9ef..f472c4d6ab5 100644 --- a/samples/client/petstore/objc/SwaggerClientTests/Tests/PetApiTest.m +++ b/samples/client/petstore/objc/SwaggerClientTests/Tests/PetApiTest.m @@ -1,7 +1,6 @@ #import #import #import -#import @interface PetApiTest : XCTestCase { @private @@ -165,13 +164,13 @@ which causes an exception when deserializing the data SWGTag* tag = [[SWGTag alloc] init]; tag.name = @"tony"; NSLog(@"%@", pet._id); - pet.tags = (id)[[NSArray alloc] initWithObjects:tag, nil]; + pet.tags = (id) @[tag]; [api addPetWithBody:pet completionHandler:^(NSError *error) { if(error) { XCTFail(@"got error %@", error); } - NSArray* tags = [[NSArray alloc] initWithObjects:@"tony", nil]; + NSArray* tags = @[@"tony",@"tony2"]; [api findPetsByTagsWithTags:tags completionHandler:^(NSArray *output, NSError *error) { if(error){ @@ -275,7 +274,7 @@ which causes an exception when deserializing the data - (SWGPet*) createPet { SWGPet * pet = [[SWGPet alloc] init]; - pet._id = [[NSNumber alloc] initWithLong:[[NSDate date] timeIntervalSince1970]]; + pet._id = @((long) [[NSDate date] timeIntervalSince1970]); pet.name = @"monkey"; SWGCategory * category = [[SWGCategory alloc] init]; @@ -289,11 +288,11 @@ which causes an exception when deserializing the data SWGTag *tag2 = [[SWGTag alloc] init]; tag2._id = [[NSNumber alloc] initWithInteger:arc4random_uniform(100000)]; tag2.name = @"test tag 2"; - pet.tags = (NSArray *)[[NSArray alloc] initWithObjects:tag1, tag2, nil]; + pet.tags = (NSArray *) @[tag1, tag2]; pet.status = @"available"; - NSArray * photos = [[NSArray alloc] initWithObjects:@"http://foo.bar.com/3", @"http://foo.bar.com/4", nil]; + NSArray * photos = @[@"http://foo.bar.com/3", @"http://foo.bar.com/4"]; pet.photoUrls = photos; return pet; } diff --git a/samples/client/petstore/objc/SwaggerClientTests/Tests/SWGApiClientTest.m b/samples/client/petstore/objc/SwaggerClientTests/Tests/SWGApiClientTest.m index ed87d8f9e2d..644b50f6504 100644 --- a/samples/client/petstore/objc/SwaggerClientTests/Tests/SWGApiClientTest.m +++ b/samples/client/petstore/objc/SwaggerClientTests/Tests/SWGApiClientTest.m @@ -25,38 +25,40 @@ NSArray *accepts = nil; accepts = @[@"APPLICATION/JSON", @"APPLICATION/XML"]; - XCTAssertEqualObjects([SWGApiClient selectHeaderAccept:accepts], @"application/json"); + SWGSanitizer * sanitizer = [[SWGSanitizer alloc] init]; + XCTAssertEqualObjects([sanitizer selectHeaderAccept:accepts], @"application/json"); accepts = @[@"application/json", @"application/xml"]; - XCTAssertEqualObjects([SWGApiClient selectHeaderAccept:accepts], @"application/json"); + XCTAssertEqualObjects([sanitizer selectHeaderAccept:accepts], @"application/json"); accepts = @[@"APPLICATION/xml", @"APPLICATION/json"]; - XCTAssertEqualObjects([SWGApiClient selectHeaderAccept:accepts], @"application/json"); + XCTAssertEqualObjects([sanitizer selectHeaderAccept:accepts], @"application/json"); accepts = @[@"text/plain", @"application/xml"]; - XCTAssertEqualObjects([SWGApiClient selectHeaderAccept:accepts], @"text/plain, application/xml"); + XCTAssertEqualObjects([sanitizer selectHeaderAccept:accepts], @"text/plain, application/xml"); accepts = @[]; - XCTAssertEqualObjects([SWGApiClient selectHeaderAccept:accepts], @""); + XCTAssertEqualObjects([sanitizer selectHeaderAccept:accepts], @""); } - (void)testSelectHeaderContentType { NSArray *contentTypes = nil; - + SWGSanitizer * sanitizer = [[SWGSanitizer alloc] init]; + contentTypes = @[@"APPLICATION/JSON", @"APPLICATION/XML"]; - XCTAssertEqualObjects([SWGApiClient selectHeaderContentType:contentTypes], @"application/json"); + XCTAssertEqualObjects([sanitizer selectHeaderContentType:contentTypes], @"application/json"); contentTypes = @[@"application/json", @"application/xml"]; - XCTAssertEqualObjects([SWGApiClient selectHeaderContentType:contentTypes], @"application/json"); + XCTAssertEqualObjects([sanitizer selectHeaderContentType:contentTypes], @"application/json"); contentTypes = @[@"APPLICATION/xml", @"APPLICATION/json"]; - XCTAssertEqualObjects([SWGApiClient selectHeaderContentType:contentTypes], @"application/json"); + XCTAssertEqualObjects([sanitizer selectHeaderContentType:contentTypes], @"application/json"); contentTypes = @[@"text/plain", @"application/xml"]; - XCTAssertEqualObjects([SWGApiClient selectHeaderContentType:contentTypes], @"text/plain"); + XCTAssertEqualObjects([sanitizer selectHeaderContentType:contentTypes], @"text/plain"); contentTypes = @[]; - XCTAssertEqualObjects([SWGApiClient selectHeaderContentType:contentTypes], @"application/json"); + XCTAssertEqualObjects([sanitizer selectHeaderContentType:contentTypes], @"application/json"); } - (void)testConfiguration { From 567c23a3df7a3517206c8eb0615d3e929a366e3a Mon Sep 17 00:00:00 2001 From: Mateusz Mackowiak Date: Wed, 11 May 2016 17:39:28 +0200 Subject: [PATCH 2/3] [Objc] Support for variations of application/json type --- .../resources/objc/Sanitizer-body.mustache | 84 ++++++++++--------- samples/client/petstore/objc/README.md | 2 +- .../objc/SwaggerClient/SWGSanitizer.m | 80 ++++++++++-------- .../Tests/SWGApiClientTest.m | 23 ++++- 4 files changed, 111 insertions(+), 78 deletions(-) diff --git a/modules/swagger-codegen/src/main/resources/objc/Sanitizer-body.mustache b/modules/swagger-codegen/src/main/resources/objc/Sanitizer-body.mustache index f43e6493d75..a111aad9cef 100644 --- a/modules/swagger-codegen/src/main/resources/objc/Sanitizer-body.mustache +++ b/modules/swagger-codegen/src/main/resources/objc/Sanitizer-body.mustache @@ -16,30 +16,44 @@ NSString * {{classPrefix}}PercentEscapedStringFromString(NSString *string) { NSMutableString *escaped = @"".mutableCopy; while (index < string.length) { - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wgnu" - NSUInteger length = MIN(string.length - index, batchSize); - #pragma GCC diagnostic pop - NSRange range = NSMakeRange(index, length); + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wgnu" + NSUInteger length = MIN(string.length - index, batchSize); + #pragma GCC diagnostic pop + NSRange range = NSMakeRange(index, length); - // To avoid breaking up character sequences such as 👴🏻👮🏽 - range = [string rangeOfComposedCharacterSequencesForRange:range]; + // To avoid breaking up character sequences such as 👴🏻👮🏽 + range = [string rangeOfComposedCharacterSequencesForRange:range]; - NSString *substring = [string substringWithRange:range]; - NSString *encoded = [substring stringByAddingPercentEncodingWithAllowedCharacters:allowedCharacterSet]; - [escaped appendString:encoded]; + NSString *substring = [string substringWithRange:range]; + NSString *encoded = [substring stringByAddingPercentEncodingWithAllowedCharacters:allowedCharacterSet]; + [escaped appendString:encoded]; - index += range.length; + index += range.length; } return escaped; } -@interface {{classPrefix}}Sanitizer () +@interface SWGSanitizer () + +@property (nonatomic, strong) NSRegularExpression* jsonHeaderTypeExpression; @end -@implementation {{classPrefix}}Sanitizer +@implementation SWGSanitizer + +static NSString * kApplicationJSONType = @"application/json"; + +-(instancetype)init { + self = [super init]; + if ( !self ) { + return nil; + } + _jsonHeaderTypeExpression = [NSRegularExpression regularExpressionWithPattern:@"(.*)application(.*)json(.*)" options:NSRegularExpressionCaseInsensitive error:nil]; + return self; +} + - (id) sanitizeForSerialization:(id) object { if (object == nil) { @@ -49,7 +63,7 @@ NSString * {{classPrefix}}PercentEscapedStringFromString(NSString *string) { return object; } else if ([object isKindOfClass:[NSDate class]]) { - return [object ISO8601String]; + return [self dateParameterToString:object]; } else if ([object isKindOfClass:[NSArray class]]) { NSArray *objectArray = object; @@ -93,7 +107,7 @@ NSString * {{classPrefix}}PercentEscapedStringFromString(NSString *string) { return [param stringValue]; } else if ([param isKindOfClass:[NSDate class]]) { - return [param ISO8601String]; + return [self dateParameterToString:param]; } else if ([param isKindOfClass:[NSArray class]]) { NSMutableArray *mutableParam = [NSMutableArray array]; @@ -111,30 +125,26 @@ NSString * {{classPrefix}}PercentEscapedStringFromString(NSString *string) { } } +- (NSString *)dateParameterToString:(id)param { + return [param ISO8601String]; +} + #pragma mark - Utility Methods /* * Detect `Accept` from accepts */ - (NSString *) selectHeaderAccept:(NSArray *)accepts { - if (accepts == nil || [accepts count] == 0) { + if (accepts.count == 0) { return @""; } - NSMutableArray *lowerAccepts = [[NSMutableArray alloc] initWithCapacity:[accepts count]]; for (NSString *string in accepts) { - NSString * lowerAccept = [string lowercaseString]; - // use rangeOfString instead of containsString for iOS 7 support - if ([lowerAccept rangeOfString:@"application/json"].location != NSNotFound) { - return @"application/json"; + if ([self.jsonHeaderTypeExpression matchesInString:string options:0 range:NSMakeRange(0, [string length])].count > 0) { + return kApplicationJSONType; } - [lowerAccepts addObject:lowerAccept]; + [lowerAccepts addObject:[string lowercaseString]]; } - - if (lowerAccepts.count == 1) { - return [lowerAccepts firstObject]; - } - return [lowerAccepts componentsJoinedByString:@", "]; } @@ -142,21 +152,17 @@ NSString * {{classPrefix}}PercentEscapedStringFromString(NSString *string) { * Detect `Content-Type` from contentTypes */ - (NSString *) selectHeaderContentType:(NSArray *)contentTypes { - if (contentTypes == nil || [contentTypes count] == 0) { - return @"application/json"; + if (contentTypes.count == 0) { + return kApplicationJSONType; } - NSMutableArray *lowerContentTypes = [[NSMutableArray alloc] initWithCapacity:[contentTypes count]]; - [contentTypes enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { - [lowerContentTypes addObject:[obj lowercaseString]]; - }]; - - if ([lowerContentTypes containsObject:@"application/json"]) { - return @"application/json"; - } - else { - return lowerContentTypes[0]; + for (NSString *string in contentTypes) { + if([self.jsonHeaderTypeExpression matchesInString:string options:0 range:NSMakeRange(0, [string length])].count > 0){ + return kApplicationJSONType; + } + [lowerContentTypes addObject:[string lowercaseString]]; } + return [lowerContentTypes firstObject]; } @end diff --git a/samples/client/petstore/objc/README.md b/samples/client/petstore/objc/README.md index d0ae437a93c..b411635fe8a 100644 --- a/samples/client/petstore/objc/README.md +++ b/samples/client/petstore/objc/README.md @@ -6,7 +6,7 @@ This ObjC package is automatically generated by the [Swagger Codegen](https://gi - API version: 1.0.0 - Package version: -- Build date: 2016-05-10T17:16:13.387+02:00 +- Build date: 2016-05-11T17:37:37.440+02:00 - Build package: class io.swagger.codegen.languages.ObjcClientCodegen ## Requirements diff --git a/samples/client/petstore/objc/SwaggerClient/SWGSanitizer.m b/samples/client/petstore/objc/SwaggerClient/SWGSanitizer.m index 673904d6a83..a74f72afbe3 100644 --- a/samples/client/petstore/objc/SwaggerClient/SWGSanitizer.m +++ b/samples/client/petstore/objc/SwaggerClient/SWGSanitizer.m @@ -16,20 +16,20 @@ NSString * SWGPercentEscapedStringFromString(NSString *string) { NSMutableString *escaped = @"".mutableCopy; while (index < string.length) { - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wgnu" - NSUInteger length = MIN(string.length - index, batchSize); - #pragma GCC diagnostic pop - NSRange range = NSMakeRange(index, length); + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wgnu" + NSUInteger length = MIN(string.length - index, batchSize); + #pragma GCC diagnostic pop + NSRange range = NSMakeRange(index, length); - // To avoid breaking up character sequences such as 👴🏻👮🏽 - range = [string rangeOfComposedCharacterSequencesForRange:range]; + // To avoid breaking up character sequences such as 👴🏻👮🏽 + range = [string rangeOfComposedCharacterSequencesForRange:range]; - NSString *substring = [string substringWithRange:range]; - NSString *encoded = [substring stringByAddingPercentEncodingWithAllowedCharacters:allowedCharacterSet]; - [escaped appendString:encoded]; + NSString *substring = [string substringWithRange:range]; + NSString *encoded = [substring stringByAddingPercentEncodingWithAllowedCharacters:allowedCharacterSet]; + [escaped appendString:encoded]; - index += range.length; + index += range.length; } return escaped; @@ -37,10 +37,24 @@ NSString * SWGPercentEscapedStringFromString(NSString *string) { @interface SWGSanitizer () +@property (nonatomic, strong) NSRegularExpression* jsonHeaderTypeExpression; + @end @implementation SWGSanitizer +static NSString * kApplicationJSONType = @"application/json"; + +-(instancetype)init { + self = [super init]; + if ( !self ) { + return nil; + } + _jsonHeaderTypeExpression = [NSRegularExpression regularExpressionWithPattern:@"(.*)application(.*)json(.*)" options:NSRegularExpressionCaseInsensitive error:nil]; + return self; +} + + - (id) sanitizeForSerialization:(id) object { if (object == nil) { return nil; @@ -49,7 +63,7 @@ NSString * SWGPercentEscapedStringFromString(NSString *string) { return object; } else if ([object isKindOfClass:[NSDate class]]) { - return [object ISO8601String]; + return [self dateParameterToString:object]; } else if ([object isKindOfClass:[NSArray class]]) { NSArray *objectArray = object; @@ -93,7 +107,7 @@ NSString * SWGPercentEscapedStringFromString(NSString *string) { return [param stringValue]; } else if ([param isKindOfClass:[NSDate class]]) { - return [param ISO8601String]; + return [self dateParameterToString:param]; } else if ([param isKindOfClass:[NSArray class]]) { NSMutableArray *mutableParam = [NSMutableArray array]; @@ -111,30 +125,26 @@ NSString * SWGPercentEscapedStringFromString(NSString *string) { } } +- (NSString *)dateParameterToString:(id)param { + return [param ISO8601String]; +} + #pragma mark - Utility Methods /* * Detect `Accept` from accepts */ - (NSString *) selectHeaderAccept:(NSArray *)accepts { - if (accepts == nil || [accepts count] == 0) { + if (accepts.count == 0) { return @""; } - NSMutableArray *lowerAccepts = [[NSMutableArray alloc] initWithCapacity:[accepts count]]; for (NSString *string in accepts) { - NSString * lowerAccept = [string lowercaseString]; - // use rangeOfString instead of containsString for iOS 7 support - if ([lowerAccept rangeOfString:@"application/json"].location != NSNotFound) { - return @"application/json"; + if ([self.jsonHeaderTypeExpression matchesInString:string options:0 range:NSMakeRange(0, [string length])].count > 0) { + return kApplicationJSONType; } - [lowerAccepts addObject:lowerAccept]; + [lowerAccepts addObject:[string lowercaseString]]; } - - if (lowerAccepts.count == 1) { - return [lowerAccepts firstObject]; - } - return [lowerAccepts componentsJoinedByString:@", "]; } @@ -142,21 +152,17 @@ NSString * SWGPercentEscapedStringFromString(NSString *string) { * Detect `Content-Type` from contentTypes */ - (NSString *) selectHeaderContentType:(NSArray *)contentTypes { - if (contentTypes == nil || [contentTypes count] == 0) { - return @"application/json"; + if (contentTypes.count == 0) { + return kApplicationJSONType; } - NSMutableArray *lowerContentTypes = [[NSMutableArray alloc] initWithCapacity:[contentTypes count]]; - [contentTypes enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { - [lowerContentTypes addObject:[obj lowercaseString]]; - }]; - - if ([lowerContentTypes containsObject:@"application/json"]) { - return @"application/json"; - } - else { - return lowerContentTypes[0]; + for (NSString *string in contentTypes) { + if([self.jsonHeaderTypeExpression matchesInString:string options:0 range:NSMakeRange(0, [string length])].count > 0){ + return kApplicationJSONType; + } + [lowerContentTypes addObject:[string lowercaseString]]; } + return [lowerContentTypes firstObject]; } @end diff --git a/samples/client/petstore/objc/SwaggerClientTests/Tests/SWGApiClientTest.m b/samples/client/petstore/objc/SwaggerClientTests/Tests/SWGApiClientTest.m index 644b50f6504..205c3a290f8 100644 --- a/samples/client/petstore/objc/SwaggerClientTests/Tests/SWGApiClientTest.m +++ b/samples/client/petstore/objc/SwaggerClientTests/Tests/SWGApiClientTest.m @@ -33,6 +33,18 @@ accepts = @[@"APPLICATION/xml", @"APPLICATION/json"]; XCTAssertEqualObjects([sanitizer selectHeaderAccept:accepts], @"application/json"); + + accepts = @[@"application/vnd.github+json", @"application/vnd.github+xml"]; + XCTAssertEqualObjects([sanitizer selectHeaderAccept:accepts], @"application/json"); + + accepts = @[@"application/json;charset=utf-8", @"application/vnd.github+xml"]; + XCTAssertEqualObjects([sanitizer selectHeaderAccept:accepts], @"application/json"); + + accepts = @[@"application/vnd.github.v3.html+json", @"application/vnd.github+xml"]; + XCTAssertEqualObjects([sanitizer selectHeaderAccept:accepts], @"application/json"); + + accepts = @[@"application/vnd.github.v3.html+json"]; + XCTAssertEqualObjects([sanitizer selectHeaderAccept:accepts], @"application/json"); accepts = @[@"text/plain", @"application/xml"]; XCTAssertEqualObjects([sanitizer selectHeaderAccept:accepts], @"text/plain, application/xml"); @@ -53,7 +65,16 @@ contentTypes = @[@"APPLICATION/xml", @"APPLICATION/json"]; XCTAssertEqualObjects([sanitizer selectHeaderContentType:contentTypes], @"application/json"); - + + contentTypes = @[@"application/vnd.github+json", @"application/vnd.github+xml"]; + XCTAssertEqualObjects([sanitizer selectHeaderContentType:contentTypes], @"application/json"); + + contentTypes = @[@"application/json;charset=utf-8", @"application/vnd.github+xml"]; + XCTAssertEqualObjects([sanitizer selectHeaderContentType:contentTypes], @"application/json"); + + contentTypes = @[@"application/vnd.github.v3.html+json", @"application/vnd.github+xml"]; + XCTAssertEqualObjects([sanitizer selectHeaderContentType:contentTypes], @"application/json"); + contentTypes = @[@"text/plain", @"application/xml"]; XCTAssertEqualObjects([sanitizer selectHeaderContentType:contentTypes], @"text/plain"); From ac37c4364954f1baa7061ee45f068c1037b0119c Mon Sep 17 00:00:00 2001 From: Mateusz Mackowiak Date: Wed, 11 May 2016 18:20:15 +0200 Subject: [PATCH 3/3] [Objc] Moved [request setHTTPShouldHandleCookies:NO]; to postProcessRequest method for easier override to modify request. --- .../main/resources/objc/ApiClient-body.mustache | 15 ++++++++------- samples/client/petstore/objc/README.md | 2 +- .../petstore/objc/SwaggerClient/SWGApiClient.m | 15 ++++++++------- 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/modules/swagger-codegen/src/main/resources/objc/ApiClient-body.mustache b/modules/swagger-codegen/src/main/resources/objc/ApiClient-body.mustache index 6b9d3e841bb..37bdfd8f4a7 100644 --- a/modules/swagger-codegen/src/main/resources/objc/ApiClient-body.mustache +++ b/modules/swagger-codegen/src/main/resources/objc/ApiClient-body.mustache @@ -329,10 +329,7 @@ static NSString * {{classPrefix}}__fileNameForResponse(NSURLResponse *response) } // request cache - BOOL hasHeaderParams = false; - if (headerParams != nil && [headerParams count] > 0) { - hasHeaderParams = true; - } + BOOL hasHeaderParams = [headerParams count] > 0; if (offlineState) { {{classPrefix}}DebugLog(@"%@ cache forced", resourcePath); [request setCachePolicy:NSURLRequestReturnCacheDataDontLoad]; @@ -353,9 +350,7 @@ static NSString * {{classPrefix}}__fileNameForResponse(NSURLResponse *response) } [self.requestSerializer setValue:responseContentType forHTTPHeaderField:@"Accept"]; - - // Always disable cookies! - [request setHTTPShouldHandleCookies:NO]; + [self postProcessRequest:request]; NSNumber* requestId = [{{classPrefix}}ApiClient queueRequest]; if ([responseType isEqualToString:@"NSURL*"] || [responseType isEqualToString:@"NSURL"]) { @@ -376,6 +371,12 @@ static NSString * {{classPrefix}}__fileNameForResponse(NSURLResponse *response) 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 diff --git a/samples/client/petstore/objc/README.md b/samples/client/petstore/objc/README.md index b411635fe8a..6fbc67a7fae 100644 --- a/samples/client/petstore/objc/README.md +++ b/samples/client/petstore/objc/README.md @@ -6,7 +6,7 @@ This ObjC package is automatically generated by the [Swagger Codegen](https://gi - API version: 1.0.0 - Package version: -- Build date: 2016-05-11T17:37:37.440+02:00 +- Build date: 2016-05-11T18:16:45.229+02:00 - Build package: class io.swagger.codegen.languages.ObjcClientCodegen ## Requirements diff --git a/samples/client/petstore/objc/SwaggerClient/SWGApiClient.m b/samples/client/petstore/objc/SwaggerClient/SWGApiClient.m index a6745932320..55e84a056a4 100644 --- a/samples/client/petstore/objc/SwaggerClient/SWGApiClient.m +++ b/samples/client/petstore/objc/SwaggerClient/SWGApiClient.m @@ -329,10 +329,7 @@ static NSString * SWG__fileNameForResponse(NSURLResponse *response) { } // request cache - BOOL hasHeaderParams = false; - if (headerParams != nil && [headerParams count] > 0) { - hasHeaderParams = true; - } + BOOL hasHeaderParams = [headerParams count] > 0; if (offlineState) { SWGDebugLog(@"%@ cache forced", resourcePath); [request setCachePolicy:NSURLRequestReturnCacheDataDontLoad]; @@ -353,9 +350,7 @@ static NSString * SWG__fileNameForResponse(NSURLResponse *response) { } [self.requestSerializer setValue:responseContentType forHTTPHeaderField:@"Accept"]; - - // Always disable cookies! - [request setHTTPShouldHandleCookies:NO]; + [self postProcessRequest:request]; NSNumber* requestId = [SWGApiClient queueRequest]; if ([responseType isEqualToString:@"NSURL*"] || [responseType isEqualToString:@"NSURL"]) { @@ -376,6 +371,12 @@ static NSString * SWG__fileNameForResponse(NSURLResponse *response) { 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