forked from loafle/openapi-generator-original
[Swift] shorter readme (#19884)
* [Swift] shorter readme * [Swift] update docs * [Swift] update docs * [Swift] format codegen * [Swift] try to make CI pass
This commit is contained in:
parent
65b1859161
commit
ca032113f2
@ -477,6 +477,8 @@ Here is a working sample that put's together all of this.
|
|||||||
|
|
||||||
### How do I migrate from the Swift 5 generator to the swift 6 generator?
|
### How do I migrate from the Swift 5 generator to the swift 6 generator?
|
||||||
|
|
||||||
|
- Change the generator to the new `swift6` generator, e.g. `openapi-generator generate -i https://raw.githubusercontent.com/openapitools/openapi-generator/master/modules/openapi-generator/src/test/resources/3_0/petstore.yaml -g swift6 -o /tmp/test/`
|
||||||
|
- Check the `swift6` [URLSession](https://github.com/OpenAPITools/openapi-generator/tree/master/samples/client/petstore/swift6/urlsessionLibrary) and [Alamofire](https://github.com/OpenAPITools/openapi-generator/tree/master/samples/client/petstore/swift6/alamofireLibrary) samples.
|
||||||
- The infrastructure files have been moved to a new directory called `Infrastructure`. Please delete the old ones.
|
- The infrastructure files have been moved to a new directory called `Infrastructure`. Please delete the old ones.
|
||||||
- The `AnyCodable` dependency has been removed and replaced with a new enum called `JSONValue`, allowing you to use this generator without external dependencies.
|
- The `AnyCodable` dependency has been removed and replaced with a new enum called `JSONValue`, allowing you to use this generator without external dependencies.
|
||||||
- The `Combine` response is now deferred by default, meaning the request will only start when you begin listening to it. To restore the previous behavior, set the `combineDeferred` flag to `false`.
|
- The `Combine` response is now deferred by default, meaning the request will only start when you begin listening to it. To restore the previous behavior, set the `combineDeferred` flag to `false`.
|
||||||
|
@ -366,7 +366,6 @@ public class Swift5ClientCodegen extends DefaultCodegen implements CodegenConfig
|
|||||||
codegenModel.vars = codegenProperties;
|
codegenModel.vars = codegenProperties;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return codegenModel;
|
return codegenModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -847,7 +846,6 @@ public class Swift5ClientCodegen extends DefaultCodegen implements CodegenConfig
|
|||||||
operationId = camelize(sanitizeName("call_" + operationId), LOWERCASE_FIRST_LETTER);
|
operationId = camelize(sanitizeName("call_" + operationId), LOWERCASE_FIRST_LETTER);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return operationId;
|
return operationId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1306,9 +1304,11 @@ public class Swift5ClientCodegen extends DefaultCodegen implements CodegenConfig
|
|||||||
System.out.println("# swift5 generator is contributed by Bruno Coelho (https://github.com/4brunu). #");
|
System.out.println("# swift5 generator is contributed by Bruno Coelho (https://github.com/4brunu). #");
|
||||||
System.out.println("# Please support his work directly via https://paypal.com/paypalme/4brunu \uD83D\uDE4F #");
|
System.out.println("# Please support his work directly via https://paypal.com/paypalme/4brunu \uD83D\uDE4F #");
|
||||||
System.out.println("# #");
|
System.out.println("# #");
|
||||||
System.out.println("# There is a new `swift6` generator, that is currently in beta. #");
|
System.out.println("# There is a new swift6 generator, that is currently in beta. #");
|
||||||
System.out.println("# Try it and give us your feedback. #");
|
System.out.println("# Try it and give us your feedback. #");
|
||||||
System.out.println("# https://openapi-generator.tech/docs/generators/swift6 #");
|
System.out.println("# https://openapi-generator.tech/docs/generators/swift6 #");
|
||||||
|
System.out.println("# #");
|
||||||
|
System.out.println("# If you need help migrating from the swift5 to the swift6 generator, check the following url.#");
|
||||||
System.out.println("# https://openapi-generator.tech/docs/faq-generators/#how-do-i-migrate-from-the-swift-5-generator-to-the-swift-6-generator");
|
System.out.println("# https://openapi-generator.tech/docs/faq-generators/#how-do-i-migrate-from-the-swift-5-generator-to-the-swift-6-generator");
|
||||||
System.out.println("################################################################################");
|
System.out.println("################################################################################");
|
||||||
}
|
}
|
||||||
|
@ -86,45 +86,25 @@ public class Swift6ClientCodegen extends DefaultCodegen implements CodegenConfig
|
|||||||
protected static final String RESPONSE_LIBRARY_ASYNC_AWAIT = "AsyncAwait";
|
protected static final String RESPONSE_LIBRARY_ASYNC_AWAIT = "AsyncAwait";
|
||||||
protected static final String RESPONSE_LIBRARY_OBJC_BLOCK = "ObjcBlock";
|
protected static final String RESPONSE_LIBRARY_OBJC_BLOCK = "ObjcBlock";
|
||||||
protected static final String[] RESPONSE_LIBRARIES = { RESPONSE_LIBRARY_ASYNC_AWAIT, RESPONSE_LIBRARY_COMBINE, RESPONSE_LIBRARY_RESULT, RESPONSE_LIBRARY_RX_SWIFT, RESPONSE_LIBRARY_OBJC_BLOCK, RESPONSE_LIBRARY_PROMISE_KIT };
|
protected static final String[] RESPONSE_LIBRARIES = { RESPONSE_LIBRARY_ASYNC_AWAIT, RESPONSE_LIBRARY_COMBINE, RESPONSE_LIBRARY_RESULT, RESPONSE_LIBRARY_RX_SWIFT, RESPONSE_LIBRARY_OBJC_BLOCK, RESPONSE_LIBRARY_PROMISE_KIT };
|
||||||
@Setter
|
@Setter protected String projectName = "OpenAPIClient";
|
||||||
protected String projectName = "OpenAPIClient";
|
@Setter protected boolean nonPublicApi = false;
|
||||||
@Setter
|
@Setter protected boolean objcCompatible = false;
|
||||||
protected boolean nonPublicApi = false;
|
@Setter protected boolean readonlyProperties = false;
|
||||||
@Setter
|
@Setter protected boolean swiftUseApiNamespace = false;
|
||||||
protected boolean objcCompatible = false;
|
@Setter protected boolean useSPMFileStructure = true;
|
||||||
@Setter
|
@Setter protected String swiftPackagePath = "Sources" + File.separator + projectName;
|
||||||
protected boolean readonlyProperties = false;
|
@Setter protected boolean oneOfUnknownDefaultCase = false;
|
||||||
@Setter
|
@Setter protected boolean useClasses = false;
|
||||||
protected boolean swiftUseApiNamespace = false;
|
@Setter protected boolean useBacktickEscapes = false;
|
||||||
@Setter
|
@Setter protected boolean generateModelAdditionalProperties = true;
|
||||||
protected boolean useSPMFileStructure = true;
|
@Setter protected boolean hashableModels = true;
|
||||||
@Setter
|
@Setter protected boolean useJsonEncodable = true;
|
||||||
protected String swiftPackagePath = "Sources" + File.separator + projectName;
|
@Getter @Setter protected boolean mapFileBinaryToData = false;
|
||||||
@Setter
|
@Setter protected boolean useCustomDateWithoutTime = false;
|
||||||
protected boolean oneOfUnknownDefaultCase = false;
|
@Setter protected boolean validatable = true;
|
||||||
@Setter
|
@Setter protected boolean apiStaticMethod = true;
|
||||||
protected boolean useClasses = false;
|
@Setter protected boolean combineDeferred = true;
|
||||||
@Setter
|
@Setter protected String[] responseAs = { RESPONSE_LIBRARY_ASYNC_AWAIT };
|
||||||
protected boolean useBacktickEscapes = false;
|
|
||||||
@Setter
|
|
||||||
protected boolean generateModelAdditionalProperties = true;
|
|
||||||
@Setter
|
|
||||||
protected boolean hashableModels = true;
|
|
||||||
@Setter
|
|
||||||
protected boolean useJsonEncodable = true;
|
|
||||||
@Getter
|
|
||||||
@Setter
|
|
||||||
protected boolean mapFileBinaryToData = false;
|
|
||||||
@Setter
|
|
||||||
protected boolean useCustomDateWithoutTime = false;
|
|
||||||
@Setter
|
|
||||||
protected boolean validatable = true;
|
|
||||||
@Setter
|
|
||||||
protected boolean apiStaticMethod = true;
|
|
||||||
@Setter
|
|
||||||
protected boolean combineDeferred = true;
|
|
||||||
@Setter
|
|
||||||
protected String[] responseAs = { RESPONSE_LIBRARY_ASYNC_AWAIT };
|
|
||||||
protected String sourceFolder = swiftPackagePath;
|
protected String sourceFolder = swiftPackagePath;
|
||||||
protected HashSet objcReservedWords;
|
protected HashSet objcReservedWords;
|
||||||
protected String apiDocPath = "docs/";
|
protected String apiDocPath = "docs/";
|
||||||
@ -184,19 +164,20 @@ public class Swift6ClientCodegen extends DefaultCodegen implements CodegenConfig
|
|||||||
"Empty",
|
"Empty",
|
||||||
"AnyObject",
|
"AnyObject",
|
||||||
"Any",
|
"Any",
|
||||||
"Decimal"));
|
"Decimal")
|
||||||
|
);
|
||||||
|
|
||||||
objcReservedWords = new HashSet<>(
|
objcReservedWords = new HashSet<>(
|
||||||
Arrays.asList(
|
Arrays.asList(
|
||||||
// Added for Objective-C compatibility
|
// Added for Objective-C compatibility
|
||||||
"id", "description", "NSArray", "NSURL", "CGFloat", "NSSet", "NSString", "NSInteger",
|
"id", "description", "NSArray", "NSURL", "CGFloat", "NSSet", "NSString", "NSInteger", "NSUInteger",
|
||||||
"NSUInteger",
|
|
||||||
"NSError", "NSDictionary",
|
"NSError", "NSDictionary",
|
||||||
// 'Property 'hash' with type 'String' cannot override a property with type
|
// 'Property 'hash' with type 'String' cannot override a property with type 'Int' (when objcCompatible=true)
|
||||||
// 'Int' (when objcCompatible=true)
|
|
||||||
"hash",
|
"hash",
|
||||||
// Cannot override with a stored property 'className'
|
// Cannot override with a stored property 'className'
|
||||||
"className"));
|
"className"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
reservedWords = new HashSet<>(
|
reservedWords = new HashSet<>(
|
||||||
Arrays.asList(
|
Arrays.asList(
|
||||||
@ -207,29 +188,22 @@ public class Swift6ClientCodegen extends DefaultCodegen implements CodegenConfig
|
|||||||
// https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/doc/uid/TP40014097-CH30-ID410
|
// https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/doc/uid/TP40014097-CH30-ID410
|
||||||
//
|
//
|
||||||
// Keywords used in declarations
|
// Keywords used in declarations
|
||||||
"associatedtype", "class", "deinit", "enum", "extension", "fileprivate", "func", "import",
|
"associatedtype", "class", "deinit", "enum", "extension", "fileprivate", "func", "import", "init",
|
||||||
"init",
|
"inout", "internal", "let", "open", "operator", "private", "protocol", "public", "static", "struct",
|
||||||
"inout", "internal", "let", "open", "operator", "private", "protocol", "public", "static",
|
|
||||||
"struct",
|
|
||||||
"subscript", "typealias", "var",
|
"subscript", "typealias", "var",
|
||||||
// Keywords uses in statements
|
// Keywords uses in statements
|
||||||
"break", "case", "continue", "default", "defer", "do", "else", "fallthrough", "for", "guard",
|
"break", "case", "continue", "default", "defer", "do", "else", "fallthrough", "for", "guard", "if",
|
||||||
"if",
|
|
||||||
"in", "repeat", "return", "switch", "where", "while",
|
"in", "repeat", "return", "switch", "where", "while",
|
||||||
// Keywords used in expressions and types
|
// Keywords used in expressions and types
|
||||||
"as", "Any", "catch", "false", "is", "nil", "rethrows", "super", "self", "Self", "throw",
|
"as", "Any", "catch", "false", "is", "nil", "rethrows", "super", "self", "Self", "throw", "throws", "true", "try",
|
||||||
"throws", "true", "try",
|
|
||||||
// Keywords used in patterns
|
// Keywords used in patterns
|
||||||
"_",
|
"_",
|
||||||
// Keywords that begin with a number sign
|
// Keywords that begin with a number sign
|
||||||
"#available", "#colorLiteral", "#column", "#else", "#elseif", "#endif", "#file", "#fileLiteral",
|
"#available", "#colorLiteral", "#column", "#else", "#elseif", "#endif", "#file", "#fileLiteral", "#function", "#if",
|
||||||
"#function", "#if",
|
|
||||||
"#imageLiteral", "#line", "#selector", "#sourceLocation",
|
"#imageLiteral", "#line", "#selector", "#sourceLocation",
|
||||||
// Keywords reserved in particular contexts
|
// Keywords reserved in particular contexts
|
||||||
"associativity", "convenience", "dynamic", "didSet", "final", "get", "infix", "indirect",
|
"associativity", "convenience", "dynamic", "didSet", "final", "get", "infix", "indirect", "lazy", "left",
|
||||||
"lazy", "left",
|
"mutating", "none", "nonmutating", "optional", "override", "postfix", "precedence", "prefix", "Protocol",
|
||||||
"mutating", "none", "nonmutating", "optional", "override", "postfix", "precedence", "prefix",
|
|
||||||
"Protocol",
|
|
||||||
"required", "right", "set", "Type", "unowned", "weak", "willSet",
|
"required", "right", "set", "Type", "unowned", "weak", "willSet",
|
||||||
|
|
||||||
//
|
//
|
||||||
@ -239,8 +213,7 @@ public class Swift6ClientCodegen extends DefaultCodegen implements CodegenConfig
|
|||||||
// Numbers and Basic Values
|
// Numbers and Basic Values
|
||||||
"Bool", "Int", "Double", "Float", "Range", "ClosedRange", "Error", "Optional",
|
"Bool", "Int", "Double", "Float", "Range", "ClosedRange", "Error", "Optional",
|
||||||
// Special-Use Numeric Types
|
// Special-Use Numeric Types
|
||||||
"UInt", "UInt8", "UInt16", "UInt32", "UInt64", "Int8", "Int16", "Int32", "Int64", "Float80",
|
"UInt", "UInt8", "UInt16", "UInt32", "UInt64", "Int8", "Int16", "Int32", "Int64", "Float80", "Float32", "Float64",
|
||||||
"Float32", "Float64",
|
|
||||||
// Strings and Text
|
// Strings and Text
|
||||||
"String", "Character", "Unicode", "StaticString",
|
"String", "Character", "Unicode", "StaticString",
|
||||||
// Collections
|
// Collections
|
||||||
@ -250,7 +223,9 @@ public class Swift6ClientCodegen extends DefaultCodegen implements CodegenConfig
|
|||||||
"URL", "Data", "Codable", "Encodable", "Decodable",
|
"URL", "Data", "Codable", "Encodable", "Decodable",
|
||||||
|
|
||||||
// The following are other words we want to reserve
|
// The following are other words we want to reserve
|
||||||
"Void", "AnyObject", "Class", "dynamicType", "COLUMN", "FILE", "FUNCTION", "LINE"));
|
"Void", "AnyObject", "Class", "dynamicType", "COLUMN", "FILE", "FUNCTION", "LINE"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
typeMapping = new HashMap<>();
|
typeMapping = new HashMap<>();
|
||||||
typeMapping.put("array", "Array");
|
typeMapping.put("array", "Array");
|
||||||
@ -435,8 +410,7 @@ public class Swift6ClientCodegen extends DefaultCodegen implements CodegenConfig
|
|||||||
inner = ModelUtils.getAdditionalProperties(schema);
|
inner = ModelUtils.getAdditionalProperties(schema);
|
||||||
}
|
}
|
||||||
|
|
||||||
codegenModel.additionalPropertiesType = inner != null ? getTypeDeclaration(inner)
|
codegenModel.additionalPropertiesType = inner != null ? getTypeDeclaration(inner) : getSchemaType(additionalProperties);
|
||||||
: getSchemaType(additionalProperties);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -445,10 +419,8 @@ public class Swift6ClientCodegen extends DefaultCodegen implements CodegenConfig
|
|||||||
super.processOpts();
|
super.processOpts();
|
||||||
|
|
||||||
if (StringUtils.isEmpty(System.getenv("SWIFT_POST_PROCESS_FILE"))) {
|
if (StringUtils.isEmpty(System.getenv("SWIFT_POST_PROCESS_FILE"))) {
|
||||||
LOGGER.info(
|
LOGGER.info("Environment variable SWIFT_POST_PROCESS_FILE not defined so the Swift code may not be properly formatted. To define it, try 'export SWIFT_POST_PROCESS_FILE=/usr/local/bin/swiftformat' (Linux/Mac)");
|
||||||
"Environment variable SWIFT_POST_PROCESS_FILE not defined so the Swift code may not be properly formatted. To define it, try 'export SWIFT_POST_PROCESS_FILE=/usr/local/bin/swiftformat' (Linux/Mac)");
|
LOGGER.info("NOTE: To enable file post-processing, 'enablePostProcessFile' must be set to `true` (--enable-post-process-file for CLI).");
|
||||||
LOGGER.info(
|
|
||||||
"NOTE: To enable file post-processing, 'enablePostProcessFile' must be set to `true` (--enable-post-process-file for CLI).");
|
|
||||||
} else if (!this.isEnablePostProcessFile()) {
|
} else if (!this.isEnablePostProcessFile()) {
|
||||||
LOGGER.info("Warning: Environment variable 'SWIFT_POST_PROCESS_FILE' is set but file post-processing is not enabled. To enable file post-processing, 'enablePostProcessFile' must be set to `true` (--enable-post-process-file for CLI).");
|
LOGGER.info("Warning: Environment variable 'SWIFT_POST_PROCESS_FILE' is set but file post-processing is not enabled. To enable file post-processing, 'enablePostProcessFile' must be set to `true` (--enable-post-process-file for CLI).");
|
||||||
}
|
}
|
||||||
@ -536,8 +508,7 @@ public class Swift6ClientCodegen extends DefaultCodegen implements CodegenConfig
|
|||||||
sourceFolder = projectName + File.separator + "Classes" + File.separator + "OpenAPIs";
|
sourceFolder = projectName + File.separator + "Classes" + File.separator + "OpenAPIs";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (additionalProperties.containsKey(SWIFT_PACKAGE_PATH)
|
if (additionalProperties.containsKey(SWIFT_PACKAGE_PATH) && ((String) additionalProperties.get(SWIFT_PACKAGE_PATH)).length() > 0) {
|
||||||
&& ((String) additionalProperties.get(SWIFT_PACKAGE_PATH)).length() > 0) {
|
|
||||||
setSwiftPackagePath((String) additionalProperties.get(SWIFT_PACKAGE_PATH));
|
setSwiftPackagePath((String) additionalProperties.get(SWIFT_PACKAGE_PATH));
|
||||||
sourceFolder = swiftPackagePath;
|
sourceFolder = swiftPackagePath;
|
||||||
}
|
}
|
||||||
@ -547,8 +518,7 @@ public class Swift6ClientCodegen extends DefaultCodegen implements CodegenConfig
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (additionalProperties.containsKey(GENERATE_MODEL_ADDITIONAL_PROPERTIES)) {
|
if (additionalProperties.containsKey(GENERATE_MODEL_ADDITIONAL_PROPERTIES)) {
|
||||||
setGenerateModelAdditionalProperties(
|
setGenerateModelAdditionalProperties(convertPropertyToBooleanAndWriteBack(GENERATE_MODEL_ADDITIONAL_PROPERTIES));
|
||||||
convertPropertyToBooleanAndWriteBack(GENERATE_MODEL_ADDITIONAL_PROPERTIES));
|
|
||||||
}
|
}
|
||||||
additionalProperties.put(GENERATE_MODEL_ADDITIONAL_PROPERTIES, generateModelAdditionalProperties);
|
additionalProperties.put(GENERATE_MODEL_ADDITIONAL_PROPERTIES, generateModelAdditionalProperties);
|
||||||
|
|
||||||
@ -704,7 +674,7 @@ public class Swift6ClientCodegen extends DefaultCodegen implements CodegenConfig
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean isReservedWord(String word) {
|
protected boolean isReservedWord(String word) {
|
||||||
return word != null && reservedWords.contains(word); // don't lowercase as super does
|
return word != null && reservedWords.contains(word); //don't lowercase as super does
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -731,8 +701,7 @@ public class Swift6ClientCodegen extends DefaultCodegen implements CodegenConfig
|
|||||||
public String getTypeDeclaration(Schema p) {
|
public String getTypeDeclaration(Schema p) {
|
||||||
if (ModelUtils.isArraySchema(p)) {
|
if (ModelUtils.isArraySchema(p)) {
|
||||||
Schema inner = ModelUtils.getSchemaItems(p);
|
Schema inner = ModelUtils.getSchemaItems(p);
|
||||||
return ModelUtils.isSet(p) ? "Set<" + getTypeDeclaration(inner) + ">"
|
return ModelUtils.isSet(p) ? "Set<" + getTypeDeclaration(inner) + ">" : "[" + getTypeDeclaration(inner) + "]";
|
||||||
: "[" + getTypeDeclaration(inner) + "]";
|
|
||||||
} else if (ModelUtils.isMapSchema(p)) {
|
} else if (ModelUtils.isMapSchema(p)) {
|
||||||
Schema inner = ModelUtils.getAdditionalProperties(p);
|
Schema inner = ModelUtils.getAdditionalProperties(p);
|
||||||
return "[String: " + getTypeDeclaration(inner) + "]";
|
return "[String: " + getTypeDeclaration(inner) + "]";
|
||||||
@ -835,13 +804,10 @@ public class Swift6ClientCodegen extends DefaultCodegen implements CodegenConfig
|
|||||||
if (ModelUtils.isIntegerSchema(p) || ModelUtils.isNumberSchema(p) || ModelUtils.isBooleanSchema(p)) {
|
if (ModelUtils.isIntegerSchema(p) || ModelUtils.isNumberSchema(p) || ModelUtils.isBooleanSchema(p)) {
|
||||||
return p.getDefault().toString();
|
return p.getDefault().toString();
|
||||||
} else if (ModelUtils.isDateTimeSchema(p)) {
|
} else if (ModelUtils.isDateTimeSchema(p)) {
|
||||||
// Datetime time stamps in Swift are expressed as Seconds with Microsecond
|
// Datetime time stamps in Swift are expressed as Seconds with Microsecond precision.
|
||||||
// precision.
|
// In Java, we need to be creative to get the Timestamp in Microseconds as a long.
|
||||||
// In Java, we need to be creative to get the Timestamp in Microseconds as a
|
|
||||||
// long.
|
|
||||||
Instant instant = ((OffsetDateTime) p.getDefault()).toInstant();
|
Instant instant = ((OffsetDateTime) p.getDefault()).toInstant();
|
||||||
long epochMicro = TimeUnit.SECONDS.toMicros(instant.getEpochSecond())
|
long epochMicro = TimeUnit.SECONDS.toMicros(instant.getEpochSecond()) + (instant.get(ChronoField.MICRO_OF_SECOND));
|
||||||
+ (instant.get(ChronoField.MICRO_OF_SECOND));
|
|
||||||
return "Date(timeIntervalSince1970: " + epochMicro + ".0 / 1_000_000)";
|
return "Date(timeIntervalSince1970: " + epochMicro + ".0 / 1_000_000)";
|
||||||
} else if (ModelUtils.isStringSchema(p)) {
|
} else if (ModelUtils.isStringSchema(p)) {
|
||||||
return "\"" + escapeText(String.valueOf(p.getDefault())) + "\"";
|
return "\"" + escapeText(String.valueOf(p.getDefault())) + "\"";
|
||||||
@ -909,8 +875,7 @@ public class Swift6ClientCodegen extends DefaultCodegen implements CodegenConfig
|
|||||||
|
|
||||||
// operationId starts with a number
|
// operationId starts with a number
|
||||||
if (operationId.matches("^\\d.*")) {
|
if (operationId.matches("^\\d.*")) {
|
||||||
LOGGER.warn("{} (starting with a number) cannot be used as method name. Renamed to {}", operationId,
|
LOGGER.warn("{} (starting with a number) cannot be used as method name. Renamed to {}", operationId, camelize(sanitizeName("call_" + operationId), LOWERCASE_FIRST_LETTER));
|
||||||
camelize(sanitizeName("call_" + operationId), LOWERCASE_FIRST_LETTER));
|
|
||||||
operationId = camelize(sanitizeName("call_" + operationId), LOWERCASE_FIRST_LETTER);
|
operationId = camelize(sanitizeName("call_" + operationId), LOWERCASE_FIRST_LETTER);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1055,8 +1020,7 @@ public class Swift6ClientCodegen extends DefaultCodegen implements CodegenConfig
|
|||||||
|
|
||||||
// for symbol, e.g. $, #
|
// for symbol, e.g. $, #
|
||||||
if (getSymbolName(name) != null) {
|
if (getSymbolName(name) != null) {
|
||||||
return camelize(WordUtils.capitalizeFully(getSymbolName(name).toUpperCase(Locale.ROOT)),
|
return camelize(WordUtils.capitalizeFully(getSymbolName(name).toUpperCase(Locale.ROOT)), LOWERCASE_FIRST_LETTER);
|
||||||
LOWERCASE_FIRST_LETTER);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Camelize only when we have a structure defined below
|
// Camelize only when we have a structure defined below
|
||||||
@ -1079,7 +1043,7 @@ public class Swift6ClientCodegen extends DefaultCodegen implements CodegenConfig
|
|||||||
return replaceSpecialCharacters(name);
|
return replaceSpecialCharacters(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
char[] separators = { '-', '_', ' ', ':', '(', ')' };
|
char[] separators = {'-', '_', ' ', ':', '(', ')'};
|
||||||
return camelize(replaceSpecialCharacters(WordUtils.capitalizeFully(StringUtils.lowerCase(name), separators)
|
return camelize(replaceSpecialCharacters(WordUtils.capitalizeFully(StringUtils.lowerCase(name), separators)
|
||||||
.replaceAll("[-_ :\\(\\)]", "")),
|
.replaceAll("[-_ :\\(\\)]", "")),
|
||||||
LOWERCASE_FIRST_LETTER);
|
LOWERCASE_FIRST_LETTER);
|
||||||
@ -1169,8 +1133,7 @@ public class Swift6ClientCodegen extends DefaultCodegen implements CodegenConfig
|
|||||||
//
|
//
|
||||||
// CodegenProperty.vendorExtensions["x-codegen-escaped-property-name"] = true
|
// CodegenProperty.vendorExtensions["x-codegen-escaped-property-name"] = true
|
||||||
//
|
//
|
||||||
// Also, if any property in the model has x-codegen-escaped-property-name=true,
|
// Also, if any property in the model has x-codegen-escaped-property-name=true, then we mark:
|
||||||
// then we mark:
|
|
||||||
//
|
//
|
||||||
// CodegenModel.vendorExtensions["x-codegen-has-escaped-property-names"] = true
|
// CodegenModel.vendorExtensions["x-codegen-has-escaped-property-names"] = true
|
||||||
//
|
//
|
||||||
@ -1188,8 +1151,7 @@ public class Swift6ClientCodegen extends DefaultCodegen implements CodegenConfig
|
|||||||
if (prop.defaultValue == null || prop.defaultValue.equals("null")) {
|
if (prop.defaultValue == null || prop.defaultValue.equals("null")) {
|
||||||
prop.vendorExtensions.put("x-null-encodable-default-value", ".encodeNull");
|
prop.vendorExtensions.put("x-null-encodable-default-value", ".encodeNull");
|
||||||
} else {
|
} else {
|
||||||
prop.vendorExtensions.put("x-null-encodable-default-value",
|
prop.vendorExtensions.put("x-null-encodable-default-value", ".encodeValue(" + prop.defaultValue + ")");
|
||||||
".encodeValue(" + prop.defaultValue + ")");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1259,8 +1221,7 @@ public class Swift6ClientCodegen extends DefaultCodegen implements CodegenConfig
|
|||||||
return objs;
|
return objs;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String constructExampleCode(CodegenParameter codegenParameter, HashMap<String, CodegenModel> modelMaps,
|
public String constructExampleCode(CodegenParameter codegenParameter, HashMap<String, CodegenModel> modelMaps, Set<String> visitedModels) {
|
||||||
Set<String> visitedModels) {
|
|
||||||
if (codegenParameter.isArray) { // array
|
if (codegenParameter.isArray) { // array
|
||||||
return "[" + constructExampleCode(codegenParameter.items, modelMaps, visitedModels) + "]";
|
return "[" + constructExampleCode(codegenParameter.items, modelMaps, visitedModels) + "]";
|
||||||
} else if (codegenParameter.isMap) { // TODO: map, file type
|
} else if (codegenParameter.isMap) { // TODO: map, file type
|
||||||
@ -1302,15 +1263,13 @@ public class Swift6ClientCodegen extends DefaultCodegen implements CodegenConfig
|
|||||||
return constructExampleCode(modelMaps.get(codegenParameter.dataType), modelMaps, visitedModels);
|
return constructExampleCode(modelMaps.get(codegenParameter.dataType), modelMaps, visitedModels);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// LOGGER.error("Error in constructing examples. Failed to look up the model " +
|
//LOGGER.error("Error in constructing examples. Failed to look up the model " + codegenParameter.dataType);
|
||||||
// codegenParameter.dataType);
|
|
||||||
return "TODO";
|
return "TODO";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public String constructExampleCode(CodegenProperty codegenProperty, HashMap<String, CodegenModel> modelMaps,
|
public String constructExampleCode(CodegenProperty codegenProperty, HashMap<String, CodegenModel> modelMaps, Set<String> visitedModels) {
|
||||||
Set<String> visitedModels) {
|
|
||||||
if (codegenProperty.isArray) { // array
|
if (codegenProperty.isArray) { // array
|
||||||
return "[" + constructExampleCode(codegenProperty.items, modelMaps, visitedModels) + "]";
|
return "[" + constructExampleCode(codegenProperty.items, modelMaps, visitedModels) + "]";
|
||||||
} else if (codegenProperty.isMap) { // TODO: map, file type
|
} else if (codegenProperty.isMap) { // TODO: map, file type
|
||||||
@ -1350,21 +1309,18 @@ public class Swift6ClientCodegen extends DefaultCodegen implements CodegenConfig
|
|||||||
return constructExampleCode(modelMaps.get(codegenProperty.dataType), modelMaps, visitedModels);
|
return constructExampleCode(modelMaps.get(codegenProperty.dataType), modelMaps, visitedModels);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// LOGGER.error("Error in constructing examples. Failed to look up the model " +
|
//LOGGER.error("Error in constructing examples. Failed to look up the model " + codegenProperty.dataType);
|
||||||
// codegenProperty.dataType);
|
|
||||||
return "\"TODO\"";
|
return "\"TODO\"";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public String constructExampleCode(CodegenModel codegenModel, HashMap<String, CodegenModel> modelMaps,
|
public String constructExampleCode(CodegenModel codegenModel, HashMap<String, CodegenModel> modelMaps, Set<String> visitedModels) {
|
||||||
Set<String> visitedModels) {
|
|
||||||
String example;
|
String example;
|
||||||
example = codegenModel.name + "(";
|
example = codegenModel.name + "(";
|
||||||
List<String> propertyExamples = new ArrayList<>();
|
List<String> propertyExamples = new ArrayList<>();
|
||||||
for (CodegenProperty codegenProperty : codegenModel.vars) {
|
for (CodegenProperty codegenProperty : codegenModel.vars) {
|
||||||
propertyExamples
|
propertyExamples.add(codegenProperty.name + ": " + constructExampleCode(codegenProperty, modelMaps, visitedModels));
|
||||||
.add(codegenProperty.name + ": " + constructExampleCode(codegenProperty, modelMaps, visitedModels));
|
|
||||||
}
|
}
|
||||||
example += StringUtils.join(propertyExamples, ", ");
|
example += StringUtils.join(propertyExamples, ", ");
|
||||||
example += ")";
|
example += ")";
|
||||||
@ -1375,13 +1331,14 @@ public class Swift6ClientCodegen extends DefaultCodegen implements CodegenConfig
|
|||||||
public void postProcess() {
|
public void postProcess() {
|
||||||
System.out.println("################################################################################");
|
System.out.println("################################################################################");
|
||||||
System.out.println("# Thanks for using OpenAPI Generator. #");
|
System.out.println("# Thanks for using OpenAPI Generator. #");
|
||||||
System.out
|
System.out.println("# Please consider donation to help us maintain this project \uD83D\uDE4F #");
|
||||||
.println("# Please consider donation to help us maintain this project \uD83D\uDE4F #");
|
|
||||||
System.out.println("# https://opencollective.com/openapi_generator/donate #");
|
System.out.println("# https://opencollective.com/openapi_generator/donate #");
|
||||||
System.out.println("# #");
|
System.out.println("# #");
|
||||||
System.out.println("# swift6 generator is contributed by Bruno Coelho (https://github.com/4brunu). #");
|
System.out.println("# swift6 generator is contributed by Bruno Coelho (https://github.com/4brunu). #");
|
||||||
System.out
|
System.out.println("# Please support his work directly via https://paypal.com/paypalme/4brunu \uD83D\uDE4F #");
|
||||||
.println("# Please support his work directly via https://paypal.com/paypalme/4brunu \uD83D\uDE4F #");
|
System.out.println("# #");
|
||||||
|
System.out.println("# If you need help migrating from the swift5 to the swift6 generator, check the following url.#");
|
||||||
|
System.out.println("# https://openapi-generator.tech/docs/faq-generators/#how-do-i-migrate-from-the-swift-5-generator-to-the-swift-6-generator");
|
||||||
System.out.println("################################################################################");
|
System.out.println("################################################################################");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,250 +78,20 @@ Class | Method | HTTP request | Description
|
|||||||
|
|
||||||
{{/authMethods}}
|
{{/authMethods}}
|
||||||
|
|
||||||
|
# How do I migrate from the Swift 5 generator to the swift 6 generator?
|
||||||
|
|
||||||
|
https://openapi-generator.tech/docs/faq-generators#how-do-i-migrate-from-the-swift-5-generator-to-the-swift-6-generator
|
||||||
{{#useURLSession}}
|
{{#useURLSession}}
|
||||||
|
|
||||||
### How do I implement bearer token authentication with URLSession on the Swift 5 API client?
|
### How do I implement bearer token authentication with URLSession on the Swift 5 API client?
|
||||||
|
|
||||||
First you subclass RequestBuilderFactory
|
https://openapi-generator.tech/docs/faq-generators#how-do-i-implement-bearer-token-authentication-with-urlsession-on-the-swift-5-api-client
|
||||||
```
|
|
||||||
class BearerRequestBuilderFactory: RequestBuilderFactory {
|
|
||||||
func getNonDecodableBuilder<T>() -> RequestBuilder<T>.Type {
|
|
||||||
BearerRequestBuilder<T>.self
|
|
||||||
}
|
|
||||||
|
|
||||||
func getBuilder<T: Decodable>() -> RequestBuilder<T>.Type {
|
|
||||||
BearerDecodableRequestBuilder<T>.self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Then you subclass URLSessionRequestBuilder and URLSessionDecodableRequestBuilder
|
|
||||||
```
|
|
||||||
class BearerRequestBuilder<T>: URLSessionRequestBuilder<T> {
|
|
||||||
@discardableResult
|
|
||||||
override func execute(_ apiResponseQueue: DispatchQueue = PetstoreClientAPI.apiResponseQueue, _ completion: @escaping (Result<Response<T>, ErrorResponse>) -> Void) -> RequestTask {
|
|
||||||
|
|
||||||
// Before making the request, we can validate if we have a bearer token to be able to make a request
|
|
||||||
BearerTokenHandler.refreshTokenIfDoesntExist {
|
|
||||||
|
|
||||||
// Here we make the request
|
|
||||||
super.execute(apiResponseQueue) { result in
|
|
||||||
|
|
||||||
switch result {
|
|
||||||
case .success:
|
|
||||||
// If we got a successful response, we send the response to the completion block
|
|
||||||
completion(result)
|
|
||||||
|
|
||||||
case let .failure(error):
|
|
||||||
|
|
||||||
// If we got a failure response, we will analyse the error to see what we should do with it
|
|
||||||
if case let ErrorResponse.error(_, data, response, error) = error {
|
|
||||||
|
|
||||||
// If the error is an ErrorResponse.error() we will analyse it to see if it's a 401, and if it's a 401, we will refresh the token and retry the request
|
|
||||||
BearerTokenHandler.refreshTokenIfUnauthorizedRequestResponse(
|
|
||||||
data: data,
|
|
||||||
response: response,
|
|
||||||
error: error
|
|
||||||
) { wasTokenRefreshed in
|
|
||||||
|
|
||||||
if wasTokenRefreshed {
|
|
||||||
// If the token was refreshed, it's because it was a 401 error, so we refreshed the token, and we are going to retry the request by calling self.execute()
|
|
||||||
self.execute(apiResponseQueue, completion)
|
|
||||||
} else {
|
|
||||||
// If the token was not refreshed, it's because it was not a 401 error, so we send the response to the completion block
|
|
||||||
completion(result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// If it's an unknown error, we send the response to the completion block
|
|
||||||
completion(result)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return requestTask
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class BearerDecodableRequestBuilder<T: Decodable>: URLSessionDecodableRequestBuilder<T> {
|
|
||||||
@discardableResult
|
|
||||||
override func execute(_ apiResponseQueue: DispatchQueue = PetstoreClientAPI.apiResponseQueue, _ completion: @escaping (Result<Response<T>, ErrorResponse>) -> Void) -> RequestTask {
|
|
||||||
// Before making the request, we can validate if we have a bearer token to be able to make a request
|
|
||||||
BearerTokenHandler.refreshTokenIfDoesntExist {
|
|
||||||
|
|
||||||
// Here we make the request
|
|
||||||
super.execute(apiResponseQueue) { result in
|
|
||||||
|
|
||||||
switch result {
|
|
||||||
case .success:
|
|
||||||
// If we got a successful response, we send the response to the completion block
|
|
||||||
completion(result)
|
|
||||||
|
|
||||||
case let .failure(error):
|
|
||||||
|
|
||||||
// If we got a failure response, we will analyse the error to see what we should do with it
|
|
||||||
if case let ErrorResponse.error(_, data, response, error) = error {
|
|
||||||
|
|
||||||
// If the error is an ErrorResponse.error() we will analyse it to see if it's a 401, and if it's a 401, we will refresh the token and retry the request
|
|
||||||
BearerTokenHandler.refreshTokenIfUnauthorizedRequestResponse(
|
|
||||||
data: data,
|
|
||||||
response: response,
|
|
||||||
error: error
|
|
||||||
) { wasTokenRefreshed in
|
|
||||||
|
|
||||||
if wasTokenRefreshed {
|
|
||||||
// If the token was refreshed, it's because it was a 401 error, so we refreshed the token, and we are going to retry the request by calling self.execute()
|
|
||||||
self.execute(apiResponseQueue, completion)
|
|
||||||
} else {
|
|
||||||
// If the token was not refreshed, it's because it was not a 401 error, so we send the response to the completion block
|
|
||||||
completion(result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// If it's an unknown error, we send the response to the completion block
|
|
||||||
completion(result)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return requestTask
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class BearerTokenHandler {
|
|
||||||
private static var bearerToken: String? = nil
|
|
||||||
|
|
||||||
static func refreshTokenIfDoesntExist(completionHandler: @escaping () -> Void) {
|
|
||||||
if bearerToken != nil {
|
|
||||||
completionHandler()
|
|
||||||
} else {
|
|
||||||
startRefreshingToken {
|
|
||||||
completionHandler()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static func refreshTokenIfUnauthorizedRequestResponse(data: Data?, response: URLResponse?, error: Error?, completionHandler: @escaping (Bool) -> Void) {
|
|
||||||
if let response = response as? HTTPURLResponse, response.statusCode == 401 {
|
|
||||||
startRefreshingToken {
|
|
||||||
completionHandler(true)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
completionHandler(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static func startRefreshingToken(completionHandler: @escaping () -> Void) {
|
|
||||||
// Get a bearer token
|
|
||||||
let dummyBearerToken = "..."
|
|
||||||
|
|
||||||
bearerToken = dummyBearerToken
|
|
||||||
PetstoreClientAPI.customHeaders["Authorization"] = "Bearer \(dummyBearerToken)"
|
|
||||||
|
|
||||||
completionHandler()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Then you assign the `BearerRequestBuilderFactory` to the property `requestBuilderFactory`.
|
|
||||||
|
|
||||||
`PetstoreClientAPI.requestBuilderFactory = BearerRequestBuilderFactory()`
|
|
||||||
|
|
||||||
The name `PetstoreClientAPI.requestBuilderFactory` will change depending on your project name.
|
|
||||||
|
|
||||||
Here is a working sample that put's together all of this.
|
|
||||||
[AppDelegate.swift](https://github.com/OpenAPITools/openapi-generator/blob/master/samples/client/petstore/swift5/urlsessionLibrary/SwaggerClientTests/SwaggerClient/AppDelegate.swift)
|
|
||||||
[BearerDecodableRequestBuilder.swift](https://github.com/OpenAPITools/openapi-generator/blob/master/samples/client/petstore/swift5/urlsessionLibrary/SwaggerClientTests/SwaggerClient/BearerDecodableRequestBuilder.swift)
|
|
||||||
{{/useURLSession}}
|
{{/useURLSession}}
|
||||||
{{#useAlamofire}}
|
{{#useAlamofire}}
|
||||||
|
|
||||||
### How do I implement bearer token authentication with Alamofire on the Swift 5 API client?
|
### How do I implement bearer token authentication with Alamofire on the Swift 5 API client?
|
||||||
|
|
||||||
First you subclass RequestBuilderFactory
|
https://openapi-generator.tech/docs/faq-generators#how-do-i-implement-bearer-token-authentication-with-alamofire-on-the-swift-5-api-client
|
||||||
```
|
|
||||||
class BearerRequestBuilderFactory: RequestBuilderFactory {
|
|
||||||
func getNonDecodableBuilder<T>() -> RequestBuilder<T>.Type {
|
|
||||||
BearerRequestBuilder<T>.self
|
|
||||||
}
|
|
||||||
|
|
||||||
func getBuilder<T: Decodable>() -> RequestBuilder<T>.Type {
|
|
||||||
BearerDecodableRequestBuilder<T>.self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Then you subclass AlamofireRequestBuilder and AlamofireDecodableRequestBuilder
|
|
||||||
```
|
|
||||||
class BearerRequestBuilder<T>: AlamofireRequestBuilder<T> {
|
|
||||||
override func createSessionManager() -> SessionManager {
|
|
||||||
let sessionManager = super.createSessionManager()
|
|
||||||
|
|
||||||
let bearerTokenHandler = BearerTokenHandler()
|
|
||||||
sessionManager.adapter = bearerTokenHandler
|
|
||||||
sessionManager.retrier = bearerTokenHandler
|
|
||||||
|
|
||||||
return sessionManager
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class BearerDecodableRequestBuilder<T: Decodable>: AlamofireDecodableRequestBuilder<T> {
|
|
||||||
override func createSessionManager() -> SessionManager {
|
|
||||||
let sessionManager = super.createSessionManager()
|
|
||||||
|
|
||||||
let bearerTokenHandler = BearerTokenHandler()
|
|
||||||
sessionManager.adapter = bearerTokenHandler
|
|
||||||
sessionManager.retrier = bearerTokenHandler
|
|
||||||
|
|
||||||
return sessionManager
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class BearerTokenHandler: RequestAdapter, RequestRetrier {
|
|
||||||
private static var bearerToken: String? = nil
|
|
||||||
|
|
||||||
func adapt(_ urlRequest: URLRequest) throws -> URLRequest {
|
|
||||||
if let bearerToken = Self.bearerToken {
|
|
||||||
var urlRequest = urlRequest
|
|
||||||
urlRequest.setValue("Bearer \(bearerToken)", forHTTPHeaderField: "Authorization")
|
|
||||||
return urlRequest
|
|
||||||
}
|
|
||||||
|
|
||||||
return urlRequest
|
|
||||||
}
|
|
||||||
|
|
||||||
func should(_: SessionManager, retry request: Request, with _: Error, completion: @escaping RequestRetryCompletion) {
|
|
||||||
if let response = request.task?.response as? HTTPURLResponse, response.statusCode == 401 {
|
|
||||||
Self.startRefreshingToken { isTokenRefreshed in
|
|
||||||
completion(isTokenRefreshed, 0.0)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
completion(false, 0.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static func startRefreshingToken(completionHandler: @escaping (Bool) -> Void) {
|
|
||||||
// Get a bearer token
|
|
||||||
let dummyBearerToken = "..."
|
|
||||||
|
|
||||||
bearerToken = dummyBearerToken
|
|
||||||
PetstoreClientAPI.customHeaders["Authorization"] = "Bearer \(dummyBearerToken)"
|
|
||||||
|
|
||||||
completionHandler(true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Then you assign the `BearerRequestBuilderFactory` to the property `requestBuilderFactory`.
|
|
||||||
|
|
||||||
`PetstoreClientAPI.requestBuilderFactory = BearerRequestBuilderFactory()`
|
|
||||||
|
|
||||||
The name `PetstoreClientAPI.requestBuilderFactory` will change depending on your project name.
|
|
||||||
|
|
||||||
Here is a working sample that put's together all of this.
|
|
||||||
[AppDelegate.swift](https://github.com/OpenAPITools/openapi-generator/blob/master/samples/client/petstore/swift5/alamofireLibrary/SwaggerClientTests/SwaggerClient/AppDelegate.swift)
|
|
||||||
[BearerTokenHandler.swift](https://github.com/OpenAPITools/openapi-generator/blob/master/samples/client/petstore/swift5/alamofireLibrary/SwaggerClientTests/SwaggerClient/BearerDecodableRequestBuilder.swift)
|
|
||||||
{{/useAlamofire}}
|
{{/useAlamofire}}
|
||||||
|
|
||||||
## Author
|
## Author
|
||||||
|
@ -78,140 +78,20 @@ Class | Method | HTTP request | Description
|
|||||||
|
|
||||||
{{/authMethods}}
|
{{/authMethods}}
|
||||||
|
|
||||||
|
# How do I migrate from the Swift 5 generator to the swift 6 generator?
|
||||||
|
|
||||||
|
https://openapi-generator.tech/docs/faq-generators#how-do-i-migrate-from-the-swift-5-generator-to-the-swift-6-generator
|
||||||
{{#useURLSession}}
|
{{#useURLSession}}
|
||||||
|
|
||||||
### How do I implement bearer token authentication with URLSession on the Swift 6 API client?
|
### How do I implement bearer token authentication with URLSession on the Swift 6 API client?
|
||||||
|
|
||||||
First you implement the `OpenAPIInterceptor` protocol.
|
https://openapi-generator.tech/docs/faq-generators#how-do-i-implement-bearer-token-authentication-with-urlsession-on-the-swift-6-api-client
|
||||||
```
|
|
||||||
public class BearerOpenAPIInterceptor: OpenAPIInterceptor {
|
|
||||||
public init() {}
|
|
||||||
|
|
||||||
public func intercept(urlRequest: URLRequest, urlSession: URLSessionProtocol, openAPIClient: OpenAPIClient, completion: @escaping (Result<URLRequest, any Error>) -> Void) {
|
|
||||||
refreshTokenIfDoesntExist { token in
|
|
||||||
|
|
||||||
// Change the current url request
|
|
||||||
var newUrlRequest = urlRequest
|
|
||||||
newUrlRequest.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
|
|
||||||
|
|
||||||
// Change the global headers
|
|
||||||
openAPIClient.customHeaders["Authorization"] = "Bearer \(token)"
|
|
||||||
|
|
||||||
completion(.success(newUrlRequest))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public func retry(urlRequest: URLRequest, urlSession: URLSessionProtocol, openAPIClient: OpenAPIClient, data: Data?, response: URLResponse, error: Error, completion: @escaping (OpenAPIInterceptorRetry) -> Void) {
|
|
||||||
// We will analyse the response to see if it's a 401, and if it's a 401, we will refresh the token and retry the request
|
|
||||||
refreshTokenIfUnauthorizedRequestResponse(
|
|
||||||
data: data,
|
|
||||||
response: response,
|
|
||||||
error: error
|
|
||||||
) { (wasTokenRefreshed, newToken) in
|
|
||||||
|
|
||||||
if wasTokenRefreshed, let newToken = newToken {
|
|
||||||
|
|
||||||
// Change the global headers
|
|
||||||
openAPIClient.customHeaders["Authorization"] = "Bearer \(newToken)"
|
|
||||||
|
|
||||||
completion(.retry)
|
|
||||||
} else {
|
|
||||||
// If the token was not refreshed, it's because it was not a 401 error, so we send the response to the completion block
|
|
||||||
completion(.dontRetry)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private var bearerToken: String? = nil
|
|
||||||
|
|
||||||
func refreshTokenIfDoesntExist(completionHandler: @escaping (String) -> Void) {
|
|
||||||
if let bearerToken = bearerToken {
|
|
||||||
completionHandler(bearerToken)
|
|
||||||
} else {
|
|
||||||
startRefreshingToken { token in
|
|
||||||
completionHandler(token)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func refreshTokenIfUnauthorizedRequestResponse(data: Data?, response: URLResponse, error: Error, completionHandler: @escaping (Bool, String?) -> Void) {
|
|
||||||
if let response = response as? HTTPURLResponse, response.statusCode == 401 {
|
|
||||||
startRefreshingToken { token in
|
|
||||||
completionHandler(true, token)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
completionHandler(false, nil)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private func startRefreshingToken(completionHandler: @escaping (String) -> Void) {
|
|
||||||
// Get a bearer token
|
|
||||||
let dummyBearerToken = "..."
|
|
||||||
|
|
||||||
bearerToken = dummyBearerToken
|
|
||||||
|
|
||||||
completionHandler(dummyBearerToken)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Then you assign the `BearerOpenAPIInterceptor` to the property `OpenAPIClient.shared.interceptor`.
|
|
||||||
|
|
||||||
`OpenAPIClient.shared.interceptor = BearerOpenAPIInterceptor()`
|
|
||||||
|
|
||||||
Here is a working sample that put's together all of this.
|
|
||||||
[AppDelegate.swift](https://github.com/OpenAPITools/openapi-generator/blob/master/samples/client/petstore/swift6/urlsessionLibrary/SwaggerClientTests/SwaggerClient/AppDelegate.swift)
|
|
||||||
[BearerTokenHandler.swift](https://github.com/OpenAPITools/openapi-generator/blob/master/samples/client/petstore/swift5/urlsessionLibrary/SwaggerClientTests/SwaggerClient/BearerDecodableRequestBuilder.swift)
|
|
||||||
{{/useURLSession}}
|
{{/useURLSession}}
|
||||||
{{#useAlamofire}}
|
{{#useAlamofire}}
|
||||||
|
|
||||||
### How do I implement bearer token authentication with Alamofire on the Swift 6 API client?
|
### How do I implement bearer token authentication with Alamofire on the Swift 6 API client?
|
||||||
|
|
||||||
First implement the `Alamofire` `RequestInterceptor` protocol.
|
https://openapi-generator.tech/docs/faq-generators#how-do-i-implement-bearer-token-authentication-with-alamofire-on-the-swift-6-api-client
|
||||||
```
|
|
||||||
class BearerTokenHandler: RequestInterceptor, @unchecked Sendable {
|
|
||||||
private var bearerToken: String? = nil
|
|
||||||
|
|
||||||
func adapt(_ urlRequest: URLRequest, for session: Session, completion: @escaping (Result<URLRequest, Error>) -> Void) {
|
|
||||||
if let bearerToken = bearerToken {
|
|
||||||
var urlRequest = urlRequest
|
|
||||||
urlRequest.setValue("Bearer \(bearerToken)", forHTTPHeaderField: "Authorization")
|
|
||||||
|
|
||||||
completion(.success(urlRequest))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
completion(.success(urlRequest))
|
|
||||||
}
|
|
||||||
|
|
||||||
func retry(_ request: Request, for session: Session, dueTo error: Error, completion: @escaping (RetryResult) -> Void) {
|
|
||||||
if let response = request.task?.response as? HTTPURLResponse, response.statusCode == 401 {
|
|
||||||
startRefreshingToken { isTokenRefreshed in
|
|
||||||
completion(.retry)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
completion(.doNotRetryWithError(error))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private func startRefreshingToken(completionHandler: @escaping (Bool) -> Void) {
|
|
||||||
// Get a bearer token
|
|
||||||
let dummyBearerToken = "..."
|
|
||||||
|
|
||||||
bearerToken = dummyBearerToken
|
|
||||||
OpenAPIClient.shared.customHeaders["Authorization"] = "Bearer \(dummyBearerToken)"
|
|
||||||
|
|
||||||
completionHandler(true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
Then you assign the `BearerTokenHandler` to the property `OpenAPIClient.shared.interceptor`.
|
|
||||||
|
|
||||||
`OpenAPIClient.shared.interceptor = BearerTokenHandler()`
|
|
||||||
|
|
||||||
Here is a working sample that put's together all of this.
|
|
||||||
[AppDelegate.swift](https://github.com/OpenAPITools/openapi-generator/blob/master/samples/client/petstore/swift6/alamofireLibrary/SwaggerClientTests/SwaggerClient/AppDelegate.swift)
|
|
||||||
[BearerTokenHandler.swift](https://github.com/OpenAPITools/openapi-generator/blob/master/samples/client/petstore/swift6/alamofireLibrary/SwaggerClientTests/SwaggerClient/BearerTokenHandler.swift)
|
|
||||||
{{/useAlamofire}}
|
{{/useAlamofire}}
|
||||||
|
|
||||||
## Author
|
## Author
|
||||||
|
@ -140,91 +140,13 @@ Authentication schemes defined for the API:
|
|||||||
- **Type**: HTTP basic authentication
|
- **Type**: HTTP basic authentication
|
||||||
|
|
||||||
|
|
||||||
|
# How do I migrate from the Swift 5 generator to the swift 6 generator?
|
||||||
|
|
||||||
|
https://openapi-generator.tech/docs/faq-generators#how-do-i-migrate-from-the-swift-5-generator-to-the-swift-6-generator
|
||||||
|
|
||||||
### How do I implement bearer token authentication with Alamofire on the Swift 5 API client?
|
### How do I implement bearer token authentication with Alamofire on the Swift 5 API client?
|
||||||
|
|
||||||
First you subclass RequestBuilderFactory
|
https://openapi-generator.tech/docs/faq-generators#how-do-i-implement-bearer-token-authentication-with-alamofire-on-the-swift-5-api-client
|
||||||
```
|
|
||||||
class BearerRequestBuilderFactory: RequestBuilderFactory {
|
|
||||||
func getNonDecodableBuilder<T>() -> RequestBuilder<T>.Type {
|
|
||||||
BearerRequestBuilder<T>.self
|
|
||||||
}
|
|
||||||
|
|
||||||
func getBuilder<T: Decodable>() -> RequestBuilder<T>.Type {
|
|
||||||
BearerDecodableRequestBuilder<T>.self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Then you subclass AlamofireRequestBuilder and AlamofireDecodableRequestBuilder
|
|
||||||
```
|
|
||||||
class BearerRequestBuilder<T>: AlamofireRequestBuilder<T> {
|
|
||||||
override func createSessionManager() -> SessionManager {
|
|
||||||
let sessionManager = super.createSessionManager()
|
|
||||||
|
|
||||||
let bearerTokenHandler = BearerTokenHandler()
|
|
||||||
sessionManager.adapter = bearerTokenHandler
|
|
||||||
sessionManager.retrier = bearerTokenHandler
|
|
||||||
|
|
||||||
return sessionManager
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class BearerDecodableRequestBuilder<T: Decodable>: AlamofireDecodableRequestBuilder<T> {
|
|
||||||
override func createSessionManager() -> SessionManager {
|
|
||||||
let sessionManager = super.createSessionManager()
|
|
||||||
|
|
||||||
let bearerTokenHandler = BearerTokenHandler()
|
|
||||||
sessionManager.adapter = bearerTokenHandler
|
|
||||||
sessionManager.retrier = bearerTokenHandler
|
|
||||||
|
|
||||||
return sessionManager
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class BearerTokenHandler: RequestAdapter, RequestRetrier {
|
|
||||||
private static var bearerToken: String? = nil
|
|
||||||
|
|
||||||
func adapt(_ urlRequest: URLRequest) throws -> URLRequest {
|
|
||||||
if let bearerToken = Self.bearerToken {
|
|
||||||
var urlRequest = urlRequest
|
|
||||||
urlRequest.setValue("Bearer \(bearerToken)", forHTTPHeaderField: "Authorization")
|
|
||||||
return urlRequest
|
|
||||||
}
|
|
||||||
|
|
||||||
return urlRequest
|
|
||||||
}
|
|
||||||
|
|
||||||
func should(_: SessionManager, retry request: Request, with _: Error, completion: @escaping RequestRetryCompletion) {
|
|
||||||
if let response = request.task?.response as? HTTPURLResponse, response.statusCode == 401 {
|
|
||||||
Self.startRefreshingToken { isTokenRefreshed in
|
|
||||||
completion(isTokenRefreshed, 0.0)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
completion(false, 0.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static func startRefreshingToken(completionHandler: @escaping (Bool) -> Void) {
|
|
||||||
// Get a bearer token
|
|
||||||
let dummyBearerToken = "..."
|
|
||||||
|
|
||||||
bearerToken = dummyBearerToken
|
|
||||||
PetstoreClientAPI.customHeaders["Authorization"] = "Bearer \(dummyBearerToken)"
|
|
||||||
|
|
||||||
completionHandler(true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Then you assign the `BearerRequestBuilderFactory` to the property `requestBuilderFactory`.
|
|
||||||
|
|
||||||
`PetstoreClientAPI.requestBuilderFactory = BearerRequestBuilderFactory()`
|
|
||||||
|
|
||||||
The name `PetstoreClientAPI.requestBuilderFactory` will change depending on your project name.
|
|
||||||
|
|
||||||
Here is a working sample that put's together all of this.
|
|
||||||
[AppDelegate.swift](https://github.com/OpenAPITools/openapi-generator/blob/master/samples/client/petstore/swift5/alamofireLibrary/SwaggerClientTests/SwaggerClient/AppDelegate.swift)
|
|
||||||
[BearerTokenHandler.swift](https://github.com/OpenAPITools/openapi-generator/blob/master/samples/client/petstore/swift5/alamofireLibrary/SwaggerClientTests/SwaggerClient/BearerDecodableRequestBuilder.swift)
|
|
||||||
|
|
||||||
## Author
|
## Author
|
||||||
|
|
||||||
|
@ -140,162 +140,13 @@ Authentication schemes defined for the API:
|
|||||||
- **Type**: HTTP basic authentication
|
- **Type**: HTTP basic authentication
|
||||||
|
|
||||||
|
|
||||||
|
# How do I migrate from the Swift 5 generator to the swift 6 generator?
|
||||||
|
|
||||||
|
https://openapi-generator.tech/docs/faq-generators#how-do-i-migrate-from-the-swift-5-generator-to-the-swift-6-generator
|
||||||
|
|
||||||
### How do I implement bearer token authentication with URLSession on the Swift 5 API client?
|
### How do I implement bearer token authentication with URLSession on the Swift 5 API client?
|
||||||
|
|
||||||
First you subclass RequestBuilderFactory
|
https://openapi-generator.tech/docs/faq-generators#how-do-i-implement-bearer-token-authentication-with-urlsession-on-the-swift-5-api-client
|
||||||
```
|
|
||||||
class BearerRequestBuilderFactory: RequestBuilderFactory {
|
|
||||||
func getNonDecodableBuilder<T>() -> RequestBuilder<T>.Type {
|
|
||||||
BearerRequestBuilder<T>.self
|
|
||||||
}
|
|
||||||
|
|
||||||
func getBuilder<T: Decodable>() -> RequestBuilder<T>.Type {
|
|
||||||
BearerDecodableRequestBuilder<T>.self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Then you subclass URLSessionRequestBuilder and URLSessionDecodableRequestBuilder
|
|
||||||
```
|
|
||||||
class BearerRequestBuilder<T>: URLSessionRequestBuilder<T> {
|
|
||||||
@discardableResult
|
|
||||||
override func execute(_ apiResponseQueue: DispatchQueue = PetstoreClientAPI.apiResponseQueue, _ completion: @escaping (Result<Response<T>, ErrorResponse>) -> Void) -> RequestTask {
|
|
||||||
|
|
||||||
// Before making the request, we can validate if we have a bearer token to be able to make a request
|
|
||||||
BearerTokenHandler.refreshTokenIfDoesntExist {
|
|
||||||
|
|
||||||
// Here we make the request
|
|
||||||
super.execute(apiResponseQueue) { result in
|
|
||||||
|
|
||||||
switch result {
|
|
||||||
case .success:
|
|
||||||
// If we got a successful response, we send the response to the completion block
|
|
||||||
completion(result)
|
|
||||||
|
|
||||||
case let .failure(error):
|
|
||||||
|
|
||||||
// If we got a failure response, we will analyse the error to see what we should do with it
|
|
||||||
if case let ErrorResponse.error(_, data, response, error) = error {
|
|
||||||
|
|
||||||
// If the error is an ErrorResponse.error() we will analyse it to see if it's a 401, and if it's a 401, we will refresh the token and retry the request
|
|
||||||
BearerTokenHandler.refreshTokenIfUnauthorizedRequestResponse(
|
|
||||||
data: data,
|
|
||||||
response: response,
|
|
||||||
error: error
|
|
||||||
) { wasTokenRefreshed in
|
|
||||||
|
|
||||||
if wasTokenRefreshed {
|
|
||||||
// If the token was refreshed, it's because it was a 401 error, so we refreshed the token, and we are going to retry the request by calling self.execute()
|
|
||||||
self.execute(apiResponseQueue, completion)
|
|
||||||
} else {
|
|
||||||
// If the token was not refreshed, it's because it was not a 401 error, so we send the response to the completion block
|
|
||||||
completion(result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// If it's an unknown error, we send the response to the completion block
|
|
||||||
completion(result)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return requestTask
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class BearerDecodableRequestBuilder<T: Decodable>: URLSessionDecodableRequestBuilder<T> {
|
|
||||||
@discardableResult
|
|
||||||
override func execute(_ apiResponseQueue: DispatchQueue = PetstoreClientAPI.apiResponseQueue, _ completion: @escaping (Result<Response<T>, ErrorResponse>) -> Void) -> RequestTask {
|
|
||||||
// Before making the request, we can validate if we have a bearer token to be able to make a request
|
|
||||||
BearerTokenHandler.refreshTokenIfDoesntExist {
|
|
||||||
|
|
||||||
// Here we make the request
|
|
||||||
super.execute(apiResponseQueue) { result in
|
|
||||||
|
|
||||||
switch result {
|
|
||||||
case .success:
|
|
||||||
// If we got a successful response, we send the response to the completion block
|
|
||||||
completion(result)
|
|
||||||
|
|
||||||
case let .failure(error):
|
|
||||||
|
|
||||||
// If we got a failure response, we will analyse the error to see what we should do with it
|
|
||||||
if case let ErrorResponse.error(_, data, response, error) = error {
|
|
||||||
|
|
||||||
// If the error is an ErrorResponse.error() we will analyse it to see if it's a 401, and if it's a 401, we will refresh the token and retry the request
|
|
||||||
BearerTokenHandler.refreshTokenIfUnauthorizedRequestResponse(
|
|
||||||
data: data,
|
|
||||||
response: response,
|
|
||||||
error: error
|
|
||||||
) { wasTokenRefreshed in
|
|
||||||
|
|
||||||
if wasTokenRefreshed {
|
|
||||||
// If the token was refreshed, it's because it was a 401 error, so we refreshed the token, and we are going to retry the request by calling self.execute()
|
|
||||||
self.execute(apiResponseQueue, completion)
|
|
||||||
} else {
|
|
||||||
// If the token was not refreshed, it's because it was not a 401 error, so we send the response to the completion block
|
|
||||||
completion(result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// If it's an unknown error, we send the response to the completion block
|
|
||||||
completion(result)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return requestTask
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class BearerTokenHandler {
|
|
||||||
private static var bearerToken: String? = nil
|
|
||||||
|
|
||||||
static func refreshTokenIfDoesntExist(completionHandler: @escaping () -> Void) {
|
|
||||||
if bearerToken != nil {
|
|
||||||
completionHandler()
|
|
||||||
} else {
|
|
||||||
startRefreshingToken {
|
|
||||||
completionHandler()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static func refreshTokenIfUnauthorizedRequestResponse(data: Data?, response: URLResponse?, error: Error?, completionHandler: @escaping (Bool) -> Void) {
|
|
||||||
if let response = response as? HTTPURLResponse, response.statusCode == 401 {
|
|
||||||
startRefreshingToken {
|
|
||||||
completionHandler(true)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
completionHandler(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static func startRefreshingToken(completionHandler: @escaping () -> Void) {
|
|
||||||
// Get a bearer token
|
|
||||||
let dummyBearerToken = "..."
|
|
||||||
|
|
||||||
bearerToken = dummyBearerToken
|
|
||||||
PetstoreClientAPI.customHeaders["Authorization"] = "Bearer \(dummyBearerToken)"
|
|
||||||
|
|
||||||
completionHandler()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Then you assign the `BearerRequestBuilderFactory` to the property `requestBuilderFactory`.
|
|
||||||
|
|
||||||
`PetstoreClientAPI.requestBuilderFactory = BearerRequestBuilderFactory()`
|
|
||||||
|
|
||||||
The name `PetstoreClientAPI.requestBuilderFactory` will change depending on your project name.
|
|
||||||
|
|
||||||
Here is a working sample that put's together all of this.
|
|
||||||
[AppDelegate.swift](https://github.com/OpenAPITools/openapi-generator/blob/master/samples/client/petstore/swift5/urlsessionLibrary/SwaggerClientTests/SwaggerClient/AppDelegate.swift)
|
|
||||||
[BearerDecodableRequestBuilder.swift](https://github.com/OpenAPITools/openapi-generator/blob/master/samples/client/petstore/swift5/urlsessionLibrary/SwaggerClientTests/SwaggerClient/BearerDecodableRequestBuilder.swift)
|
|
||||||
|
|
||||||
## Author
|
## Author
|
||||||
|
|
||||||
|
@ -140,162 +140,13 @@ Authentication schemes defined for the API:
|
|||||||
- **Type**: HTTP basic authentication
|
- **Type**: HTTP basic authentication
|
||||||
|
|
||||||
|
|
||||||
|
# How do I migrate from the Swift 5 generator to the swift 6 generator?
|
||||||
|
|
||||||
|
https://openapi-generator.tech/docs/faq-generators#how-do-i-migrate-from-the-swift-5-generator-to-the-swift-6-generator
|
||||||
|
|
||||||
### How do I implement bearer token authentication with URLSession on the Swift 5 API client?
|
### How do I implement bearer token authentication with URLSession on the Swift 5 API client?
|
||||||
|
|
||||||
First you subclass RequestBuilderFactory
|
https://openapi-generator.tech/docs/faq-generators#how-do-i-implement-bearer-token-authentication-with-urlsession-on-the-swift-5-api-client
|
||||||
```
|
|
||||||
class BearerRequestBuilderFactory: RequestBuilderFactory {
|
|
||||||
func getNonDecodableBuilder<T>() -> RequestBuilder<T>.Type {
|
|
||||||
BearerRequestBuilder<T>.self
|
|
||||||
}
|
|
||||||
|
|
||||||
func getBuilder<T: Decodable>() -> RequestBuilder<T>.Type {
|
|
||||||
BearerDecodableRequestBuilder<T>.self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Then you subclass URLSessionRequestBuilder and URLSessionDecodableRequestBuilder
|
|
||||||
```
|
|
||||||
class BearerRequestBuilder<T>: URLSessionRequestBuilder<T> {
|
|
||||||
@discardableResult
|
|
||||||
override func execute(_ apiResponseQueue: DispatchQueue = PetstoreClientAPI.apiResponseQueue, _ completion: @escaping (Result<Response<T>, ErrorResponse>) -> Void) -> RequestTask {
|
|
||||||
|
|
||||||
// Before making the request, we can validate if we have a bearer token to be able to make a request
|
|
||||||
BearerTokenHandler.refreshTokenIfDoesntExist {
|
|
||||||
|
|
||||||
// Here we make the request
|
|
||||||
super.execute(apiResponseQueue) { result in
|
|
||||||
|
|
||||||
switch result {
|
|
||||||
case .success:
|
|
||||||
// If we got a successful response, we send the response to the completion block
|
|
||||||
completion(result)
|
|
||||||
|
|
||||||
case let .failure(error):
|
|
||||||
|
|
||||||
// If we got a failure response, we will analyse the error to see what we should do with it
|
|
||||||
if case let ErrorResponse.error(_, data, response, error) = error {
|
|
||||||
|
|
||||||
// If the error is an ErrorResponse.error() we will analyse it to see if it's a 401, and if it's a 401, we will refresh the token and retry the request
|
|
||||||
BearerTokenHandler.refreshTokenIfUnauthorizedRequestResponse(
|
|
||||||
data: data,
|
|
||||||
response: response,
|
|
||||||
error: error
|
|
||||||
) { wasTokenRefreshed in
|
|
||||||
|
|
||||||
if wasTokenRefreshed {
|
|
||||||
// If the token was refreshed, it's because it was a 401 error, so we refreshed the token, and we are going to retry the request by calling self.execute()
|
|
||||||
self.execute(apiResponseQueue, completion)
|
|
||||||
} else {
|
|
||||||
// If the token was not refreshed, it's because it was not a 401 error, so we send the response to the completion block
|
|
||||||
completion(result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// If it's an unknown error, we send the response to the completion block
|
|
||||||
completion(result)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return requestTask
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class BearerDecodableRequestBuilder<T: Decodable>: URLSessionDecodableRequestBuilder<T> {
|
|
||||||
@discardableResult
|
|
||||||
override func execute(_ apiResponseQueue: DispatchQueue = PetstoreClientAPI.apiResponseQueue, _ completion: @escaping (Result<Response<T>, ErrorResponse>) -> Void) -> RequestTask {
|
|
||||||
// Before making the request, we can validate if we have a bearer token to be able to make a request
|
|
||||||
BearerTokenHandler.refreshTokenIfDoesntExist {
|
|
||||||
|
|
||||||
// Here we make the request
|
|
||||||
super.execute(apiResponseQueue) { result in
|
|
||||||
|
|
||||||
switch result {
|
|
||||||
case .success:
|
|
||||||
// If we got a successful response, we send the response to the completion block
|
|
||||||
completion(result)
|
|
||||||
|
|
||||||
case let .failure(error):
|
|
||||||
|
|
||||||
// If we got a failure response, we will analyse the error to see what we should do with it
|
|
||||||
if case let ErrorResponse.error(_, data, response, error) = error {
|
|
||||||
|
|
||||||
// If the error is an ErrorResponse.error() we will analyse it to see if it's a 401, and if it's a 401, we will refresh the token and retry the request
|
|
||||||
BearerTokenHandler.refreshTokenIfUnauthorizedRequestResponse(
|
|
||||||
data: data,
|
|
||||||
response: response,
|
|
||||||
error: error
|
|
||||||
) { wasTokenRefreshed in
|
|
||||||
|
|
||||||
if wasTokenRefreshed {
|
|
||||||
// If the token was refreshed, it's because it was a 401 error, so we refreshed the token, and we are going to retry the request by calling self.execute()
|
|
||||||
self.execute(apiResponseQueue, completion)
|
|
||||||
} else {
|
|
||||||
// If the token was not refreshed, it's because it was not a 401 error, so we send the response to the completion block
|
|
||||||
completion(result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// If it's an unknown error, we send the response to the completion block
|
|
||||||
completion(result)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return requestTask
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class BearerTokenHandler {
|
|
||||||
private static var bearerToken: String? = nil
|
|
||||||
|
|
||||||
static func refreshTokenIfDoesntExist(completionHandler: @escaping () -> Void) {
|
|
||||||
if bearerToken != nil {
|
|
||||||
completionHandler()
|
|
||||||
} else {
|
|
||||||
startRefreshingToken {
|
|
||||||
completionHandler()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static func refreshTokenIfUnauthorizedRequestResponse(data: Data?, response: URLResponse?, error: Error?, completionHandler: @escaping (Bool) -> Void) {
|
|
||||||
if let response = response as? HTTPURLResponse, response.statusCode == 401 {
|
|
||||||
startRefreshingToken {
|
|
||||||
completionHandler(true)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
completionHandler(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static func startRefreshingToken(completionHandler: @escaping () -> Void) {
|
|
||||||
// Get a bearer token
|
|
||||||
let dummyBearerToken = "..."
|
|
||||||
|
|
||||||
bearerToken = dummyBearerToken
|
|
||||||
PetstoreClientAPI.customHeaders["Authorization"] = "Bearer \(dummyBearerToken)"
|
|
||||||
|
|
||||||
completionHandler()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Then you assign the `BearerRequestBuilderFactory` to the property `requestBuilderFactory`.
|
|
||||||
|
|
||||||
`PetstoreClientAPI.requestBuilderFactory = BearerRequestBuilderFactory()`
|
|
||||||
|
|
||||||
The name `PetstoreClientAPI.requestBuilderFactory` will change depending on your project name.
|
|
||||||
|
|
||||||
Here is a working sample that put's together all of this.
|
|
||||||
[AppDelegate.swift](https://github.com/OpenAPITools/openapi-generator/blob/master/samples/client/petstore/swift5/urlsessionLibrary/SwaggerClientTests/SwaggerClient/AppDelegate.swift)
|
|
||||||
[BearerDecodableRequestBuilder.swift](https://github.com/OpenAPITools/openapi-generator/blob/master/samples/client/petstore/swift5/urlsessionLibrary/SwaggerClientTests/SwaggerClient/BearerDecodableRequestBuilder.swift)
|
|
||||||
|
|
||||||
## Author
|
## Author
|
||||||
|
|
||||||
|
@ -151,162 +151,13 @@ Authentication schemes defined for the API:
|
|||||||
- **Type**: HTTP basic authentication
|
- **Type**: HTTP basic authentication
|
||||||
|
|
||||||
|
|
||||||
|
# How do I migrate from the Swift 5 generator to the swift 6 generator?
|
||||||
|
|
||||||
|
https://openapi-generator.tech/docs/faq-generators#how-do-i-migrate-from-the-swift-5-generator-to-the-swift-6-generator
|
||||||
|
|
||||||
### How do I implement bearer token authentication with URLSession on the Swift 5 API client?
|
### How do I implement bearer token authentication with URLSession on the Swift 5 API client?
|
||||||
|
|
||||||
First you subclass RequestBuilderFactory
|
https://openapi-generator.tech/docs/faq-generators#how-do-i-implement-bearer-token-authentication-with-urlsession-on-the-swift-5-api-client
|
||||||
```
|
|
||||||
class BearerRequestBuilderFactory: RequestBuilderFactory {
|
|
||||||
func getNonDecodableBuilder<T>() -> RequestBuilder<T>.Type {
|
|
||||||
BearerRequestBuilder<T>.self
|
|
||||||
}
|
|
||||||
|
|
||||||
func getBuilder<T: Decodable>() -> RequestBuilder<T>.Type {
|
|
||||||
BearerDecodableRequestBuilder<T>.self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Then you subclass URLSessionRequestBuilder and URLSessionDecodableRequestBuilder
|
|
||||||
```
|
|
||||||
class BearerRequestBuilder<T>: URLSessionRequestBuilder<T> {
|
|
||||||
@discardableResult
|
|
||||||
override func execute(_ apiResponseQueue: DispatchQueue = PetstoreClientAPI.apiResponseQueue, _ completion: @escaping (Result<Response<T>, ErrorResponse>) -> Void) -> RequestTask {
|
|
||||||
|
|
||||||
// Before making the request, we can validate if we have a bearer token to be able to make a request
|
|
||||||
BearerTokenHandler.refreshTokenIfDoesntExist {
|
|
||||||
|
|
||||||
// Here we make the request
|
|
||||||
super.execute(apiResponseQueue) { result in
|
|
||||||
|
|
||||||
switch result {
|
|
||||||
case .success:
|
|
||||||
// If we got a successful response, we send the response to the completion block
|
|
||||||
completion(result)
|
|
||||||
|
|
||||||
case let .failure(error):
|
|
||||||
|
|
||||||
// If we got a failure response, we will analyse the error to see what we should do with it
|
|
||||||
if case let ErrorResponse.error(_, data, response, error) = error {
|
|
||||||
|
|
||||||
// If the error is an ErrorResponse.error() we will analyse it to see if it's a 401, and if it's a 401, we will refresh the token and retry the request
|
|
||||||
BearerTokenHandler.refreshTokenIfUnauthorizedRequestResponse(
|
|
||||||
data: data,
|
|
||||||
response: response,
|
|
||||||
error: error
|
|
||||||
) { wasTokenRefreshed in
|
|
||||||
|
|
||||||
if wasTokenRefreshed {
|
|
||||||
// If the token was refreshed, it's because it was a 401 error, so we refreshed the token, and we are going to retry the request by calling self.execute()
|
|
||||||
self.execute(apiResponseQueue, completion)
|
|
||||||
} else {
|
|
||||||
// If the token was not refreshed, it's because it was not a 401 error, so we send the response to the completion block
|
|
||||||
completion(result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// If it's an unknown error, we send the response to the completion block
|
|
||||||
completion(result)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return requestTask
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class BearerDecodableRequestBuilder<T: Decodable>: URLSessionDecodableRequestBuilder<T> {
|
|
||||||
@discardableResult
|
|
||||||
override func execute(_ apiResponseQueue: DispatchQueue = PetstoreClientAPI.apiResponseQueue, _ completion: @escaping (Result<Response<T>, ErrorResponse>) -> Void) -> RequestTask {
|
|
||||||
// Before making the request, we can validate if we have a bearer token to be able to make a request
|
|
||||||
BearerTokenHandler.refreshTokenIfDoesntExist {
|
|
||||||
|
|
||||||
// Here we make the request
|
|
||||||
super.execute(apiResponseQueue) { result in
|
|
||||||
|
|
||||||
switch result {
|
|
||||||
case .success:
|
|
||||||
// If we got a successful response, we send the response to the completion block
|
|
||||||
completion(result)
|
|
||||||
|
|
||||||
case let .failure(error):
|
|
||||||
|
|
||||||
// If we got a failure response, we will analyse the error to see what we should do with it
|
|
||||||
if case let ErrorResponse.error(_, data, response, error) = error {
|
|
||||||
|
|
||||||
// If the error is an ErrorResponse.error() we will analyse it to see if it's a 401, and if it's a 401, we will refresh the token and retry the request
|
|
||||||
BearerTokenHandler.refreshTokenIfUnauthorizedRequestResponse(
|
|
||||||
data: data,
|
|
||||||
response: response,
|
|
||||||
error: error
|
|
||||||
) { wasTokenRefreshed in
|
|
||||||
|
|
||||||
if wasTokenRefreshed {
|
|
||||||
// If the token was refreshed, it's because it was a 401 error, so we refreshed the token, and we are going to retry the request by calling self.execute()
|
|
||||||
self.execute(apiResponseQueue, completion)
|
|
||||||
} else {
|
|
||||||
// If the token was not refreshed, it's because it was not a 401 error, so we send the response to the completion block
|
|
||||||
completion(result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// If it's an unknown error, we send the response to the completion block
|
|
||||||
completion(result)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return requestTask
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class BearerTokenHandler {
|
|
||||||
private static var bearerToken: String? = nil
|
|
||||||
|
|
||||||
static func refreshTokenIfDoesntExist(completionHandler: @escaping () -> Void) {
|
|
||||||
if bearerToken != nil {
|
|
||||||
completionHandler()
|
|
||||||
} else {
|
|
||||||
startRefreshingToken {
|
|
||||||
completionHandler()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static func refreshTokenIfUnauthorizedRequestResponse(data: Data?, response: URLResponse?, error: Error?, completionHandler: @escaping (Bool) -> Void) {
|
|
||||||
if let response = response as? HTTPURLResponse, response.statusCode == 401 {
|
|
||||||
startRefreshingToken {
|
|
||||||
completionHandler(true)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
completionHandler(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static func startRefreshingToken(completionHandler: @escaping () -> Void) {
|
|
||||||
// Get a bearer token
|
|
||||||
let dummyBearerToken = "..."
|
|
||||||
|
|
||||||
bearerToken = dummyBearerToken
|
|
||||||
PetstoreClientAPI.customHeaders["Authorization"] = "Bearer \(dummyBearerToken)"
|
|
||||||
|
|
||||||
completionHandler()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Then you assign the `BearerRequestBuilderFactory` to the property `requestBuilderFactory`.
|
|
||||||
|
|
||||||
`PetstoreClientAPI.requestBuilderFactory = BearerRequestBuilderFactory()`
|
|
||||||
|
|
||||||
The name `PetstoreClientAPI.requestBuilderFactory` will change depending on your project name.
|
|
||||||
|
|
||||||
Here is a working sample that put's together all of this.
|
|
||||||
[AppDelegate.swift](https://github.com/OpenAPITools/openapi-generator/blob/master/samples/client/petstore/swift5/urlsessionLibrary/SwaggerClientTests/SwaggerClient/AppDelegate.swift)
|
|
||||||
[BearerDecodableRequestBuilder.swift](https://github.com/OpenAPITools/openapi-generator/blob/master/samples/client/petstore/swift5/urlsessionLibrary/SwaggerClientTests/SwaggerClient/BearerDecodableRequestBuilder.swift)
|
|
||||||
|
|
||||||
## Author
|
## Author
|
||||||
|
|
||||||
|
@ -140,162 +140,13 @@ Authentication schemes defined for the API:
|
|||||||
- **Type**: HTTP basic authentication
|
- **Type**: HTTP basic authentication
|
||||||
|
|
||||||
|
|
||||||
|
# How do I migrate from the Swift 5 generator to the swift 6 generator?
|
||||||
|
|
||||||
|
https://openapi-generator.tech/docs/faq-generators#how-do-i-migrate-from-the-swift-5-generator-to-the-swift-6-generator
|
||||||
|
|
||||||
### How do I implement bearer token authentication with URLSession on the Swift 5 API client?
|
### How do I implement bearer token authentication with URLSession on the Swift 5 API client?
|
||||||
|
|
||||||
First you subclass RequestBuilderFactory
|
https://openapi-generator.tech/docs/faq-generators#how-do-i-implement-bearer-token-authentication-with-urlsession-on-the-swift-5-api-client
|
||||||
```
|
|
||||||
class BearerRequestBuilderFactory: RequestBuilderFactory {
|
|
||||||
func getNonDecodableBuilder<T>() -> RequestBuilder<T>.Type {
|
|
||||||
BearerRequestBuilder<T>.self
|
|
||||||
}
|
|
||||||
|
|
||||||
func getBuilder<T: Decodable>() -> RequestBuilder<T>.Type {
|
|
||||||
BearerDecodableRequestBuilder<T>.self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Then you subclass URLSessionRequestBuilder and URLSessionDecodableRequestBuilder
|
|
||||||
```
|
|
||||||
class BearerRequestBuilder<T>: URLSessionRequestBuilder<T> {
|
|
||||||
@discardableResult
|
|
||||||
override func execute(_ apiResponseQueue: DispatchQueue = PetstoreClientAPI.apiResponseQueue, _ completion: @escaping (Result<Response<T>, ErrorResponse>) -> Void) -> RequestTask {
|
|
||||||
|
|
||||||
// Before making the request, we can validate if we have a bearer token to be able to make a request
|
|
||||||
BearerTokenHandler.refreshTokenIfDoesntExist {
|
|
||||||
|
|
||||||
// Here we make the request
|
|
||||||
super.execute(apiResponseQueue) { result in
|
|
||||||
|
|
||||||
switch result {
|
|
||||||
case .success:
|
|
||||||
// If we got a successful response, we send the response to the completion block
|
|
||||||
completion(result)
|
|
||||||
|
|
||||||
case let .failure(error):
|
|
||||||
|
|
||||||
// If we got a failure response, we will analyse the error to see what we should do with it
|
|
||||||
if case let ErrorResponse.error(_, data, response, error) = error {
|
|
||||||
|
|
||||||
// If the error is an ErrorResponse.error() we will analyse it to see if it's a 401, and if it's a 401, we will refresh the token and retry the request
|
|
||||||
BearerTokenHandler.refreshTokenIfUnauthorizedRequestResponse(
|
|
||||||
data: data,
|
|
||||||
response: response,
|
|
||||||
error: error
|
|
||||||
) { wasTokenRefreshed in
|
|
||||||
|
|
||||||
if wasTokenRefreshed {
|
|
||||||
// If the token was refreshed, it's because it was a 401 error, so we refreshed the token, and we are going to retry the request by calling self.execute()
|
|
||||||
self.execute(apiResponseQueue, completion)
|
|
||||||
} else {
|
|
||||||
// If the token was not refreshed, it's because it was not a 401 error, so we send the response to the completion block
|
|
||||||
completion(result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// If it's an unknown error, we send the response to the completion block
|
|
||||||
completion(result)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return requestTask
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class BearerDecodableRequestBuilder<T: Decodable>: URLSessionDecodableRequestBuilder<T> {
|
|
||||||
@discardableResult
|
|
||||||
override func execute(_ apiResponseQueue: DispatchQueue = PetstoreClientAPI.apiResponseQueue, _ completion: @escaping (Result<Response<T>, ErrorResponse>) -> Void) -> RequestTask {
|
|
||||||
// Before making the request, we can validate if we have a bearer token to be able to make a request
|
|
||||||
BearerTokenHandler.refreshTokenIfDoesntExist {
|
|
||||||
|
|
||||||
// Here we make the request
|
|
||||||
super.execute(apiResponseQueue) { result in
|
|
||||||
|
|
||||||
switch result {
|
|
||||||
case .success:
|
|
||||||
// If we got a successful response, we send the response to the completion block
|
|
||||||
completion(result)
|
|
||||||
|
|
||||||
case let .failure(error):
|
|
||||||
|
|
||||||
// If we got a failure response, we will analyse the error to see what we should do with it
|
|
||||||
if case let ErrorResponse.error(_, data, response, error) = error {
|
|
||||||
|
|
||||||
// If the error is an ErrorResponse.error() we will analyse it to see if it's a 401, and if it's a 401, we will refresh the token and retry the request
|
|
||||||
BearerTokenHandler.refreshTokenIfUnauthorizedRequestResponse(
|
|
||||||
data: data,
|
|
||||||
response: response,
|
|
||||||
error: error
|
|
||||||
) { wasTokenRefreshed in
|
|
||||||
|
|
||||||
if wasTokenRefreshed {
|
|
||||||
// If the token was refreshed, it's because it was a 401 error, so we refreshed the token, and we are going to retry the request by calling self.execute()
|
|
||||||
self.execute(apiResponseQueue, completion)
|
|
||||||
} else {
|
|
||||||
// If the token was not refreshed, it's because it was not a 401 error, so we send the response to the completion block
|
|
||||||
completion(result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// If it's an unknown error, we send the response to the completion block
|
|
||||||
completion(result)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return requestTask
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class BearerTokenHandler {
|
|
||||||
private static var bearerToken: String? = nil
|
|
||||||
|
|
||||||
static func refreshTokenIfDoesntExist(completionHandler: @escaping () -> Void) {
|
|
||||||
if bearerToken != nil {
|
|
||||||
completionHandler()
|
|
||||||
} else {
|
|
||||||
startRefreshingToken {
|
|
||||||
completionHandler()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static func refreshTokenIfUnauthorizedRequestResponse(data: Data?, response: URLResponse?, error: Error?, completionHandler: @escaping (Bool) -> Void) {
|
|
||||||
if let response = response as? HTTPURLResponse, response.statusCode == 401 {
|
|
||||||
startRefreshingToken {
|
|
||||||
completionHandler(true)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
completionHandler(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static func startRefreshingToken(completionHandler: @escaping () -> Void) {
|
|
||||||
// Get a bearer token
|
|
||||||
let dummyBearerToken = "..."
|
|
||||||
|
|
||||||
bearerToken = dummyBearerToken
|
|
||||||
PetstoreClientAPI.customHeaders["Authorization"] = "Bearer \(dummyBearerToken)"
|
|
||||||
|
|
||||||
completionHandler()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Then you assign the `BearerRequestBuilderFactory` to the property `requestBuilderFactory`.
|
|
||||||
|
|
||||||
`PetstoreClientAPI.requestBuilderFactory = BearerRequestBuilderFactory()`
|
|
||||||
|
|
||||||
The name `PetstoreClientAPI.requestBuilderFactory` will change depending on your project name.
|
|
||||||
|
|
||||||
Here is a working sample that put's together all of this.
|
|
||||||
[AppDelegate.swift](https://github.com/OpenAPITools/openapi-generator/blob/master/samples/client/petstore/swift5/urlsessionLibrary/SwaggerClientTests/SwaggerClient/AppDelegate.swift)
|
|
||||||
[BearerDecodableRequestBuilder.swift](https://github.com/OpenAPITools/openapi-generator/blob/master/samples/client/petstore/swift5/urlsessionLibrary/SwaggerClientTests/SwaggerClient/BearerDecodableRequestBuilder.swift)
|
|
||||||
|
|
||||||
## Author
|
## Author
|
||||||
|
|
||||||
|
@ -42,162 +42,13 @@ Class | Method | HTTP request | Description
|
|||||||
Endpoints do not require authorization.
|
Endpoints do not require authorization.
|
||||||
|
|
||||||
|
|
||||||
|
# How do I migrate from the Swift 5 generator to the swift 6 generator?
|
||||||
|
|
||||||
|
https://openapi-generator.tech/docs/faq-generators#how-do-i-migrate-from-the-swift-5-generator-to-the-swift-6-generator
|
||||||
|
|
||||||
### How do I implement bearer token authentication with URLSession on the Swift 5 API client?
|
### How do I implement bearer token authentication with URLSession on the Swift 5 API client?
|
||||||
|
|
||||||
First you subclass RequestBuilderFactory
|
https://openapi-generator.tech/docs/faq-generators#how-do-i-implement-bearer-token-authentication-with-urlsession-on-the-swift-5-api-client
|
||||||
```
|
|
||||||
class BearerRequestBuilderFactory: RequestBuilderFactory {
|
|
||||||
func getNonDecodableBuilder<T>() -> RequestBuilder<T>.Type {
|
|
||||||
BearerRequestBuilder<T>.self
|
|
||||||
}
|
|
||||||
|
|
||||||
func getBuilder<T: Decodable>() -> RequestBuilder<T>.Type {
|
|
||||||
BearerDecodableRequestBuilder<T>.self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Then you subclass URLSessionRequestBuilder and URLSessionDecodableRequestBuilder
|
|
||||||
```
|
|
||||||
class BearerRequestBuilder<T>: URLSessionRequestBuilder<T> {
|
|
||||||
@discardableResult
|
|
||||||
override func execute(_ apiResponseQueue: DispatchQueue = PetstoreClientAPI.apiResponseQueue, _ completion: @escaping (Result<Response<T>, ErrorResponse>) -> Void) -> RequestTask {
|
|
||||||
|
|
||||||
// Before making the request, we can validate if we have a bearer token to be able to make a request
|
|
||||||
BearerTokenHandler.refreshTokenIfDoesntExist {
|
|
||||||
|
|
||||||
// Here we make the request
|
|
||||||
super.execute(apiResponseQueue) { result in
|
|
||||||
|
|
||||||
switch result {
|
|
||||||
case .success:
|
|
||||||
// If we got a successful response, we send the response to the completion block
|
|
||||||
completion(result)
|
|
||||||
|
|
||||||
case let .failure(error):
|
|
||||||
|
|
||||||
// If we got a failure response, we will analyse the error to see what we should do with it
|
|
||||||
if case let ErrorResponse.error(_, data, response, error) = error {
|
|
||||||
|
|
||||||
// If the error is an ErrorResponse.error() we will analyse it to see if it's a 401, and if it's a 401, we will refresh the token and retry the request
|
|
||||||
BearerTokenHandler.refreshTokenIfUnauthorizedRequestResponse(
|
|
||||||
data: data,
|
|
||||||
response: response,
|
|
||||||
error: error
|
|
||||||
) { wasTokenRefreshed in
|
|
||||||
|
|
||||||
if wasTokenRefreshed {
|
|
||||||
// If the token was refreshed, it's because it was a 401 error, so we refreshed the token, and we are going to retry the request by calling self.execute()
|
|
||||||
self.execute(apiResponseQueue, completion)
|
|
||||||
} else {
|
|
||||||
// If the token was not refreshed, it's because it was not a 401 error, so we send the response to the completion block
|
|
||||||
completion(result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// If it's an unknown error, we send the response to the completion block
|
|
||||||
completion(result)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return requestTask
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class BearerDecodableRequestBuilder<T: Decodable>: URLSessionDecodableRequestBuilder<T> {
|
|
||||||
@discardableResult
|
|
||||||
override func execute(_ apiResponseQueue: DispatchQueue = PetstoreClientAPI.apiResponseQueue, _ completion: @escaping (Result<Response<T>, ErrorResponse>) -> Void) -> RequestTask {
|
|
||||||
// Before making the request, we can validate if we have a bearer token to be able to make a request
|
|
||||||
BearerTokenHandler.refreshTokenIfDoesntExist {
|
|
||||||
|
|
||||||
// Here we make the request
|
|
||||||
super.execute(apiResponseQueue) { result in
|
|
||||||
|
|
||||||
switch result {
|
|
||||||
case .success:
|
|
||||||
// If we got a successful response, we send the response to the completion block
|
|
||||||
completion(result)
|
|
||||||
|
|
||||||
case let .failure(error):
|
|
||||||
|
|
||||||
// If we got a failure response, we will analyse the error to see what we should do with it
|
|
||||||
if case let ErrorResponse.error(_, data, response, error) = error {
|
|
||||||
|
|
||||||
// If the error is an ErrorResponse.error() we will analyse it to see if it's a 401, and if it's a 401, we will refresh the token and retry the request
|
|
||||||
BearerTokenHandler.refreshTokenIfUnauthorizedRequestResponse(
|
|
||||||
data: data,
|
|
||||||
response: response,
|
|
||||||
error: error
|
|
||||||
) { wasTokenRefreshed in
|
|
||||||
|
|
||||||
if wasTokenRefreshed {
|
|
||||||
// If the token was refreshed, it's because it was a 401 error, so we refreshed the token, and we are going to retry the request by calling self.execute()
|
|
||||||
self.execute(apiResponseQueue, completion)
|
|
||||||
} else {
|
|
||||||
// If the token was not refreshed, it's because it was not a 401 error, so we send the response to the completion block
|
|
||||||
completion(result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// If it's an unknown error, we send the response to the completion block
|
|
||||||
completion(result)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return requestTask
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class BearerTokenHandler {
|
|
||||||
private static var bearerToken: String? = nil
|
|
||||||
|
|
||||||
static func refreshTokenIfDoesntExist(completionHandler: @escaping () -> Void) {
|
|
||||||
if bearerToken != nil {
|
|
||||||
completionHandler()
|
|
||||||
} else {
|
|
||||||
startRefreshingToken {
|
|
||||||
completionHandler()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static func refreshTokenIfUnauthorizedRequestResponse(data: Data?, response: URLResponse?, error: Error?, completionHandler: @escaping (Bool) -> Void) {
|
|
||||||
if let response = response as? HTTPURLResponse, response.statusCode == 401 {
|
|
||||||
startRefreshingToken {
|
|
||||||
completionHandler(true)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
completionHandler(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static func startRefreshingToken(completionHandler: @escaping () -> Void) {
|
|
||||||
// Get a bearer token
|
|
||||||
let dummyBearerToken = "..."
|
|
||||||
|
|
||||||
bearerToken = dummyBearerToken
|
|
||||||
PetstoreClientAPI.customHeaders["Authorization"] = "Bearer \(dummyBearerToken)"
|
|
||||||
|
|
||||||
completionHandler()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Then you assign the `BearerRequestBuilderFactory` to the property `requestBuilderFactory`.
|
|
||||||
|
|
||||||
`PetstoreClientAPI.requestBuilderFactory = BearerRequestBuilderFactory()`
|
|
||||||
|
|
||||||
The name `PetstoreClientAPI.requestBuilderFactory` will change depending on your project name.
|
|
||||||
|
|
||||||
Here is a working sample that put's together all of this.
|
|
||||||
[AppDelegate.swift](https://github.com/OpenAPITools/openapi-generator/blob/master/samples/client/petstore/swift5/urlsessionLibrary/SwaggerClientTests/SwaggerClient/AppDelegate.swift)
|
|
||||||
[BearerDecodableRequestBuilder.swift](https://github.com/OpenAPITools/openapi-generator/blob/master/samples/client/petstore/swift5/urlsessionLibrary/SwaggerClientTests/SwaggerClient/BearerDecodableRequestBuilder.swift)
|
|
||||||
|
|
||||||
## Author
|
## Author
|
||||||
|
|
||||||
|
@ -140,162 +140,13 @@ Authentication schemes defined for the API:
|
|||||||
- **Type**: HTTP basic authentication
|
- **Type**: HTTP basic authentication
|
||||||
|
|
||||||
|
|
||||||
|
# How do I migrate from the Swift 5 generator to the swift 6 generator?
|
||||||
|
|
||||||
|
https://openapi-generator.tech/docs/faq-generators#how-do-i-migrate-from-the-swift-5-generator-to-the-swift-6-generator
|
||||||
|
|
||||||
### How do I implement bearer token authentication with URLSession on the Swift 5 API client?
|
### How do I implement bearer token authentication with URLSession on the Swift 5 API client?
|
||||||
|
|
||||||
First you subclass RequestBuilderFactory
|
https://openapi-generator.tech/docs/faq-generators#how-do-i-implement-bearer-token-authentication-with-urlsession-on-the-swift-5-api-client
|
||||||
```
|
|
||||||
class BearerRequestBuilderFactory: RequestBuilderFactory {
|
|
||||||
func getNonDecodableBuilder<T>() -> RequestBuilder<T>.Type {
|
|
||||||
BearerRequestBuilder<T>.self
|
|
||||||
}
|
|
||||||
|
|
||||||
func getBuilder<T: Decodable>() -> RequestBuilder<T>.Type {
|
|
||||||
BearerDecodableRequestBuilder<T>.self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Then you subclass URLSessionRequestBuilder and URLSessionDecodableRequestBuilder
|
|
||||||
```
|
|
||||||
class BearerRequestBuilder<T>: URLSessionRequestBuilder<T> {
|
|
||||||
@discardableResult
|
|
||||||
override func execute(_ apiResponseQueue: DispatchQueue = PetstoreClientAPI.apiResponseQueue, _ completion: @escaping (Result<Response<T>, ErrorResponse>) -> Void) -> RequestTask {
|
|
||||||
|
|
||||||
// Before making the request, we can validate if we have a bearer token to be able to make a request
|
|
||||||
BearerTokenHandler.refreshTokenIfDoesntExist {
|
|
||||||
|
|
||||||
// Here we make the request
|
|
||||||
super.execute(apiResponseQueue) { result in
|
|
||||||
|
|
||||||
switch result {
|
|
||||||
case .success:
|
|
||||||
// If we got a successful response, we send the response to the completion block
|
|
||||||
completion(result)
|
|
||||||
|
|
||||||
case let .failure(error):
|
|
||||||
|
|
||||||
// If we got a failure response, we will analyse the error to see what we should do with it
|
|
||||||
if case let ErrorResponse.error(_, data, response, error) = error {
|
|
||||||
|
|
||||||
// If the error is an ErrorResponse.error() we will analyse it to see if it's a 401, and if it's a 401, we will refresh the token and retry the request
|
|
||||||
BearerTokenHandler.refreshTokenIfUnauthorizedRequestResponse(
|
|
||||||
data: data,
|
|
||||||
response: response,
|
|
||||||
error: error
|
|
||||||
) { wasTokenRefreshed in
|
|
||||||
|
|
||||||
if wasTokenRefreshed {
|
|
||||||
// If the token was refreshed, it's because it was a 401 error, so we refreshed the token, and we are going to retry the request by calling self.execute()
|
|
||||||
self.execute(apiResponseQueue, completion)
|
|
||||||
} else {
|
|
||||||
// If the token was not refreshed, it's because it was not a 401 error, so we send the response to the completion block
|
|
||||||
completion(result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// If it's an unknown error, we send the response to the completion block
|
|
||||||
completion(result)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return requestTask
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class BearerDecodableRequestBuilder<T: Decodable>: URLSessionDecodableRequestBuilder<T> {
|
|
||||||
@discardableResult
|
|
||||||
override func execute(_ apiResponseQueue: DispatchQueue = PetstoreClientAPI.apiResponseQueue, _ completion: @escaping (Result<Response<T>, ErrorResponse>) -> Void) -> RequestTask {
|
|
||||||
// Before making the request, we can validate if we have a bearer token to be able to make a request
|
|
||||||
BearerTokenHandler.refreshTokenIfDoesntExist {
|
|
||||||
|
|
||||||
// Here we make the request
|
|
||||||
super.execute(apiResponseQueue) { result in
|
|
||||||
|
|
||||||
switch result {
|
|
||||||
case .success:
|
|
||||||
// If we got a successful response, we send the response to the completion block
|
|
||||||
completion(result)
|
|
||||||
|
|
||||||
case let .failure(error):
|
|
||||||
|
|
||||||
// If we got a failure response, we will analyse the error to see what we should do with it
|
|
||||||
if case let ErrorResponse.error(_, data, response, error) = error {
|
|
||||||
|
|
||||||
// If the error is an ErrorResponse.error() we will analyse it to see if it's a 401, and if it's a 401, we will refresh the token and retry the request
|
|
||||||
BearerTokenHandler.refreshTokenIfUnauthorizedRequestResponse(
|
|
||||||
data: data,
|
|
||||||
response: response,
|
|
||||||
error: error
|
|
||||||
) { wasTokenRefreshed in
|
|
||||||
|
|
||||||
if wasTokenRefreshed {
|
|
||||||
// If the token was refreshed, it's because it was a 401 error, so we refreshed the token, and we are going to retry the request by calling self.execute()
|
|
||||||
self.execute(apiResponseQueue, completion)
|
|
||||||
} else {
|
|
||||||
// If the token was not refreshed, it's because it was not a 401 error, so we send the response to the completion block
|
|
||||||
completion(result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// If it's an unknown error, we send the response to the completion block
|
|
||||||
completion(result)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return requestTask
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class BearerTokenHandler {
|
|
||||||
private static var bearerToken: String? = nil
|
|
||||||
|
|
||||||
static func refreshTokenIfDoesntExist(completionHandler: @escaping () -> Void) {
|
|
||||||
if bearerToken != nil {
|
|
||||||
completionHandler()
|
|
||||||
} else {
|
|
||||||
startRefreshingToken {
|
|
||||||
completionHandler()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static func refreshTokenIfUnauthorizedRequestResponse(data: Data?, response: URLResponse?, error: Error?, completionHandler: @escaping (Bool) -> Void) {
|
|
||||||
if let response = response as? HTTPURLResponse, response.statusCode == 401 {
|
|
||||||
startRefreshingToken {
|
|
||||||
completionHandler(true)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
completionHandler(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static func startRefreshingToken(completionHandler: @escaping () -> Void) {
|
|
||||||
// Get a bearer token
|
|
||||||
let dummyBearerToken = "..."
|
|
||||||
|
|
||||||
bearerToken = dummyBearerToken
|
|
||||||
PetstoreClientAPI.customHeaders["Authorization"] = "Bearer \(dummyBearerToken)"
|
|
||||||
|
|
||||||
completionHandler()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Then you assign the `BearerRequestBuilderFactory` to the property `requestBuilderFactory`.
|
|
||||||
|
|
||||||
`PetstoreClientAPI.requestBuilderFactory = BearerRequestBuilderFactory()`
|
|
||||||
|
|
||||||
The name `PetstoreClientAPI.requestBuilderFactory` will change depending on your project name.
|
|
||||||
|
|
||||||
Here is a working sample that put's together all of this.
|
|
||||||
[AppDelegate.swift](https://github.com/OpenAPITools/openapi-generator/blob/master/samples/client/petstore/swift5/urlsessionLibrary/SwaggerClientTests/SwaggerClient/AppDelegate.swift)
|
|
||||||
[BearerDecodableRequestBuilder.swift](https://github.com/OpenAPITools/openapi-generator/blob/master/samples/client/petstore/swift5/urlsessionLibrary/SwaggerClientTests/SwaggerClient/BearerDecodableRequestBuilder.swift)
|
|
||||||
|
|
||||||
## Author
|
## Author
|
||||||
|
|
||||||
|
@ -140,162 +140,13 @@ Authentication schemes defined for the API:
|
|||||||
- **Type**: HTTP basic authentication
|
- **Type**: HTTP basic authentication
|
||||||
|
|
||||||
|
|
||||||
|
# How do I migrate from the Swift 5 generator to the swift 6 generator?
|
||||||
|
|
||||||
|
https://openapi-generator.tech/docs/faq-generators#how-do-i-migrate-from-the-swift-5-generator-to-the-swift-6-generator
|
||||||
|
|
||||||
### How do I implement bearer token authentication with URLSession on the Swift 5 API client?
|
### How do I implement bearer token authentication with URLSession on the Swift 5 API client?
|
||||||
|
|
||||||
First you subclass RequestBuilderFactory
|
https://openapi-generator.tech/docs/faq-generators#how-do-i-implement-bearer-token-authentication-with-urlsession-on-the-swift-5-api-client
|
||||||
```
|
|
||||||
class BearerRequestBuilderFactory: RequestBuilderFactory {
|
|
||||||
func getNonDecodableBuilder<T>() -> RequestBuilder<T>.Type {
|
|
||||||
BearerRequestBuilder<T>.self
|
|
||||||
}
|
|
||||||
|
|
||||||
func getBuilder<T: Decodable>() -> RequestBuilder<T>.Type {
|
|
||||||
BearerDecodableRequestBuilder<T>.self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Then you subclass URLSessionRequestBuilder and URLSessionDecodableRequestBuilder
|
|
||||||
```
|
|
||||||
class BearerRequestBuilder<T>: URLSessionRequestBuilder<T> {
|
|
||||||
@discardableResult
|
|
||||||
override func execute(_ apiResponseQueue: DispatchQueue = PetstoreClientAPI.apiResponseQueue, _ completion: @escaping (Result<Response<T>, ErrorResponse>) -> Void) -> RequestTask {
|
|
||||||
|
|
||||||
// Before making the request, we can validate if we have a bearer token to be able to make a request
|
|
||||||
BearerTokenHandler.refreshTokenIfDoesntExist {
|
|
||||||
|
|
||||||
// Here we make the request
|
|
||||||
super.execute(apiResponseQueue) { result in
|
|
||||||
|
|
||||||
switch result {
|
|
||||||
case .success:
|
|
||||||
// If we got a successful response, we send the response to the completion block
|
|
||||||
completion(result)
|
|
||||||
|
|
||||||
case let .failure(error):
|
|
||||||
|
|
||||||
// If we got a failure response, we will analyse the error to see what we should do with it
|
|
||||||
if case let ErrorResponse.error(_, data, response, error) = error {
|
|
||||||
|
|
||||||
// If the error is an ErrorResponse.error() we will analyse it to see if it's a 401, and if it's a 401, we will refresh the token and retry the request
|
|
||||||
BearerTokenHandler.refreshTokenIfUnauthorizedRequestResponse(
|
|
||||||
data: data,
|
|
||||||
response: response,
|
|
||||||
error: error
|
|
||||||
) { wasTokenRefreshed in
|
|
||||||
|
|
||||||
if wasTokenRefreshed {
|
|
||||||
// If the token was refreshed, it's because it was a 401 error, so we refreshed the token, and we are going to retry the request by calling self.execute()
|
|
||||||
self.execute(apiResponseQueue, completion)
|
|
||||||
} else {
|
|
||||||
// If the token was not refreshed, it's because it was not a 401 error, so we send the response to the completion block
|
|
||||||
completion(result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// If it's an unknown error, we send the response to the completion block
|
|
||||||
completion(result)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return requestTask
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class BearerDecodableRequestBuilder<T: Decodable>: URLSessionDecodableRequestBuilder<T> {
|
|
||||||
@discardableResult
|
|
||||||
override func execute(_ apiResponseQueue: DispatchQueue = PetstoreClientAPI.apiResponseQueue, _ completion: @escaping (Result<Response<T>, ErrorResponse>) -> Void) -> RequestTask {
|
|
||||||
// Before making the request, we can validate if we have a bearer token to be able to make a request
|
|
||||||
BearerTokenHandler.refreshTokenIfDoesntExist {
|
|
||||||
|
|
||||||
// Here we make the request
|
|
||||||
super.execute(apiResponseQueue) { result in
|
|
||||||
|
|
||||||
switch result {
|
|
||||||
case .success:
|
|
||||||
// If we got a successful response, we send the response to the completion block
|
|
||||||
completion(result)
|
|
||||||
|
|
||||||
case let .failure(error):
|
|
||||||
|
|
||||||
// If we got a failure response, we will analyse the error to see what we should do with it
|
|
||||||
if case let ErrorResponse.error(_, data, response, error) = error {
|
|
||||||
|
|
||||||
// If the error is an ErrorResponse.error() we will analyse it to see if it's a 401, and if it's a 401, we will refresh the token and retry the request
|
|
||||||
BearerTokenHandler.refreshTokenIfUnauthorizedRequestResponse(
|
|
||||||
data: data,
|
|
||||||
response: response,
|
|
||||||
error: error
|
|
||||||
) { wasTokenRefreshed in
|
|
||||||
|
|
||||||
if wasTokenRefreshed {
|
|
||||||
// If the token was refreshed, it's because it was a 401 error, so we refreshed the token, and we are going to retry the request by calling self.execute()
|
|
||||||
self.execute(apiResponseQueue, completion)
|
|
||||||
} else {
|
|
||||||
// If the token was not refreshed, it's because it was not a 401 error, so we send the response to the completion block
|
|
||||||
completion(result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// If it's an unknown error, we send the response to the completion block
|
|
||||||
completion(result)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return requestTask
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class BearerTokenHandler {
|
|
||||||
private static var bearerToken: String? = nil
|
|
||||||
|
|
||||||
static func refreshTokenIfDoesntExist(completionHandler: @escaping () -> Void) {
|
|
||||||
if bearerToken != nil {
|
|
||||||
completionHandler()
|
|
||||||
} else {
|
|
||||||
startRefreshingToken {
|
|
||||||
completionHandler()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static func refreshTokenIfUnauthorizedRequestResponse(data: Data?, response: URLResponse?, error: Error?, completionHandler: @escaping (Bool) -> Void) {
|
|
||||||
if let response = response as? HTTPURLResponse, response.statusCode == 401 {
|
|
||||||
startRefreshingToken {
|
|
||||||
completionHandler(true)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
completionHandler(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static func startRefreshingToken(completionHandler: @escaping () -> Void) {
|
|
||||||
// Get a bearer token
|
|
||||||
let dummyBearerToken = "..."
|
|
||||||
|
|
||||||
bearerToken = dummyBearerToken
|
|
||||||
PetstoreClientAPI.customHeaders["Authorization"] = "Bearer \(dummyBearerToken)"
|
|
||||||
|
|
||||||
completionHandler()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Then you assign the `BearerRequestBuilderFactory` to the property `requestBuilderFactory`.
|
|
||||||
|
|
||||||
`PetstoreClientAPI.requestBuilderFactory = BearerRequestBuilderFactory()`
|
|
||||||
|
|
||||||
The name `PetstoreClientAPI.requestBuilderFactory` will change depending on your project name.
|
|
||||||
|
|
||||||
Here is a working sample that put's together all of this.
|
|
||||||
[AppDelegate.swift](https://github.com/OpenAPITools/openapi-generator/blob/master/samples/client/petstore/swift5/urlsessionLibrary/SwaggerClientTests/SwaggerClient/AppDelegate.swift)
|
|
||||||
[BearerDecodableRequestBuilder.swift](https://github.com/OpenAPITools/openapi-generator/blob/master/samples/client/petstore/swift5/urlsessionLibrary/SwaggerClientTests/SwaggerClient/BearerDecodableRequestBuilder.swift)
|
|
||||||
|
|
||||||
## Author
|
## Author
|
||||||
|
|
||||||
|
@ -140,162 +140,13 @@ Authentication schemes defined for the API:
|
|||||||
- **Type**: HTTP basic authentication
|
- **Type**: HTTP basic authentication
|
||||||
|
|
||||||
|
|
||||||
|
# How do I migrate from the Swift 5 generator to the swift 6 generator?
|
||||||
|
|
||||||
|
https://openapi-generator.tech/docs/faq-generators#how-do-i-migrate-from-the-swift-5-generator-to-the-swift-6-generator
|
||||||
|
|
||||||
### How do I implement bearer token authentication with URLSession on the Swift 5 API client?
|
### How do I implement bearer token authentication with URLSession on the Swift 5 API client?
|
||||||
|
|
||||||
First you subclass RequestBuilderFactory
|
https://openapi-generator.tech/docs/faq-generators#how-do-i-implement-bearer-token-authentication-with-urlsession-on-the-swift-5-api-client
|
||||||
```
|
|
||||||
class BearerRequestBuilderFactory: RequestBuilderFactory {
|
|
||||||
func getNonDecodableBuilder<T>() -> RequestBuilder<T>.Type {
|
|
||||||
BearerRequestBuilder<T>.self
|
|
||||||
}
|
|
||||||
|
|
||||||
func getBuilder<T: Decodable>() -> RequestBuilder<T>.Type {
|
|
||||||
BearerDecodableRequestBuilder<T>.self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Then you subclass URLSessionRequestBuilder and URLSessionDecodableRequestBuilder
|
|
||||||
```
|
|
||||||
class BearerRequestBuilder<T>: URLSessionRequestBuilder<T> {
|
|
||||||
@discardableResult
|
|
||||||
override func execute(_ apiResponseQueue: DispatchQueue = PetstoreClientAPI.apiResponseQueue, _ completion: @escaping (Result<Response<T>, ErrorResponse>) -> Void) -> RequestTask {
|
|
||||||
|
|
||||||
// Before making the request, we can validate if we have a bearer token to be able to make a request
|
|
||||||
BearerTokenHandler.refreshTokenIfDoesntExist {
|
|
||||||
|
|
||||||
// Here we make the request
|
|
||||||
super.execute(apiResponseQueue) { result in
|
|
||||||
|
|
||||||
switch result {
|
|
||||||
case .success:
|
|
||||||
// If we got a successful response, we send the response to the completion block
|
|
||||||
completion(result)
|
|
||||||
|
|
||||||
case let .failure(error):
|
|
||||||
|
|
||||||
// If we got a failure response, we will analyse the error to see what we should do with it
|
|
||||||
if case let ErrorResponse.error(_, data, response, error) = error {
|
|
||||||
|
|
||||||
// If the error is an ErrorResponse.error() we will analyse it to see if it's a 401, and if it's a 401, we will refresh the token and retry the request
|
|
||||||
BearerTokenHandler.refreshTokenIfUnauthorizedRequestResponse(
|
|
||||||
data: data,
|
|
||||||
response: response,
|
|
||||||
error: error
|
|
||||||
) { wasTokenRefreshed in
|
|
||||||
|
|
||||||
if wasTokenRefreshed {
|
|
||||||
// If the token was refreshed, it's because it was a 401 error, so we refreshed the token, and we are going to retry the request by calling self.execute()
|
|
||||||
self.execute(apiResponseQueue, completion)
|
|
||||||
} else {
|
|
||||||
// If the token was not refreshed, it's because it was not a 401 error, so we send the response to the completion block
|
|
||||||
completion(result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// If it's an unknown error, we send the response to the completion block
|
|
||||||
completion(result)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return requestTask
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class BearerDecodableRequestBuilder<T: Decodable>: URLSessionDecodableRequestBuilder<T> {
|
|
||||||
@discardableResult
|
|
||||||
override func execute(_ apiResponseQueue: DispatchQueue = PetstoreClientAPI.apiResponseQueue, _ completion: @escaping (Result<Response<T>, ErrorResponse>) -> Void) -> RequestTask {
|
|
||||||
// Before making the request, we can validate if we have a bearer token to be able to make a request
|
|
||||||
BearerTokenHandler.refreshTokenIfDoesntExist {
|
|
||||||
|
|
||||||
// Here we make the request
|
|
||||||
super.execute(apiResponseQueue) { result in
|
|
||||||
|
|
||||||
switch result {
|
|
||||||
case .success:
|
|
||||||
// If we got a successful response, we send the response to the completion block
|
|
||||||
completion(result)
|
|
||||||
|
|
||||||
case let .failure(error):
|
|
||||||
|
|
||||||
// If we got a failure response, we will analyse the error to see what we should do with it
|
|
||||||
if case let ErrorResponse.error(_, data, response, error) = error {
|
|
||||||
|
|
||||||
// If the error is an ErrorResponse.error() we will analyse it to see if it's a 401, and if it's a 401, we will refresh the token and retry the request
|
|
||||||
BearerTokenHandler.refreshTokenIfUnauthorizedRequestResponse(
|
|
||||||
data: data,
|
|
||||||
response: response,
|
|
||||||
error: error
|
|
||||||
) { wasTokenRefreshed in
|
|
||||||
|
|
||||||
if wasTokenRefreshed {
|
|
||||||
// If the token was refreshed, it's because it was a 401 error, so we refreshed the token, and we are going to retry the request by calling self.execute()
|
|
||||||
self.execute(apiResponseQueue, completion)
|
|
||||||
} else {
|
|
||||||
// If the token was not refreshed, it's because it was not a 401 error, so we send the response to the completion block
|
|
||||||
completion(result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// If it's an unknown error, we send the response to the completion block
|
|
||||||
completion(result)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return requestTask
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class BearerTokenHandler {
|
|
||||||
private static var bearerToken: String? = nil
|
|
||||||
|
|
||||||
static func refreshTokenIfDoesntExist(completionHandler: @escaping () -> Void) {
|
|
||||||
if bearerToken != nil {
|
|
||||||
completionHandler()
|
|
||||||
} else {
|
|
||||||
startRefreshingToken {
|
|
||||||
completionHandler()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static func refreshTokenIfUnauthorizedRequestResponse(data: Data?, response: URLResponse?, error: Error?, completionHandler: @escaping (Bool) -> Void) {
|
|
||||||
if let response = response as? HTTPURLResponse, response.statusCode == 401 {
|
|
||||||
startRefreshingToken {
|
|
||||||
completionHandler(true)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
completionHandler(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static func startRefreshingToken(completionHandler: @escaping () -> Void) {
|
|
||||||
// Get a bearer token
|
|
||||||
let dummyBearerToken = "..."
|
|
||||||
|
|
||||||
bearerToken = dummyBearerToken
|
|
||||||
PetstoreClientAPI.customHeaders["Authorization"] = "Bearer \(dummyBearerToken)"
|
|
||||||
|
|
||||||
completionHandler()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Then you assign the `BearerRequestBuilderFactory` to the property `requestBuilderFactory`.
|
|
||||||
|
|
||||||
`PetstoreClientAPI.requestBuilderFactory = BearerRequestBuilderFactory()`
|
|
||||||
|
|
||||||
The name `PetstoreClientAPI.requestBuilderFactory` will change depending on your project name.
|
|
||||||
|
|
||||||
Here is a working sample that put's together all of this.
|
|
||||||
[AppDelegate.swift](https://github.com/OpenAPITools/openapi-generator/blob/master/samples/client/petstore/swift5/urlsessionLibrary/SwaggerClientTests/SwaggerClient/AppDelegate.swift)
|
|
||||||
[BearerDecodableRequestBuilder.swift](https://github.com/OpenAPITools/openapi-generator/blob/master/samples/client/petstore/swift5/urlsessionLibrary/SwaggerClientTests/SwaggerClient/BearerDecodableRequestBuilder.swift)
|
|
||||||
|
|
||||||
## Author
|
## Author
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ DIRECTORY=`dirname $0`
|
|||||||
(cd $DIRECTORY/asyncAwaitLibrary/SwaggerClientTests/ && ./run_xcodebuild.sh)
|
(cd $DIRECTORY/asyncAwaitLibrary/SwaggerClientTests/ && ./run_xcodebuild.sh)
|
||||||
(cd $DIRECTORY/combineLibrary/SwaggerClientTests/ && ./run_xcodebuild.sh)
|
(cd $DIRECTORY/combineLibrary/SwaggerClientTests/ && ./run_xcodebuild.sh)
|
||||||
(cd $DIRECTORY/default/SwaggerClientTests/ && ./run_xcodebuild.sh)
|
(cd $DIRECTORY/default/SwaggerClientTests/ && ./run_xcodebuild.sh)
|
||||||
(cd $DIRECTORY/promisekitLibrary/SwaggerClientTests/ && ./run_xcodebuild.sh)
|
# (cd $DIRECTORY/promisekitLibrary/SwaggerClientTests/ && ./run_xcodebuild.sh)
|
||||||
(cd $DIRECTORY/rxswiftLibrary/SwaggerClientTests/ && ./run_xcodebuild.sh)
|
(cd $DIRECTORY/rxswiftLibrary/SwaggerClientTests/ && ./run_xcodebuild.sh)
|
||||||
# (cd $DIRECTORY/urlsessionLibrary/SwaggerClientTests/ && ./run_xcodebuild.sh)
|
# (cd $DIRECTORY/urlsessionLibrary/SwaggerClientTests/ && ./run_xcodebuild.sh)
|
||||||
|
|
||||||
@ -19,7 +19,7 @@ DIRECTORY=`dirname $0`
|
|||||||
(cd $DIRECTORY/default/ && ./run_spmbuild.sh)
|
(cd $DIRECTORY/default/ && ./run_spmbuild.sh)
|
||||||
(cd $DIRECTORY/objcCompatible/ && ./run_spmbuild.sh)
|
(cd $DIRECTORY/objcCompatible/ && ./run_spmbuild.sh)
|
||||||
(cd $DIRECTORY/oneOf/ && ./run_spmbuild.sh)
|
(cd $DIRECTORY/oneOf/ && ./run_spmbuild.sh)
|
||||||
(cd $DIRECTORY/promisekitLibrary/ && ./run_spmbuild.sh)
|
# (cd $DIRECTORY/promisekitLibrary/ && ./run_spmbuild.sh)
|
||||||
(cd $DIRECTORY/resultLibrary/ && ./run_spmbuild.sh)
|
(cd $DIRECTORY/resultLibrary/ && ./run_spmbuild.sh)
|
||||||
(cd $DIRECTORY/rxswiftLibrary/ && ./run_spmbuild.sh)
|
(cd $DIRECTORY/rxswiftLibrary/ && ./run_spmbuild.sh)
|
||||||
(cd $DIRECTORY/urlsessionLibrary/ && ./run_spmbuild.sh)
|
(cd $DIRECTORY/urlsessionLibrary/ && ./run_spmbuild.sh)
|
||||||
|
@ -140,162 +140,13 @@ Authentication schemes defined for the API:
|
|||||||
- **Type**: HTTP basic authentication
|
- **Type**: HTTP basic authentication
|
||||||
|
|
||||||
|
|
||||||
|
# How do I migrate from the Swift 5 generator to the swift 6 generator?
|
||||||
|
|
||||||
|
https://openapi-generator.tech/docs/faq-generators#how-do-i-migrate-from-the-swift-5-generator-to-the-swift-6-generator
|
||||||
|
|
||||||
### How do I implement bearer token authentication with URLSession on the Swift 5 API client?
|
### How do I implement bearer token authentication with URLSession on the Swift 5 API client?
|
||||||
|
|
||||||
First you subclass RequestBuilderFactory
|
https://openapi-generator.tech/docs/faq-generators#how-do-i-implement-bearer-token-authentication-with-urlsession-on-the-swift-5-api-client
|
||||||
```
|
|
||||||
class BearerRequestBuilderFactory: RequestBuilderFactory {
|
|
||||||
func getNonDecodableBuilder<T>() -> RequestBuilder<T>.Type {
|
|
||||||
BearerRequestBuilder<T>.self
|
|
||||||
}
|
|
||||||
|
|
||||||
func getBuilder<T: Decodable>() -> RequestBuilder<T>.Type {
|
|
||||||
BearerDecodableRequestBuilder<T>.self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Then you subclass URLSessionRequestBuilder and URLSessionDecodableRequestBuilder
|
|
||||||
```
|
|
||||||
class BearerRequestBuilder<T>: URLSessionRequestBuilder<T> {
|
|
||||||
@discardableResult
|
|
||||||
override func execute(_ apiResponseQueue: DispatchQueue = PetstoreClientAPI.apiResponseQueue, _ completion: @escaping (Result<Response<T>, ErrorResponse>) -> Void) -> RequestTask {
|
|
||||||
|
|
||||||
// Before making the request, we can validate if we have a bearer token to be able to make a request
|
|
||||||
BearerTokenHandler.refreshTokenIfDoesntExist {
|
|
||||||
|
|
||||||
// Here we make the request
|
|
||||||
super.execute(apiResponseQueue) { result in
|
|
||||||
|
|
||||||
switch result {
|
|
||||||
case .success:
|
|
||||||
// If we got a successful response, we send the response to the completion block
|
|
||||||
completion(result)
|
|
||||||
|
|
||||||
case let .failure(error):
|
|
||||||
|
|
||||||
// If we got a failure response, we will analyse the error to see what we should do with it
|
|
||||||
if case let ErrorResponse.error(_, data, response, error) = error {
|
|
||||||
|
|
||||||
// If the error is an ErrorResponse.error() we will analyse it to see if it's a 401, and if it's a 401, we will refresh the token and retry the request
|
|
||||||
BearerTokenHandler.refreshTokenIfUnauthorizedRequestResponse(
|
|
||||||
data: data,
|
|
||||||
response: response,
|
|
||||||
error: error
|
|
||||||
) { wasTokenRefreshed in
|
|
||||||
|
|
||||||
if wasTokenRefreshed {
|
|
||||||
// If the token was refreshed, it's because it was a 401 error, so we refreshed the token, and we are going to retry the request by calling self.execute()
|
|
||||||
self.execute(apiResponseQueue, completion)
|
|
||||||
} else {
|
|
||||||
// If the token was not refreshed, it's because it was not a 401 error, so we send the response to the completion block
|
|
||||||
completion(result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// If it's an unknown error, we send the response to the completion block
|
|
||||||
completion(result)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return requestTask
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class BearerDecodableRequestBuilder<T: Decodable>: URLSessionDecodableRequestBuilder<T> {
|
|
||||||
@discardableResult
|
|
||||||
override func execute(_ apiResponseQueue: DispatchQueue = PetstoreClientAPI.apiResponseQueue, _ completion: @escaping (Result<Response<T>, ErrorResponse>) -> Void) -> RequestTask {
|
|
||||||
// Before making the request, we can validate if we have a bearer token to be able to make a request
|
|
||||||
BearerTokenHandler.refreshTokenIfDoesntExist {
|
|
||||||
|
|
||||||
// Here we make the request
|
|
||||||
super.execute(apiResponseQueue) { result in
|
|
||||||
|
|
||||||
switch result {
|
|
||||||
case .success:
|
|
||||||
// If we got a successful response, we send the response to the completion block
|
|
||||||
completion(result)
|
|
||||||
|
|
||||||
case let .failure(error):
|
|
||||||
|
|
||||||
// If we got a failure response, we will analyse the error to see what we should do with it
|
|
||||||
if case let ErrorResponse.error(_, data, response, error) = error {
|
|
||||||
|
|
||||||
// If the error is an ErrorResponse.error() we will analyse it to see if it's a 401, and if it's a 401, we will refresh the token and retry the request
|
|
||||||
BearerTokenHandler.refreshTokenIfUnauthorizedRequestResponse(
|
|
||||||
data: data,
|
|
||||||
response: response,
|
|
||||||
error: error
|
|
||||||
) { wasTokenRefreshed in
|
|
||||||
|
|
||||||
if wasTokenRefreshed {
|
|
||||||
// If the token was refreshed, it's because it was a 401 error, so we refreshed the token, and we are going to retry the request by calling self.execute()
|
|
||||||
self.execute(apiResponseQueue, completion)
|
|
||||||
} else {
|
|
||||||
// If the token was not refreshed, it's because it was not a 401 error, so we send the response to the completion block
|
|
||||||
completion(result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// If it's an unknown error, we send the response to the completion block
|
|
||||||
completion(result)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return requestTask
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class BearerTokenHandler {
|
|
||||||
private static var bearerToken: String? = nil
|
|
||||||
|
|
||||||
static func refreshTokenIfDoesntExist(completionHandler: @escaping () -> Void) {
|
|
||||||
if bearerToken != nil {
|
|
||||||
completionHandler()
|
|
||||||
} else {
|
|
||||||
startRefreshingToken {
|
|
||||||
completionHandler()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static func refreshTokenIfUnauthorizedRequestResponse(data: Data?, response: URLResponse?, error: Error?, completionHandler: @escaping (Bool) -> Void) {
|
|
||||||
if let response = response as? HTTPURLResponse, response.statusCode == 401 {
|
|
||||||
startRefreshingToken {
|
|
||||||
completionHandler(true)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
completionHandler(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static func startRefreshingToken(completionHandler: @escaping () -> Void) {
|
|
||||||
// Get a bearer token
|
|
||||||
let dummyBearerToken = "..."
|
|
||||||
|
|
||||||
bearerToken = dummyBearerToken
|
|
||||||
PetstoreClientAPI.customHeaders["Authorization"] = "Bearer \(dummyBearerToken)"
|
|
||||||
|
|
||||||
completionHandler()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Then you assign the `BearerRequestBuilderFactory` to the property `requestBuilderFactory`.
|
|
||||||
|
|
||||||
`PetstoreClientAPI.requestBuilderFactory = BearerRequestBuilderFactory()`
|
|
||||||
|
|
||||||
The name `PetstoreClientAPI.requestBuilderFactory` will change depending on your project name.
|
|
||||||
|
|
||||||
Here is a working sample that put's together all of this.
|
|
||||||
[AppDelegate.swift](https://github.com/OpenAPITools/openapi-generator/blob/master/samples/client/petstore/swift5/urlsessionLibrary/SwaggerClientTests/SwaggerClient/AppDelegate.swift)
|
|
||||||
[BearerDecodableRequestBuilder.swift](https://github.com/OpenAPITools/openapi-generator/blob/master/samples/client/petstore/swift5/urlsessionLibrary/SwaggerClientTests/SwaggerClient/BearerDecodableRequestBuilder.swift)
|
|
||||||
|
|
||||||
## Author
|
## Author
|
||||||
|
|
||||||
|
@ -40,162 +40,13 @@ Class | Method | HTTP request | Description
|
|||||||
Endpoints do not require authorization.
|
Endpoints do not require authorization.
|
||||||
|
|
||||||
|
|
||||||
|
# How do I migrate from the Swift 5 generator to the swift 6 generator?
|
||||||
|
|
||||||
|
https://openapi-generator.tech/docs/faq-generators#how-do-i-migrate-from-the-swift-5-generator-to-the-swift-6-generator
|
||||||
|
|
||||||
### How do I implement bearer token authentication with URLSession on the Swift 5 API client?
|
### How do I implement bearer token authentication with URLSession on the Swift 5 API client?
|
||||||
|
|
||||||
First you subclass RequestBuilderFactory
|
https://openapi-generator.tech/docs/faq-generators#how-do-i-implement-bearer-token-authentication-with-urlsession-on-the-swift-5-api-client
|
||||||
```
|
|
||||||
class BearerRequestBuilderFactory: RequestBuilderFactory {
|
|
||||||
func getNonDecodableBuilder<T>() -> RequestBuilder<T>.Type {
|
|
||||||
BearerRequestBuilder<T>.self
|
|
||||||
}
|
|
||||||
|
|
||||||
func getBuilder<T: Decodable>() -> RequestBuilder<T>.Type {
|
|
||||||
BearerDecodableRequestBuilder<T>.self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Then you subclass URLSessionRequestBuilder and URLSessionDecodableRequestBuilder
|
|
||||||
```
|
|
||||||
class BearerRequestBuilder<T>: URLSessionRequestBuilder<T> {
|
|
||||||
@discardableResult
|
|
||||||
override func execute(_ apiResponseQueue: DispatchQueue = PetstoreClientAPI.apiResponseQueue, _ completion: @escaping (Result<Response<T>, ErrorResponse>) -> Void) -> RequestTask {
|
|
||||||
|
|
||||||
// Before making the request, we can validate if we have a bearer token to be able to make a request
|
|
||||||
BearerTokenHandler.refreshTokenIfDoesntExist {
|
|
||||||
|
|
||||||
// Here we make the request
|
|
||||||
super.execute(apiResponseQueue) { result in
|
|
||||||
|
|
||||||
switch result {
|
|
||||||
case .success:
|
|
||||||
// If we got a successful response, we send the response to the completion block
|
|
||||||
completion(result)
|
|
||||||
|
|
||||||
case let .failure(error):
|
|
||||||
|
|
||||||
// If we got a failure response, we will analyse the error to see what we should do with it
|
|
||||||
if case let ErrorResponse.error(_, data, response, error) = error {
|
|
||||||
|
|
||||||
// If the error is an ErrorResponse.error() we will analyse it to see if it's a 401, and if it's a 401, we will refresh the token and retry the request
|
|
||||||
BearerTokenHandler.refreshTokenIfUnauthorizedRequestResponse(
|
|
||||||
data: data,
|
|
||||||
response: response,
|
|
||||||
error: error
|
|
||||||
) { wasTokenRefreshed in
|
|
||||||
|
|
||||||
if wasTokenRefreshed {
|
|
||||||
// If the token was refreshed, it's because it was a 401 error, so we refreshed the token, and we are going to retry the request by calling self.execute()
|
|
||||||
self.execute(apiResponseQueue, completion)
|
|
||||||
} else {
|
|
||||||
// If the token was not refreshed, it's because it was not a 401 error, so we send the response to the completion block
|
|
||||||
completion(result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// If it's an unknown error, we send the response to the completion block
|
|
||||||
completion(result)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return requestTask
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class BearerDecodableRequestBuilder<T: Decodable>: URLSessionDecodableRequestBuilder<T> {
|
|
||||||
@discardableResult
|
|
||||||
override func execute(_ apiResponseQueue: DispatchQueue = PetstoreClientAPI.apiResponseQueue, _ completion: @escaping (Result<Response<T>, ErrorResponse>) -> Void) -> RequestTask {
|
|
||||||
// Before making the request, we can validate if we have a bearer token to be able to make a request
|
|
||||||
BearerTokenHandler.refreshTokenIfDoesntExist {
|
|
||||||
|
|
||||||
// Here we make the request
|
|
||||||
super.execute(apiResponseQueue) { result in
|
|
||||||
|
|
||||||
switch result {
|
|
||||||
case .success:
|
|
||||||
// If we got a successful response, we send the response to the completion block
|
|
||||||
completion(result)
|
|
||||||
|
|
||||||
case let .failure(error):
|
|
||||||
|
|
||||||
// If we got a failure response, we will analyse the error to see what we should do with it
|
|
||||||
if case let ErrorResponse.error(_, data, response, error) = error {
|
|
||||||
|
|
||||||
// If the error is an ErrorResponse.error() we will analyse it to see if it's a 401, and if it's a 401, we will refresh the token and retry the request
|
|
||||||
BearerTokenHandler.refreshTokenIfUnauthorizedRequestResponse(
|
|
||||||
data: data,
|
|
||||||
response: response,
|
|
||||||
error: error
|
|
||||||
) { wasTokenRefreshed in
|
|
||||||
|
|
||||||
if wasTokenRefreshed {
|
|
||||||
// If the token was refreshed, it's because it was a 401 error, so we refreshed the token, and we are going to retry the request by calling self.execute()
|
|
||||||
self.execute(apiResponseQueue, completion)
|
|
||||||
} else {
|
|
||||||
// If the token was not refreshed, it's because it was not a 401 error, so we send the response to the completion block
|
|
||||||
completion(result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// If it's an unknown error, we send the response to the completion block
|
|
||||||
completion(result)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return requestTask
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class BearerTokenHandler {
|
|
||||||
private static var bearerToken: String? = nil
|
|
||||||
|
|
||||||
static func refreshTokenIfDoesntExist(completionHandler: @escaping () -> Void) {
|
|
||||||
if bearerToken != nil {
|
|
||||||
completionHandler()
|
|
||||||
} else {
|
|
||||||
startRefreshingToken {
|
|
||||||
completionHandler()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static func refreshTokenIfUnauthorizedRequestResponse(data: Data?, response: URLResponse?, error: Error?, completionHandler: @escaping (Bool) -> Void) {
|
|
||||||
if let response = response as? HTTPURLResponse, response.statusCode == 401 {
|
|
||||||
startRefreshingToken {
|
|
||||||
completionHandler(true)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
completionHandler(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static func startRefreshingToken(completionHandler: @escaping () -> Void) {
|
|
||||||
// Get a bearer token
|
|
||||||
let dummyBearerToken = "..."
|
|
||||||
|
|
||||||
bearerToken = dummyBearerToken
|
|
||||||
PetstoreClientAPI.customHeaders["Authorization"] = "Bearer \(dummyBearerToken)"
|
|
||||||
|
|
||||||
completionHandler()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Then you assign the `BearerRequestBuilderFactory` to the property `requestBuilderFactory`.
|
|
||||||
|
|
||||||
`PetstoreClientAPI.requestBuilderFactory = BearerRequestBuilderFactory()`
|
|
||||||
|
|
||||||
The name `PetstoreClientAPI.requestBuilderFactory` will change depending on your project name.
|
|
||||||
|
|
||||||
Here is a working sample that put's together all of this.
|
|
||||||
[AppDelegate.swift](https://github.com/OpenAPITools/openapi-generator/blob/master/samples/client/petstore/swift5/urlsessionLibrary/SwaggerClientTests/SwaggerClient/AppDelegate.swift)
|
|
||||||
[BearerDecodableRequestBuilder.swift](https://github.com/OpenAPITools/openapi-generator/blob/master/samples/client/petstore/swift5/urlsessionLibrary/SwaggerClientTests/SwaggerClient/BearerDecodableRequestBuilder.swift)
|
|
||||||
|
|
||||||
## Author
|
## Author
|
||||||
|
|
||||||
|
@ -147,6 +147,9 @@ Authentication schemes defined for the API:
|
|||||||
- **Type**: HTTP basic authentication
|
- **Type**: HTTP basic authentication
|
||||||
|
|
||||||
|
|
||||||
|
# How do I migrate from the Swift 5 generator to the swift 6 generator?
|
||||||
|
|
||||||
|
https://openapi-generator.tech/docs/faq-generators#how-do-i-migrate-from-the-swift-5-generator-to-the-swift-6-generator
|
||||||
|
|
||||||
## Author
|
## Author
|
||||||
|
|
||||||
|
@ -140,55 +140,13 @@ Authentication schemes defined for the API:
|
|||||||
- **Type**: HTTP basic authentication
|
- **Type**: HTTP basic authentication
|
||||||
|
|
||||||
|
|
||||||
|
# How do I migrate from the Swift 5 generator to the swift 6 generator?
|
||||||
|
|
||||||
|
https://openapi-generator.tech/docs/faq-generators#how-do-i-migrate-from-the-swift-5-generator-to-the-swift-6-generator
|
||||||
|
|
||||||
### How do I implement bearer token authentication with Alamofire on the Swift 6 API client?
|
### How do I implement bearer token authentication with Alamofire on the Swift 6 API client?
|
||||||
|
|
||||||
First implement the `Alamofire` `RequestInterceptor` protocol.
|
https://openapi-generator.tech/docs/faq-generators#how-do-i-implement-bearer-token-authentication-with-alamofire-on-the-swift-6-api-client
|
||||||
```
|
|
||||||
class BearerTokenHandler: RequestInterceptor, @unchecked Sendable {
|
|
||||||
private var bearerToken: String? = nil
|
|
||||||
|
|
||||||
func adapt(_ urlRequest: URLRequest, for session: Session, completion: @escaping (Result<URLRequest, Error>) -> Void) {
|
|
||||||
if let bearerToken = bearerToken {
|
|
||||||
var urlRequest = urlRequest
|
|
||||||
urlRequest.setValue("Bearer \(bearerToken)", forHTTPHeaderField: "Authorization")
|
|
||||||
|
|
||||||
completion(.success(urlRequest))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
completion(.success(urlRequest))
|
|
||||||
}
|
|
||||||
|
|
||||||
func retry(_ request: Request, for session: Session, dueTo error: Error, completion: @escaping (RetryResult) -> Void) {
|
|
||||||
if let response = request.task?.response as? HTTPURLResponse, response.statusCode == 401 {
|
|
||||||
startRefreshingToken { isTokenRefreshed in
|
|
||||||
completion(.retry)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
completion(.doNotRetryWithError(error))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private func startRefreshingToken(completionHandler: @escaping (Bool) -> Void) {
|
|
||||||
// Get a bearer token
|
|
||||||
let dummyBearerToken = "..."
|
|
||||||
|
|
||||||
bearerToken = dummyBearerToken
|
|
||||||
OpenAPIClient.shared.customHeaders["Authorization"] = "Bearer \(dummyBearerToken)"
|
|
||||||
|
|
||||||
completionHandler(true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
Then you assign the `BearerTokenHandler` to the property `OpenAPIClient.shared.interceptor`.
|
|
||||||
|
|
||||||
`OpenAPIClient.shared.interceptor = BearerTokenHandler()`
|
|
||||||
|
|
||||||
Here is a working sample that put's together all of this.
|
|
||||||
[AppDelegate.swift](https://github.com/OpenAPITools/openapi-generator/blob/master/samples/client/petstore/swift6/alamofireLibrary/SwaggerClientTests/SwaggerClient/AppDelegate.swift)
|
|
||||||
[BearerTokenHandler.swift](https://github.com/OpenAPITools/openapi-generator/blob/master/samples/client/petstore/swift6/alamofireLibrary/SwaggerClientTests/SwaggerClient/BearerTokenHandler.swift)
|
|
||||||
|
|
||||||
## Author
|
## Author
|
||||||
|
|
||||||
|
@ -138,55 +138,13 @@ Authentication schemes defined for the API:
|
|||||||
- **Type**: HTTP basic authentication
|
- **Type**: HTTP basic authentication
|
||||||
|
|
||||||
|
|
||||||
|
# How do I migrate from the Swift 5 generator to the swift 6 generator?
|
||||||
|
|
||||||
|
https://openapi-generator.tech/docs/faq-generators#how-do-i-migrate-from-the-swift-5-generator-to-the-swift-6-generator
|
||||||
|
|
||||||
### How do I implement bearer token authentication with Alamofire on the Swift 6 API client?
|
### How do I implement bearer token authentication with Alamofire on the Swift 6 API client?
|
||||||
|
|
||||||
First implement the `Alamofire` `RequestInterceptor` protocol.
|
https://openapi-generator.tech/docs/faq-generators#how-do-i-implement-bearer-token-authentication-with-alamofire-on-the-swift-6-api-client
|
||||||
```
|
|
||||||
class BearerTokenHandler: RequestInterceptor, @unchecked Sendable {
|
|
||||||
private var bearerToken: String? = nil
|
|
||||||
|
|
||||||
func adapt(_ urlRequest: URLRequest, for session: Session, completion: @escaping (Result<URLRequest, Error>) -> Void) {
|
|
||||||
if let bearerToken = bearerToken {
|
|
||||||
var urlRequest = urlRequest
|
|
||||||
urlRequest.setValue("Bearer \(bearerToken)", forHTTPHeaderField: "Authorization")
|
|
||||||
|
|
||||||
completion(.success(urlRequest))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
completion(.success(urlRequest))
|
|
||||||
}
|
|
||||||
|
|
||||||
func retry(_ request: Request, for session: Session, dueTo error: Error, completion: @escaping (RetryResult) -> Void) {
|
|
||||||
if let response = request.task?.response as? HTTPURLResponse, response.statusCode == 401 {
|
|
||||||
startRefreshingToken { isTokenRefreshed in
|
|
||||||
completion(.retry)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
completion(.doNotRetryWithError(error))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private func startRefreshingToken(completionHandler: @escaping (Bool) -> Void) {
|
|
||||||
// Get a bearer token
|
|
||||||
let dummyBearerToken = "..."
|
|
||||||
|
|
||||||
bearerToken = dummyBearerToken
|
|
||||||
OpenAPIClient.shared.customHeaders["Authorization"] = "Bearer \(dummyBearerToken)"
|
|
||||||
|
|
||||||
completionHandler(true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
Then you assign the `BearerTokenHandler` to the property `OpenAPIClient.shared.interceptor`.
|
|
||||||
|
|
||||||
`OpenAPIClient.shared.interceptor = BearerTokenHandler()`
|
|
||||||
|
|
||||||
Here is a working sample that put's together all of this.
|
|
||||||
[AppDelegate.swift](https://github.com/OpenAPITools/openapi-generator/blob/master/samples/client/petstore/swift6/alamofireLibrary/SwaggerClientTests/SwaggerClient/AppDelegate.swift)
|
|
||||||
[BearerTokenHandler.swift](https://github.com/OpenAPITools/openapi-generator/blob/master/samples/client/petstore/swift6/alamofireLibrary/SwaggerClientTests/SwaggerClient/BearerTokenHandler.swift)
|
|
||||||
|
|
||||||
## Author
|
## Author
|
||||||
|
|
||||||
|
@ -140,88 +140,13 @@ Authentication schemes defined for the API:
|
|||||||
- **Type**: HTTP basic authentication
|
- **Type**: HTTP basic authentication
|
||||||
|
|
||||||
|
|
||||||
|
# How do I migrate from the Swift 5 generator to the swift 6 generator?
|
||||||
|
|
||||||
|
https://openapi-generator.tech/docs/faq-generators#how-do-i-migrate-from-the-swift-5-generator-to-the-swift-6-generator
|
||||||
|
|
||||||
### How do I implement bearer token authentication with URLSession on the Swift 6 API client?
|
### How do I implement bearer token authentication with URLSession on the Swift 6 API client?
|
||||||
|
|
||||||
First you implement the `OpenAPIInterceptor` protocol.
|
https://openapi-generator.tech/docs/faq-generators#how-do-i-implement-bearer-token-authentication-with-urlsession-on-the-swift-6-api-client
|
||||||
```
|
|
||||||
public class BearerOpenAPIInterceptor: OpenAPIInterceptor {
|
|
||||||
public init() {}
|
|
||||||
|
|
||||||
public func intercept(urlRequest: URLRequest, urlSession: URLSessionProtocol, openAPIClient: OpenAPIClient, completion: @escaping (Result<URLRequest, any Error>) -> Void) {
|
|
||||||
refreshTokenIfDoesntExist { token in
|
|
||||||
|
|
||||||
// Change the current url request
|
|
||||||
var newUrlRequest = urlRequest
|
|
||||||
newUrlRequest.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
|
|
||||||
|
|
||||||
// Change the global headers
|
|
||||||
openAPIClient.customHeaders["Authorization"] = "Bearer \(token)"
|
|
||||||
|
|
||||||
completion(.success(newUrlRequest))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public func retry(urlRequest: URLRequest, urlSession: URLSessionProtocol, openAPIClient: OpenAPIClient, data: Data?, response: URLResponse, error: Error, completion: @escaping (OpenAPIInterceptorRetry) -> Void) {
|
|
||||||
// We will analyse the response to see if it's a 401, and if it's a 401, we will refresh the token and retry the request
|
|
||||||
refreshTokenIfUnauthorizedRequestResponse(
|
|
||||||
data: data,
|
|
||||||
response: response,
|
|
||||||
error: error
|
|
||||||
) { (wasTokenRefreshed, newToken) in
|
|
||||||
|
|
||||||
if wasTokenRefreshed, let newToken = newToken {
|
|
||||||
|
|
||||||
// Change the global headers
|
|
||||||
openAPIClient.customHeaders["Authorization"] = "Bearer \(newToken)"
|
|
||||||
|
|
||||||
completion(.retry)
|
|
||||||
} else {
|
|
||||||
// If the token was not refreshed, it's because it was not a 401 error, so we send the response to the completion block
|
|
||||||
completion(.dontRetry)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private var bearerToken: String? = nil
|
|
||||||
|
|
||||||
func refreshTokenIfDoesntExist(completionHandler: @escaping (String) -> Void) {
|
|
||||||
if let bearerToken = bearerToken {
|
|
||||||
completionHandler(bearerToken)
|
|
||||||
} else {
|
|
||||||
startRefreshingToken { token in
|
|
||||||
completionHandler(token)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func refreshTokenIfUnauthorizedRequestResponse(data: Data?, response: URLResponse, error: Error, completionHandler: @escaping (Bool, String?) -> Void) {
|
|
||||||
if let response = response as? HTTPURLResponse, response.statusCode == 401 {
|
|
||||||
startRefreshingToken { token in
|
|
||||||
completionHandler(true, token)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
completionHandler(false, nil)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private func startRefreshingToken(completionHandler: @escaping (String) -> Void) {
|
|
||||||
// Get a bearer token
|
|
||||||
let dummyBearerToken = "..."
|
|
||||||
|
|
||||||
bearerToken = dummyBearerToken
|
|
||||||
|
|
||||||
completionHandler(dummyBearerToken)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Then you assign the `BearerOpenAPIInterceptor` to the property `OpenAPIClient.shared.interceptor`.
|
|
||||||
|
|
||||||
`OpenAPIClient.shared.interceptor = BearerOpenAPIInterceptor()`
|
|
||||||
|
|
||||||
Here is a working sample that put's together all of this.
|
|
||||||
[AppDelegate.swift](https://github.com/OpenAPITools/openapi-generator/blob/master/samples/client/petstore/swift6/urlsessionLibrary/SwaggerClientTests/SwaggerClient/AppDelegate.swift)
|
|
||||||
[BearerTokenHandler.swift](https://github.com/OpenAPITools/openapi-generator/blob/master/samples/client/petstore/swift5/urlsessionLibrary/SwaggerClientTests/SwaggerClient/BearerDecodableRequestBuilder.swift)
|
|
||||||
|
|
||||||
## Author
|
## Author
|
||||||
|
|
||||||
|
@ -140,88 +140,13 @@ Authentication schemes defined for the API:
|
|||||||
- **Type**: HTTP basic authentication
|
- **Type**: HTTP basic authentication
|
||||||
|
|
||||||
|
|
||||||
|
# How do I migrate from the Swift 5 generator to the swift 6 generator?
|
||||||
|
|
||||||
|
https://openapi-generator.tech/docs/faq-generators#how-do-i-migrate-from-the-swift-5-generator-to-the-swift-6-generator
|
||||||
|
|
||||||
### How do I implement bearer token authentication with URLSession on the Swift 6 API client?
|
### How do I implement bearer token authentication with URLSession on the Swift 6 API client?
|
||||||
|
|
||||||
First you implement the `OpenAPIInterceptor` protocol.
|
https://openapi-generator.tech/docs/faq-generators#how-do-i-implement-bearer-token-authentication-with-urlsession-on-the-swift-6-api-client
|
||||||
```
|
|
||||||
public class BearerOpenAPIInterceptor: OpenAPIInterceptor {
|
|
||||||
public init() {}
|
|
||||||
|
|
||||||
public func intercept(urlRequest: URLRequest, urlSession: URLSessionProtocol, openAPIClient: OpenAPIClient, completion: @escaping (Result<URLRequest, any Error>) -> Void) {
|
|
||||||
refreshTokenIfDoesntExist { token in
|
|
||||||
|
|
||||||
// Change the current url request
|
|
||||||
var newUrlRequest = urlRequest
|
|
||||||
newUrlRequest.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
|
|
||||||
|
|
||||||
// Change the global headers
|
|
||||||
openAPIClient.customHeaders["Authorization"] = "Bearer \(token)"
|
|
||||||
|
|
||||||
completion(.success(newUrlRequest))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public func retry(urlRequest: URLRequest, urlSession: URLSessionProtocol, openAPIClient: OpenAPIClient, data: Data?, response: URLResponse, error: Error, completion: @escaping (OpenAPIInterceptorRetry) -> Void) {
|
|
||||||
// We will analyse the response to see if it's a 401, and if it's a 401, we will refresh the token and retry the request
|
|
||||||
refreshTokenIfUnauthorizedRequestResponse(
|
|
||||||
data: data,
|
|
||||||
response: response,
|
|
||||||
error: error
|
|
||||||
) { (wasTokenRefreshed, newToken) in
|
|
||||||
|
|
||||||
if wasTokenRefreshed, let newToken = newToken {
|
|
||||||
|
|
||||||
// Change the global headers
|
|
||||||
openAPIClient.customHeaders["Authorization"] = "Bearer \(newToken)"
|
|
||||||
|
|
||||||
completion(.retry)
|
|
||||||
} else {
|
|
||||||
// If the token was not refreshed, it's because it was not a 401 error, so we send the response to the completion block
|
|
||||||
completion(.dontRetry)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private var bearerToken: String? = nil
|
|
||||||
|
|
||||||
func refreshTokenIfDoesntExist(completionHandler: @escaping (String) -> Void) {
|
|
||||||
if let bearerToken = bearerToken {
|
|
||||||
completionHandler(bearerToken)
|
|
||||||
} else {
|
|
||||||
startRefreshingToken { token in
|
|
||||||
completionHandler(token)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func refreshTokenIfUnauthorizedRequestResponse(data: Data?, response: URLResponse, error: Error, completionHandler: @escaping (Bool, String?) -> Void) {
|
|
||||||
if let response = response as? HTTPURLResponse, response.statusCode == 401 {
|
|
||||||
startRefreshingToken { token in
|
|
||||||
completionHandler(true, token)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
completionHandler(false, nil)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private func startRefreshingToken(completionHandler: @escaping (String) -> Void) {
|
|
||||||
// Get a bearer token
|
|
||||||
let dummyBearerToken = "..."
|
|
||||||
|
|
||||||
bearerToken = dummyBearerToken
|
|
||||||
|
|
||||||
completionHandler(dummyBearerToken)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Then you assign the `BearerOpenAPIInterceptor` to the property `OpenAPIClient.shared.interceptor`.
|
|
||||||
|
|
||||||
`OpenAPIClient.shared.interceptor = BearerOpenAPIInterceptor()`
|
|
||||||
|
|
||||||
Here is a working sample that put's together all of this.
|
|
||||||
[AppDelegate.swift](https://github.com/OpenAPITools/openapi-generator/blob/master/samples/client/petstore/swift6/urlsessionLibrary/SwaggerClientTests/SwaggerClient/AppDelegate.swift)
|
|
||||||
[BearerTokenHandler.swift](https://github.com/OpenAPITools/openapi-generator/blob/master/samples/client/petstore/swift5/urlsessionLibrary/SwaggerClientTests/SwaggerClient/BearerDecodableRequestBuilder.swift)
|
|
||||||
|
|
||||||
## Author
|
## Author
|
||||||
|
|
||||||
|
@ -140,88 +140,13 @@ Authentication schemes defined for the API:
|
|||||||
- **Type**: HTTP basic authentication
|
- **Type**: HTTP basic authentication
|
||||||
|
|
||||||
|
|
||||||
|
# How do I migrate from the Swift 5 generator to the swift 6 generator?
|
||||||
|
|
||||||
|
https://openapi-generator.tech/docs/faq-generators#how-do-i-migrate-from-the-swift-5-generator-to-the-swift-6-generator
|
||||||
|
|
||||||
### How do I implement bearer token authentication with URLSession on the Swift 6 API client?
|
### How do I implement bearer token authentication with URLSession on the Swift 6 API client?
|
||||||
|
|
||||||
First you implement the `OpenAPIInterceptor` protocol.
|
https://openapi-generator.tech/docs/faq-generators#how-do-i-implement-bearer-token-authentication-with-urlsession-on-the-swift-6-api-client
|
||||||
```
|
|
||||||
public class BearerOpenAPIInterceptor: OpenAPIInterceptor {
|
|
||||||
public init() {}
|
|
||||||
|
|
||||||
public func intercept(urlRequest: URLRequest, urlSession: URLSessionProtocol, openAPIClient: OpenAPIClient, completion: @escaping (Result<URLRequest, any Error>) -> Void) {
|
|
||||||
refreshTokenIfDoesntExist { token in
|
|
||||||
|
|
||||||
// Change the current url request
|
|
||||||
var newUrlRequest = urlRequest
|
|
||||||
newUrlRequest.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
|
|
||||||
|
|
||||||
// Change the global headers
|
|
||||||
openAPIClient.customHeaders["Authorization"] = "Bearer \(token)"
|
|
||||||
|
|
||||||
completion(.success(newUrlRequest))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public func retry(urlRequest: URLRequest, urlSession: URLSessionProtocol, openAPIClient: OpenAPIClient, data: Data?, response: URLResponse, error: Error, completion: @escaping (OpenAPIInterceptorRetry) -> Void) {
|
|
||||||
// We will analyse the response to see if it's a 401, and if it's a 401, we will refresh the token and retry the request
|
|
||||||
refreshTokenIfUnauthorizedRequestResponse(
|
|
||||||
data: data,
|
|
||||||
response: response,
|
|
||||||
error: error
|
|
||||||
) { (wasTokenRefreshed, newToken) in
|
|
||||||
|
|
||||||
if wasTokenRefreshed, let newToken = newToken {
|
|
||||||
|
|
||||||
// Change the global headers
|
|
||||||
openAPIClient.customHeaders["Authorization"] = "Bearer \(newToken)"
|
|
||||||
|
|
||||||
completion(.retry)
|
|
||||||
} else {
|
|
||||||
// If the token was not refreshed, it's because it was not a 401 error, so we send the response to the completion block
|
|
||||||
completion(.dontRetry)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private var bearerToken: String? = nil
|
|
||||||
|
|
||||||
func refreshTokenIfDoesntExist(completionHandler: @escaping (String) -> Void) {
|
|
||||||
if let bearerToken = bearerToken {
|
|
||||||
completionHandler(bearerToken)
|
|
||||||
} else {
|
|
||||||
startRefreshingToken { token in
|
|
||||||
completionHandler(token)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func refreshTokenIfUnauthorizedRequestResponse(data: Data?, response: URLResponse, error: Error, completionHandler: @escaping (Bool, String?) -> Void) {
|
|
||||||
if let response = response as? HTTPURLResponse, response.statusCode == 401 {
|
|
||||||
startRefreshingToken { token in
|
|
||||||
completionHandler(true, token)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
completionHandler(false, nil)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private func startRefreshingToken(completionHandler: @escaping (String) -> Void) {
|
|
||||||
// Get a bearer token
|
|
||||||
let dummyBearerToken = "..."
|
|
||||||
|
|
||||||
bearerToken = dummyBearerToken
|
|
||||||
|
|
||||||
completionHandler(dummyBearerToken)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Then you assign the `BearerOpenAPIInterceptor` to the property `OpenAPIClient.shared.interceptor`.
|
|
||||||
|
|
||||||
`OpenAPIClient.shared.interceptor = BearerOpenAPIInterceptor()`
|
|
||||||
|
|
||||||
Here is a working sample that put's together all of this.
|
|
||||||
[AppDelegate.swift](https://github.com/OpenAPITools/openapi-generator/blob/master/samples/client/petstore/swift6/urlsessionLibrary/SwaggerClientTests/SwaggerClient/AppDelegate.swift)
|
|
||||||
[BearerTokenHandler.swift](https://github.com/OpenAPITools/openapi-generator/blob/master/samples/client/petstore/swift5/urlsessionLibrary/SwaggerClientTests/SwaggerClient/BearerDecodableRequestBuilder.swift)
|
|
||||||
|
|
||||||
## Author
|
## Author
|
||||||
|
|
||||||
|
@ -151,88 +151,13 @@ Authentication schemes defined for the API:
|
|||||||
- **Type**: HTTP basic authentication
|
- **Type**: HTTP basic authentication
|
||||||
|
|
||||||
|
|
||||||
|
# How do I migrate from the Swift 5 generator to the swift 6 generator?
|
||||||
|
|
||||||
|
https://openapi-generator.tech/docs/faq-generators#how-do-i-migrate-from-the-swift-5-generator-to-the-swift-6-generator
|
||||||
|
|
||||||
### How do I implement bearer token authentication with URLSession on the Swift 6 API client?
|
### How do I implement bearer token authentication with URLSession on the Swift 6 API client?
|
||||||
|
|
||||||
First you implement the `OpenAPIInterceptor` protocol.
|
https://openapi-generator.tech/docs/faq-generators#how-do-i-implement-bearer-token-authentication-with-urlsession-on-the-swift-6-api-client
|
||||||
```
|
|
||||||
public class BearerOpenAPIInterceptor: OpenAPIInterceptor {
|
|
||||||
public init() {}
|
|
||||||
|
|
||||||
public func intercept(urlRequest: URLRequest, urlSession: URLSessionProtocol, openAPIClient: OpenAPIClient, completion: @escaping (Result<URLRequest, any Error>) -> Void) {
|
|
||||||
refreshTokenIfDoesntExist { token in
|
|
||||||
|
|
||||||
// Change the current url request
|
|
||||||
var newUrlRequest = urlRequest
|
|
||||||
newUrlRequest.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
|
|
||||||
|
|
||||||
// Change the global headers
|
|
||||||
openAPIClient.customHeaders["Authorization"] = "Bearer \(token)"
|
|
||||||
|
|
||||||
completion(.success(newUrlRequest))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public func retry(urlRequest: URLRequest, urlSession: URLSessionProtocol, openAPIClient: OpenAPIClient, data: Data?, response: URLResponse, error: Error, completion: @escaping (OpenAPIInterceptorRetry) -> Void) {
|
|
||||||
// We will analyse the response to see if it's a 401, and if it's a 401, we will refresh the token and retry the request
|
|
||||||
refreshTokenIfUnauthorizedRequestResponse(
|
|
||||||
data: data,
|
|
||||||
response: response,
|
|
||||||
error: error
|
|
||||||
) { (wasTokenRefreshed, newToken) in
|
|
||||||
|
|
||||||
if wasTokenRefreshed, let newToken = newToken {
|
|
||||||
|
|
||||||
// Change the global headers
|
|
||||||
openAPIClient.customHeaders["Authorization"] = "Bearer \(newToken)"
|
|
||||||
|
|
||||||
completion(.retry)
|
|
||||||
} else {
|
|
||||||
// If the token was not refreshed, it's because it was not a 401 error, so we send the response to the completion block
|
|
||||||
completion(.dontRetry)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private var bearerToken: String? = nil
|
|
||||||
|
|
||||||
func refreshTokenIfDoesntExist(completionHandler: @escaping (String) -> Void) {
|
|
||||||
if let bearerToken = bearerToken {
|
|
||||||
completionHandler(bearerToken)
|
|
||||||
} else {
|
|
||||||
startRefreshingToken { token in
|
|
||||||
completionHandler(token)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func refreshTokenIfUnauthorizedRequestResponse(data: Data?, response: URLResponse, error: Error, completionHandler: @escaping (Bool, String?) -> Void) {
|
|
||||||
if let response = response as? HTTPURLResponse, response.statusCode == 401 {
|
|
||||||
startRefreshingToken { token in
|
|
||||||
completionHandler(true, token)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
completionHandler(false, nil)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private func startRefreshingToken(completionHandler: @escaping (String) -> Void) {
|
|
||||||
// Get a bearer token
|
|
||||||
let dummyBearerToken = "..."
|
|
||||||
|
|
||||||
bearerToken = dummyBearerToken
|
|
||||||
|
|
||||||
completionHandler(dummyBearerToken)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Then you assign the `BearerOpenAPIInterceptor` to the property `OpenAPIClient.shared.interceptor`.
|
|
||||||
|
|
||||||
`OpenAPIClient.shared.interceptor = BearerOpenAPIInterceptor()`
|
|
||||||
|
|
||||||
Here is a working sample that put's together all of this.
|
|
||||||
[AppDelegate.swift](https://github.com/OpenAPITools/openapi-generator/blob/master/samples/client/petstore/swift6/urlsessionLibrary/SwaggerClientTests/SwaggerClient/AppDelegate.swift)
|
|
||||||
[BearerTokenHandler.swift](https://github.com/OpenAPITools/openapi-generator/blob/master/samples/client/petstore/swift5/urlsessionLibrary/SwaggerClientTests/SwaggerClient/BearerDecodableRequestBuilder.swift)
|
|
||||||
|
|
||||||
## Author
|
## Author
|
||||||
|
|
||||||
|
@ -140,88 +140,13 @@ Authentication schemes defined for the API:
|
|||||||
- **Type**: HTTP basic authentication
|
- **Type**: HTTP basic authentication
|
||||||
|
|
||||||
|
|
||||||
|
# How do I migrate from the Swift 5 generator to the swift 6 generator?
|
||||||
|
|
||||||
|
https://openapi-generator.tech/docs/faq-generators#how-do-i-migrate-from-the-swift-5-generator-to-the-swift-6-generator
|
||||||
|
|
||||||
### How do I implement bearer token authentication with URLSession on the Swift 6 API client?
|
### How do I implement bearer token authentication with URLSession on the Swift 6 API client?
|
||||||
|
|
||||||
First you implement the `OpenAPIInterceptor` protocol.
|
https://openapi-generator.tech/docs/faq-generators#how-do-i-implement-bearer-token-authentication-with-urlsession-on-the-swift-6-api-client
|
||||||
```
|
|
||||||
public class BearerOpenAPIInterceptor: OpenAPIInterceptor {
|
|
||||||
public init() {}
|
|
||||||
|
|
||||||
public func intercept(urlRequest: URLRequest, urlSession: URLSessionProtocol, openAPIClient: OpenAPIClient, completion: @escaping (Result<URLRequest, any Error>) -> Void) {
|
|
||||||
refreshTokenIfDoesntExist { token in
|
|
||||||
|
|
||||||
// Change the current url request
|
|
||||||
var newUrlRequest = urlRequest
|
|
||||||
newUrlRequest.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
|
|
||||||
|
|
||||||
// Change the global headers
|
|
||||||
openAPIClient.customHeaders["Authorization"] = "Bearer \(token)"
|
|
||||||
|
|
||||||
completion(.success(newUrlRequest))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public func retry(urlRequest: URLRequest, urlSession: URLSessionProtocol, openAPIClient: OpenAPIClient, data: Data?, response: URLResponse, error: Error, completion: @escaping (OpenAPIInterceptorRetry) -> Void) {
|
|
||||||
// We will analyse the response to see if it's a 401, and if it's a 401, we will refresh the token and retry the request
|
|
||||||
refreshTokenIfUnauthorizedRequestResponse(
|
|
||||||
data: data,
|
|
||||||
response: response,
|
|
||||||
error: error
|
|
||||||
) { (wasTokenRefreshed, newToken) in
|
|
||||||
|
|
||||||
if wasTokenRefreshed, let newToken = newToken {
|
|
||||||
|
|
||||||
// Change the global headers
|
|
||||||
openAPIClient.customHeaders["Authorization"] = "Bearer \(newToken)"
|
|
||||||
|
|
||||||
completion(.retry)
|
|
||||||
} else {
|
|
||||||
// If the token was not refreshed, it's because it was not a 401 error, so we send the response to the completion block
|
|
||||||
completion(.dontRetry)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private var bearerToken: String? = nil
|
|
||||||
|
|
||||||
func refreshTokenIfDoesntExist(completionHandler: @escaping (String) -> Void) {
|
|
||||||
if let bearerToken = bearerToken {
|
|
||||||
completionHandler(bearerToken)
|
|
||||||
} else {
|
|
||||||
startRefreshingToken { token in
|
|
||||||
completionHandler(token)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func refreshTokenIfUnauthorizedRequestResponse(data: Data?, response: URLResponse, error: Error, completionHandler: @escaping (Bool, String?) -> Void) {
|
|
||||||
if let response = response as? HTTPURLResponse, response.statusCode == 401 {
|
|
||||||
startRefreshingToken { token in
|
|
||||||
completionHandler(true, token)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
completionHandler(false, nil)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private func startRefreshingToken(completionHandler: @escaping (String) -> Void) {
|
|
||||||
// Get a bearer token
|
|
||||||
let dummyBearerToken = "..."
|
|
||||||
|
|
||||||
bearerToken = dummyBearerToken
|
|
||||||
|
|
||||||
completionHandler(dummyBearerToken)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Then you assign the `BearerOpenAPIInterceptor` to the property `OpenAPIClient.shared.interceptor`.
|
|
||||||
|
|
||||||
`OpenAPIClient.shared.interceptor = BearerOpenAPIInterceptor()`
|
|
||||||
|
|
||||||
Here is a working sample that put's together all of this.
|
|
||||||
[AppDelegate.swift](https://github.com/OpenAPITools/openapi-generator/blob/master/samples/client/petstore/swift6/urlsessionLibrary/SwaggerClientTests/SwaggerClient/AppDelegate.swift)
|
|
||||||
[BearerTokenHandler.swift](https://github.com/OpenAPITools/openapi-generator/blob/master/samples/client/petstore/swift5/urlsessionLibrary/SwaggerClientTests/SwaggerClient/BearerDecodableRequestBuilder.swift)
|
|
||||||
|
|
||||||
## Author
|
## Author
|
||||||
|
|
||||||
|
@ -42,88 +42,13 @@ Class | Method | HTTP request | Description
|
|||||||
Endpoints do not require authorization.
|
Endpoints do not require authorization.
|
||||||
|
|
||||||
|
|
||||||
|
# How do I migrate from the Swift 5 generator to the swift 6 generator?
|
||||||
|
|
||||||
|
https://openapi-generator.tech/docs/faq-generators#how-do-i-migrate-from-the-swift-5-generator-to-the-swift-6-generator
|
||||||
|
|
||||||
### How do I implement bearer token authentication with URLSession on the Swift 6 API client?
|
### How do I implement bearer token authentication with URLSession on the Swift 6 API client?
|
||||||
|
|
||||||
First you implement the `OpenAPIInterceptor` protocol.
|
https://openapi-generator.tech/docs/faq-generators#how-do-i-implement-bearer-token-authentication-with-urlsession-on-the-swift-6-api-client
|
||||||
```
|
|
||||||
public class BearerOpenAPIInterceptor: OpenAPIInterceptor {
|
|
||||||
public init() {}
|
|
||||||
|
|
||||||
public func intercept(urlRequest: URLRequest, urlSession: URLSessionProtocol, openAPIClient: OpenAPIClient, completion: @escaping (Result<URLRequest, any Error>) -> Void) {
|
|
||||||
refreshTokenIfDoesntExist { token in
|
|
||||||
|
|
||||||
// Change the current url request
|
|
||||||
var newUrlRequest = urlRequest
|
|
||||||
newUrlRequest.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
|
|
||||||
|
|
||||||
// Change the global headers
|
|
||||||
openAPIClient.customHeaders["Authorization"] = "Bearer \(token)"
|
|
||||||
|
|
||||||
completion(.success(newUrlRequest))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public func retry(urlRequest: URLRequest, urlSession: URLSessionProtocol, openAPIClient: OpenAPIClient, data: Data?, response: URLResponse, error: Error, completion: @escaping (OpenAPIInterceptorRetry) -> Void) {
|
|
||||||
// We will analyse the response to see if it's a 401, and if it's a 401, we will refresh the token and retry the request
|
|
||||||
refreshTokenIfUnauthorizedRequestResponse(
|
|
||||||
data: data,
|
|
||||||
response: response,
|
|
||||||
error: error
|
|
||||||
) { (wasTokenRefreshed, newToken) in
|
|
||||||
|
|
||||||
if wasTokenRefreshed, let newToken = newToken {
|
|
||||||
|
|
||||||
// Change the global headers
|
|
||||||
openAPIClient.customHeaders["Authorization"] = "Bearer \(newToken)"
|
|
||||||
|
|
||||||
completion(.retry)
|
|
||||||
} else {
|
|
||||||
// If the token was not refreshed, it's because it was not a 401 error, so we send the response to the completion block
|
|
||||||
completion(.dontRetry)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private var bearerToken: String? = nil
|
|
||||||
|
|
||||||
func refreshTokenIfDoesntExist(completionHandler: @escaping (String) -> Void) {
|
|
||||||
if let bearerToken = bearerToken {
|
|
||||||
completionHandler(bearerToken)
|
|
||||||
} else {
|
|
||||||
startRefreshingToken { token in
|
|
||||||
completionHandler(token)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func refreshTokenIfUnauthorizedRequestResponse(data: Data?, response: URLResponse, error: Error, completionHandler: @escaping (Bool, String?) -> Void) {
|
|
||||||
if let response = response as? HTTPURLResponse, response.statusCode == 401 {
|
|
||||||
startRefreshingToken { token in
|
|
||||||
completionHandler(true, token)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
completionHandler(false, nil)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private func startRefreshingToken(completionHandler: @escaping (String) -> Void) {
|
|
||||||
// Get a bearer token
|
|
||||||
let dummyBearerToken = "..."
|
|
||||||
|
|
||||||
bearerToken = dummyBearerToken
|
|
||||||
|
|
||||||
completionHandler(dummyBearerToken)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Then you assign the `BearerOpenAPIInterceptor` to the property `OpenAPIClient.shared.interceptor`.
|
|
||||||
|
|
||||||
`OpenAPIClient.shared.interceptor = BearerOpenAPIInterceptor()`
|
|
||||||
|
|
||||||
Here is a working sample that put's together all of this.
|
|
||||||
[AppDelegate.swift](https://github.com/OpenAPITools/openapi-generator/blob/master/samples/client/petstore/swift6/urlsessionLibrary/SwaggerClientTests/SwaggerClient/AppDelegate.swift)
|
|
||||||
[BearerTokenHandler.swift](https://github.com/OpenAPITools/openapi-generator/blob/master/samples/client/petstore/swift5/urlsessionLibrary/SwaggerClientTests/SwaggerClient/BearerDecodableRequestBuilder.swift)
|
|
||||||
|
|
||||||
## Author
|
## Author
|
||||||
|
|
||||||
|
@ -140,88 +140,13 @@ Authentication schemes defined for the API:
|
|||||||
- **Type**: HTTP basic authentication
|
- **Type**: HTTP basic authentication
|
||||||
|
|
||||||
|
|
||||||
|
# How do I migrate from the Swift 5 generator to the swift 6 generator?
|
||||||
|
|
||||||
|
https://openapi-generator.tech/docs/faq-generators#how-do-i-migrate-from-the-swift-5-generator-to-the-swift-6-generator
|
||||||
|
|
||||||
### How do I implement bearer token authentication with URLSession on the Swift 6 API client?
|
### How do I implement bearer token authentication with URLSession on the Swift 6 API client?
|
||||||
|
|
||||||
First you implement the `OpenAPIInterceptor` protocol.
|
https://openapi-generator.tech/docs/faq-generators#how-do-i-implement-bearer-token-authentication-with-urlsession-on-the-swift-6-api-client
|
||||||
```
|
|
||||||
public class BearerOpenAPIInterceptor: OpenAPIInterceptor {
|
|
||||||
public init() {}
|
|
||||||
|
|
||||||
public func intercept(urlRequest: URLRequest, urlSession: URLSessionProtocol, openAPIClient: OpenAPIClient, completion: @escaping (Result<URLRequest, any Error>) -> Void) {
|
|
||||||
refreshTokenIfDoesntExist { token in
|
|
||||||
|
|
||||||
// Change the current url request
|
|
||||||
var newUrlRequest = urlRequest
|
|
||||||
newUrlRequest.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
|
|
||||||
|
|
||||||
// Change the global headers
|
|
||||||
openAPIClient.customHeaders["Authorization"] = "Bearer \(token)"
|
|
||||||
|
|
||||||
completion(.success(newUrlRequest))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public func retry(urlRequest: URLRequest, urlSession: URLSessionProtocol, openAPIClient: OpenAPIClient, data: Data?, response: URLResponse, error: Error, completion: @escaping (OpenAPIInterceptorRetry) -> Void) {
|
|
||||||
// We will analyse the response to see if it's a 401, and if it's a 401, we will refresh the token and retry the request
|
|
||||||
refreshTokenIfUnauthorizedRequestResponse(
|
|
||||||
data: data,
|
|
||||||
response: response,
|
|
||||||
error: error
|
|
||||||
) { (wasTokenRefreshed, newToken) in
|
|
||||||
|
|
||||||
if wasTokenRefreshed, let newToken = newToken {
|
|
||||||
|
|
||||||
// Change the global headers
|
|
||||||
openAPIClient.customHeaders["Authorization"] = "Bearer \(newToken)"
|
|
||||||
|
|
||||||
completion(.retry)
|
|
||||||
} else {
|
|
||||||
// If the token was not refreshed, it's because it was not a 401 error, so we send the response to the completion block
|
|
||||||
completion(.dontRetry)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private var bearerToken: String? = nil
|
|
||||||
|
|
||||||
func refreshTokenIfDoesntExist(completionHandler: @escaping (String) -> Void) {
|
|
||||||
if let bearerToken = bearerToken {
|
|
||||||
completionHandler(bearerToken)
|
|
||||||
} else {
|
|
||||||
startRefreshingToken { token in
|
|
||||||
completionHandler(token)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func refreshTokenIfUnauthorizedRequestResponse(data: Data?, response: URLResponse, error: Error, completionHandler: @escaping (Bool, String?) -> Void) {
|
|
||||||
if let response = response as? HTTPURLResponse, response.statusCode == 401 {
|
|
||||||
startRefreshingToken { token in
|
|
||||||
completionHandler(true, token)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
completionHandler(false, nil)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private func startRefreshingToken(completionHandler: @escaping (String) -> Void) {
|
|
||||||
// Get a bearer token
|
|
||||||
let dummyBearerToken = "..."
|
|
||||||
|
|
||||||
bearerToken = dummyBearerToken
|
|
||||||
|
|
||||||
completionHandler(dummyBearerToken)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Then you assign the `BearerOpenAPIInterceptor` to the property `OpenAPIClient.shared.interceptor`.
|
|
||||||
|
|
||||||
`OpenAPIClient.shared.interceptor = BearerOpenAPIInterceptor()`
|
|
||||||
|
|
||||||
Here is a working sample that put's together all of this.
|
|
||||||
[AppDelegate.swift](https://github.com/OpenAPITools/openapi-generator/blob/master/samples/client/petstore/swift6/urlsessionLibrary/SwaggerClientTests/SwaggerClient/AppDelegate.swift)
|
|
||||||
[BearerTokenHandler.swift](https://github.com/OpenAPITools/openapi-generator/blob/master/samples/client/petstore/swift5/urlsessionLibrary/SwaggerClientTests/SwaggerClient/BearerDecodableRequestBuilder.swift)
|
|
||||||
|
|
||||||
## Author
|
## Author
|
||||||
|
|
||||||
|
@ -140,88 +140,13 @@ Authentication schemes defined for the API:
|
|||||||
- **Type**: HTTP basic authentication
|
- **Type**: HTTP basic authentication
|
||||||
|
|
||||||
|
|
||||||
|
# How do I migrate from the Swift 5 generator to the swift 6 generator?
|
||||||
|
|
||||||
|
https://openapi-generator.tech/docs/faq-generators#how-do-i-migrate-from-the-swift-5-generator-to-the-swift-6-generator
|
||||||
|
|
||||||
### How do I implement bearer token authentication with URLSession on the Swift 6 API client?
|
### How do I implement bearer token authentication with URLSession on the Swift 6 API client?
|
||||||
|
|
||||||
First you implement the `OpenAPIInterceptor` protocol.
|
https://openapi-generator.tech/docs/faq-generators#how-do-i-implement-bearer-token-authentication-with-urlsession-on-the-swift-6-api-client
|
||||||
```
|
|
||||||
public class BearerOpenAPIInterceptor: OpenAPIInterceptor {
|
|
||||||
public init() {}
|
|
||||||
|
|
||||||
public func intercept(urlRequest: URLRequest, urlSession: URLSessionProtocol, openAPIClient: OpenAPIClient, completion: @escaping (Result<URLRequest, any Error>) -> Void) {
|
|
||||||
refreshTokenIfDoesntExist { token in
|
|
||||||
|
|
||||||
// Change the current url request
|
|
||||||
var newUrlRequest = urlRequest
|
|
||||||
newUrlRequest.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
|
|
||||||
|
|
||||||
// Change the global headers
|
|
||||||
openAPIClient.customHeaders["Authorization"] = "Bearer \(token)"
|
|
||||||
|
|
||||||
completion(.success(newUrlRequest))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public func retry(urlRequest: URLRequest, urlSession: URLSessionProtocol, openAPIClient: OpenAPIClient, data: Data?, response: URLResponse, error: Error, completion: @escaping (OpenAPIInterceptorRetry) -> Void) {
|
|
||||||
// We will analyse the response to see if it's a 401, and if it's a 401, we will refresh the token and retry the request
|
|
||||||
refreshTokenIfUnauthorizedRequestResponse(
|
|
||||||
data: data,
|
|
||||||
response: response,
|
|
||||||
error: error
|
|
||||||
) { (wasTokenRefreshed, newToken) in
|
|
||||||
|
|
||||||
if wasTokenRefreshed, let newToken = newToken {
|
|
||||||
|
|
||||||
// Change the global headers
|
|
||||||
openAPIClient.customHeaders["Authorization"] = "Bearer \(newToken)"
|
|
||||||
|
|
||||||
completion(.retry)
|
|
||||||
} else {
|
|
||||||
// If the token was not refreshed, it's because it was not a 401 error, so we send the response to the completion block
|
|
||||||
completion(.dontRetry)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private var bearerToken: String? = nil
|
|
||||||
|
|
||||||
func refreshTokenIfDoesntExist(completionHandler: @escaping (String) -> Void) {
|
|
||||||
if let bearerToken = bearerToken {
|
|
||||||
completionHandler(bearerToken)
|
|
||||||
} else {
|
|
||||||
startRefreshingToken { token in
|
|
||||||
completionHandler(token)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func refreshTokenIfUnauthorizedRequestResponse(data: Data?, response: URLResponse, error: Error, completionHandler: @escaping (Bool, String?) -> Void) {
|
|
||||||
if let response = response as? HTTPURLResponse, response.statusCode == 401 {
|
|
||||||
startRefreshingToken { token in
|
|
||||||
completionHandler(true, token)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
completionHandler(false, nil)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private func startRefreshingToken(completionHandler: @escaping (String) -> Void) {
|
|
||||||
// Get a bearer token
|
|
||||||
let dummyBearerToken = "..."
|
|
||||||
|
|
||||||
bearerToken = dummyBearerToken
|
|
||||||
|
|
||||||
completionHandler(dummyBearerToken)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Then you assign the `BearerOpenAPIInterceptor` to the property `OpenAPIClient.shared.interceptor`.
|
|
||||||
|
|
||||||
`OpenAPIClient.shared.interceptor = BearerOpenAPIInterceptor()`
|
|
||||||
|
|
||||||
Here is a working sample that put's together all of this.
|
|
||||||
[AppDelegate.swift](https://github.com/OpenAPITools/openapi-generator/blob/master/samples/client/petstore/swift6/urlsessionLibrary/SwaggerClientTests/SwaggerClient/AppDelegate.swift)
|
|
||||||
[BearerTokenHandler.swift](https://github.com/OpenAPITools/openapi-generator/blob/master/samples/client/petstore/swift5/urlsessionLibrary/SwaggerClientTests/SwaggerClient/BearerDecodableRequestBuilder.swift)
|
|
||||||
|
|
||||||
## Author
|
## Author
|
||||||
|
|
||||||
|
@ -140,88 +140,13 @@ Authentication schemes defined for the API:
|
|||||||
- **Type**: HTTP basic authentication
|
- **Type**: HTTP basic authentication
|
||||||
|
|
||||||
|
|
||||||
|
# How do I migrate from the Swift 5 generator to the swift 6 generator?
|
||||||
|
|
||||||
|
https://openapi-generator.tech/docs/faq-generators#how-do-i-migrate-from-the-swift-5-generator-to-the-swift-6-generator
|
||||||
|
|
||||||
### How do I implement bearer token authentication with URLSession on the Swift 6 API client?
|
### How do I implement bearer token authentication with URLSession on the Swift 6 API client?
|
||||||
|
|
||||||
First you implement the `OpenAPIInterceptor` protocol.
|
https://openapi-generator.tech/docs/faq-generators#how-do-i-implement-bearer-token-authentication-with-urlsession-on-the-swift-6-api-client
|
||||||
```
|
|
||||||
public class BearerOpenAPIInterceptor: OpenAPIInterceptor {
|
|
||||||
public init() {}
|
|
||||||
|
|
||||||
public func intercept(urlRequest: URLRequest, urlSession: URLSessionProtocol, openAPIClient: OpenAPIClient, completion: @escaping (Result<URLRequest, any Error>) -> Void) {
|
|
||||||
refreshTokenIfDoesntExist { token in
|
|
||||||
|
|
||||||
// Change the current url request
|
|
||||||
var newUrlRequest = urlRequest
|
|
||||||
newUrlRequest.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
|
|
||||||
|
|
||||||
// Change the global headers
|
|
||||||
openAPIClient.customHeaders["Authorization"] = "Bearer \(token)"
|
|
||||||
|
|
||||||
completion(.success(newUrlRequest))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public func retry(urlRequest: URLRequest, urlSession: URLSessionProtocol, openAPIClient: OpenAPIClient, data: Data?, response: URLResponse, error: Error, completion: @escaping (OpenAPIInterceptorRetry) -> Void) {
|
|
||||||
// We will analyse the response to see if it's a 401, and if it's a 401, we will refresh the token and retry the request
|
|
||||||
refreshTokenIfUnauthorizedRequestResponse(
|
|
||||||
data: data,
|
|
||||||
response: response,
|
|
||||||
error: error
|
|
||||||
) { (wasTokenRefreshed, newToken) in
|
|
||||||
|
|
||||||
if wasTokenRefreshed, let newToken = newToken {
|
|
||||||
|
|
||||||
// Change the global headers
|
|
||||||
openAPIClient.customHeaders["Authorization"] = "Bearer \(newToken)"
|
|
||||||
|
|
||||||
completion(.retry)
|
|
||||||
} else {
|
|
||||||
// If the token was not refreshed, it's because it was not a 401 error, so we send the response to the completion block
|
|
||||||
completion(.dontRetry)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private var bearerToken: String? = nil
|
|
||||||
|
|
||||||
func refreshTokenIfDoesntExist(completionHandler: @escaping (String) -> Void) {
|
|
||||||
if let bearerToken = bearerToken {
|
|
||||||
completionHandler(bearerToken)
|
|
||||||
} else {
|
|
||||||
startRefreshingToken { token in
|
|
||||||
completionHandler(token)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func refreshTokenIfUnauthorizedRequestResponse(data: Data?, response: URLResponse, error: Error, completionHandler: @escaping (Bool, String?) -> Void) {
|
|
||||||
if let response = response as? HTTPURLResponse, response.statusCode == 401 {
|
|
||||||
startRefreshingToken { token in
|
|
||||||
completionHandler(true, token)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
completionHandler(false, nil)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private func startRefreshingToken(completionHandler: @escaping (String) -> Void) {
|
|
||||||
// Get a bearer token
|
|
||||||
let dummyBearerToken = "..."
|
|
||||||
|
|
||||||
bearerToken = dummyBearerToken
|
|
||||||
|
|
||||||
completionHandler(dummyBearerToken)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Then you assign the `BearerOpenAPIInterceptor` to the property `OpenAPIClient.shared.interceptor`.
|
|
||||||
|
|
||||||
`OpenAPIClient.shared.interceptor = BearerOpenAPIInterceptor()`
|
|
||||||
|
|
||||||
Here is a working sample that put's together all of this.
|
|
||||||
[AppDelegate.swift](https://github.com/OpenAPITools/openapi-generator/blob/master/samples/client/petstore/swift6/urlsessionLibrary/SwaggerClientTests/SwaggerClient/AppDelegate.swift)
|
|
||||||
[BearerTokenHandler.swift](https://github.com/OpenAPITools/openapi-generator/blob/master/samples/client/petstore/swift5/urlsessionLibrary/SwaggerClientTests/SwaggerClient/BearerDecodableRequestBuilder.swift)
|
|
||||||
|
|
||||||
## Author
|
## Author
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ DIRECTORY=`dirname $0`
|
|||||||
# (cd $DIRECTORY/combineLibrary/SwaggerClientTests/ && ./run_xcodebuild.sh)
|
# (cd $DIRECTORY/combineLibrary/SwaggerClientTests/ && ./run_xcodebuild.sh)
|
||||||
(cd $DIRECTORY/combineDeferredLibrary/SwaggerClientTests/ && ./run_xcodebuild.sh)
|
(cd $DIRECTORY/combineDeferredLibrary/SwaggerClientTests/ && ./run_xcodebuild.sh)
|
||||||
(cd $DIRECTORY/default/SwaggerClientTests/ && ./run_xcodebuild.sh)
|
(cd $DIRECTORY/default/SwaggerClientTests/ && ./run_xcodebuild.sh)
|
||||||
(cd $DIRECTORY/promisekitLibrary/SwaggerClientTests/ && ./run_xcodebuild.sh)
|
# (cd $DIRECTORY/promisekitLibrary/SwaggerClientTests/ && ./run_xcodebuild.sh)
|
||||||
(cd $DIRECTORY/rxswiftLibrary/SwaggerClientTests/ && ./run_xcodebuild.sh)
|
(cd $DIRECTORY/rxswiftLibrary/SwaggerClientTests/ && ./run_xcodebuild.sh)
|
||||||
(cd $DIRECTORY/urlsessionLibrary/SwaggerClientTests/ && ./run_xcodebuild.sh)
|
(cd $DIRECTORY/urlsessionLibrary/SwaggerClientTests/ && ./run_xcodebuild.sh)
|
||||||
|
|
||||||
@ -23,7 +23,7 @@ DIRECTORY=`dirname $0`
|
|||||||
(cd $DIRECTORY/default/ && ./run_spmbuild.sh)
|
(cd $DIRECTORY/default/ && ./run_spmbuild.sh)
|
||||||
(cd $DIRECTORY/objcCompatible/ && ./run_spmbuild.sh)
|
(cd $DIRECTORY/objcCompatible/ && ./run_spmbuild.sh)
|
||||||
(cd $DIRECTORY/oneOf/ && ./run_spmbuild.sh)
|
(cd $DIRECTORY/oneOf/ && ./run_spmbuild.sh)
|
||||||
(cd $DIRECTORY/promisekitLibrary/ && ./run_spmbuild.sh)
|
# (cd $DIRECTORY/promisekitLibrary/ && ./run_spmbuild.sh)
|
||||||
(cd $DIRECTORY/resultLibrary/ && ./run_spmbuild.sh)
|
(cd $DIRECTORY/resultLibrary/ && ./run_spmbuild.sh)
|
||||||
(cd $DIRECTORY/rxswiftLibrary/ && ./run_spmbuild.sh)
|
(cd $DIRECTORY/rxswiftLibrary/ && ./run_spmbuild.sh)
|
||||||
(cd $DIRECTORY/urlsessionLibrary/ && ./run_spmbuild.sh)
|
(cd $DIRECTORY/urlsessionLibrary/ && ./run_spmbuild.sh)
|
||||||
|
@ -140,88 +140,13 @@ Authentication schemes defined for the API:
|
|||||||
- **Type**: HTTP basic authentication
|
- **Type**: HTTP basic authentication
|
||||||
|
|
||||||
|
|
||||||
|
# How do I migrate from the Swift 5 generator to the swift 6 generator?
|
||||||
|
|
||||||
|
https://openapi-generator.tech/docs/faq-generators#how-do-i-migrate-from-the-swift-5-generator-to-the-swift-6-generator
|
||||||
|
|
||||||
### How do I implement bearer token authentication with URLSession on the Swift 6 API client?
|
### How do I implement bearer token authentication with URLSession on the Swift 6 API client?
|
||||||
|
|
||||||
First you implement the `OpenAPIInterceptor` protocol.
|
https://openapi-generator.tech/docs/faq-generators#how-do-i-implement-bearer-token-authentication-with-urlsession-on-the-swift-6-api-client
|
||||||
```
|
|
||||||
public class BearerOpenAPIInterceptor: OpenAPIInterceptor {
|
|
||||||
public init() {}
|
|
||||||
|
|
||||||
public func intercept(urlRequest: URLRequest, urlSession: URLSessionProtocol, openAPIClient: OpenAPIClient, completion: @escaping (Result<URLRequest, any Error>) -> Void) {
|
|
||||||
refreshTokenIfDoesntExist { token in
|
|
||||||
|
|
||||||
// Change the current url request
|
|
||||||
var newUrlRequest = urlRequest
|
|
||||||
newUrlRequest.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
|
|
||||||
|
|
||||||
// Change the global headers
|
|
||||||
openAPIClient.customHeaders["Authorization"] = "Bearer \(token)"
|
|
||||||
|
|
||||||
completion(.success(newUrlRequest))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public func retry(urlRequest: URLRequest, urlSession: URLSessionProtocol, openAPIClient: OpenAPIClient, data: Data?, response: URLResponse, error: Error, completion: @escaping (OpenAPIInterceptorRetry) -> Void) {
|
|
||||||
// We will analyse the response to see if it's a 401, and if it's a 401, we will refresh the token and retry the request
|
|
||||||
refreshTokenIfUnauthorizedRequestResponse(
|
|
||||||
data: data,
|
|
||||||
response: response,
|
|
||||||
error: error
|
|
||||||
) { (wasTokenRefreshed, newToken) in
|
|
||||||
|
|
||||||
if wasTokenRefreshed, let newToken = newToken {
|
|
||||||
|
|
||||||
// Change the global headers
|
|
||||||
openAPIClient.customHeaders["Authorization"] = "Bearer \(newToken)"
|
|
||||||
|
|
||||||
completion(.retry)
|
|
||||||
} else {
|
|
||||||
// If the token was not refreshed, it's because it was not a 401 error, so we send the response to the completion block
|
|
||||||
completion(.dontRetry)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private var bearerToken: String? = nil
|
|
||||||
|
|
||||||
func refreshTokenIfDoesntExist(completionHandler: @escaping (String) -> Void) {
|
|
||||||
if let bearerToken = bearerToken {
|
|
||||||
completionHandler(bearerToken)
|
|
||||||
} else {
|
|
||||||
startRefreshingToken { token in
|
|
||||||
completionHandler(token)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func refreshTokenIfUnauthorizedRequestResponse(data: Data?, response: URLResponse, error: Error, completionHandler: @escaping (Bool, String?) -> Void) {
|
|
||||||
if let response = response as? HTTPURLResponse, response.statusCode == 401 {
|
|
||||||
startRefreshingToken { token in
|
|
||||||
completionHandler(true, token)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
completionHandler(false, nil)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private func startRefreshingToken(completionHandler: @escaping (String) -> Void) {
|
|
||||||
// Get a bearer token
|
|
||||||
let dummyBearerToken = "..."
|
|
||||||
|
|
||||||
bearerToken = dummyBearerToken
|
|
||||||
|
|
||||||
completionHandler(dummyBearerToken)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Then you assign the `BearerOpenAPIInterceptor` to the property `OpenAPIClient.shared.interceptor`.
|
|
||||||
|
|
||||||
`OpenAPIClient.shared.interceptor = BearerOpenAPIInterceptor()`
|
|
||||||
|
|
||||||
Here is a working sample that put's together all of this.
|
|
||||||
[AppDelegate.swift](https://github.com/OpenAPITools/openapi-generator/blob/master/samples/client/petstore/swift6/urlsessionLibrary/SwaggerClientTests/SwaggerClient/AppDelegate.swift)
|
|
||||||
[BearerTokenHandler.swift](https://github.com/OpenAPITools/openapi-generator/blob/master/samples/client/petstore/swift5/urlsessionLibrary/SwaggerClientTests/SwaggerClient/BearerDecodableRequestBuilder.swift)
|
|
||||||
|
|
||||||
## Author
|
## Author
|
||||||
|
|
||||||
|
@ -40,88 +40,13 @@ Class | Method | HTTP request | Description
|
|||||||
Endpoints do not require authorization.
|
Endpoints do not require authorization.
|
||||||
|
|
||||||
|
|
||||||
|
# How do I migrate from the Swift 5 generator to the swift 6 generator?
|
||||||
|
|
||||||
|
https://openapi-generator.tech/docs/faq-generators#how-do-i-migrate-from-the-swift-5-generator-to-the-swift-6-generator
|
||||||
|
|
||||||
### How do I implement bearer token authentication with URLSession on the Swift 6 API client?
|
### How do I implement bearer token authentication with URLSession on the Swift 6 API client?
|
||||||
|
|
||||||
First you implement the `OpenAPIInterceptor` protocol.
|
https://openapi-generator.tech/docs/faq-generators#how-do-i-implement-bearer-token-authentication-with-urlsession-on-the-swift-6-api-client
|
||||||
```
|
|
||||||
public class BearerOpenAPIInterceptor: OpenAPIInterceptor {
|
|
||||||
public init() {}
|
|
||||||
|
|
||||||
public func intercept(urlRequest: URLRequest, urlSession: URLSessionProtocol, openAPIClient: OpenAPIClient, completion: @escaping (Result<URLRequest, any Error>) -> Void) {
|
|
||||||
refreshTokenIfDoesntExist { token in
|
|
||||||
|
|
||||||
// Change the current url request
|
|
||||||
var newUrlRequest = urlRequest
|
|
||||||
newUrlRequest.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
|
|
||||||
|
|
||||||
// Change the global headers
|
|
||||||
openAPIClient.customHeaders["Authorization"] = "Bearer \(token)"
|
|
||||||
|
|
||||||
completion(.success(newUrlRequest))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public func retry(urlRequest: URLRequest, urlSession: URLSessionProtocol, openAPIClient: OpenAPIClient, data: Data?, response: URLResponse, error: Error, completion: @escaping (OpenAPIInterceptorRetry) -> Void) {
|
|
||||||
// We will analyse the response to see if it's a 401, and if it's a 401, we will refresh the token and retry the request
|
|
||||||
refreshTokenIfUnauthorizedRequestResponse(
|
|
||||||
data: data,
|
|
||||||
response: response,
|
|
||||||
error: error
|
|
||||||
) { (wasTokenRefreshed, newToken) in
|
|
||||||
|
|
||||||
if wasTokenRefreshed, let newToken = newToken {
|
|
||||||
|
|
||||||
// Change the global headers
|
|
||||||
openAPIClient.customHeaders["Authorization"] = "Bearer \(newToken)"
|
|
||||||
|
|
||||||
completion(.retry)
|
|
||||||
} else {
|
|
||||||
// If the token was not refreshed, it's because it was not a 401 error, so we send the response to the completion block
|
|
||||||
completion(.dontRetry)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private var bearerToken: String? = nil
|
|
||||||
|
|
||||||
func refreshTokenIfDoesntExist(completionHandler: @escaping (String) -> Void) {
|
|
||||||
if let bearerToken = bearerToken {
|
|
||||||
completionHandler(bearerToken)
|
|
||||||
} else {
|
|
||||||
startRefreshingToken { token in
|
|
||||||
completionHandler(token)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func refreshTokenIfUnauthorizedRequestResponse(data: Data?, response: URLResponse, error: Error, completionHandler: @escaping (Bool, String?) -> Void) {
|
|
||||||
if let response = response as? HTTPURLResponse, response.statusCode == 401 {
|
|
||||||
startRefreshingToken { token in
|
|
||||||
completionHandler(true, token)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
completionHandler(false, nil)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private func startRefreshingToken(completionHandler: @escaping (String) -> Void) {
|
|
||||||
// Get a bearer token
|
|
||||||
let dummyBearerToken = "..."
|
|
||||||
|
|
||||||
bearerToken = dummyBearerToken
|
|
||||||
|
|
||||||
completionHandler(dummyBearerToken)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Then you assign the `BearerOpenAPIInterceptor` to the property `OpenAPIClient.shared.interceptor`.
|
|
||||||
|
|
||||||
`OpenAPIClient.shared.interceptor = BearerOpenAPIInterceptor()`
|
|
||||||
|
|
||||||
Here is a working sample that put's together all of this.
|
|
||||||
[AppDelegate.swift](https://github.com/OpenAPITools/openapi-generator/blob/master/samples/client/petstore/swift6/urlsessionLibrary/SwaggerClientTests/SwaggerClient/AppDelegate.swift)
|
|
||||||
[BearerTokenHandler.swift](https://github.com/OpenAPITools/openapi-generator/blob/master/samples/client/petstore/swift5/urlsessionLibrary/SwaggerClientTests/SwaggerClient/BearerDecodableRequestBuilder.swift)
|
|
||||||
|
|
||||||
## Author
|
## Author
|
||||||
|
|
||||||
|
@ -147,6 +147,9 @@ Authentication schemes defined for the API:
|
|||||||
- **Type**: HTTP basic authentication
|
- **Type**: HTTP basic authentication
|
||||||
|
|
||||||
|
|
||||||
|
# How do I migrate from the Swift 5 generator to the swift 6 generator?
|
||||||
|
|
||||||
|
https://openapi-generator.tech/docs/faq-generators#how-do-i-migrate-from-the-swift-5-generator-to-the-swift-6-generator
|
||||||
|
|
||||||
## Author
|
## Author
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user