From 2354d402a8813c3893d1499e852fea24c4c941fa Mon Sep 17 00:00:00 2001 From: Bruno Coelho <4brunu@users.noreply.github.com> Date: Mon, 14 Oct 2024 12:55:25 +0100 Subject: [PATCH] [swift6] promote to beta and improve documentation (#19856) * [swift6] promote to beta * [swift6] format code * [swift] authentication docs * [swift] update docs * [swift] update docs * [swift] update docs * [swift] update docs * [swift] update docs * [swift] update docs * [swift] update docs * [swift] update docs * [swift] update docs * [swift] update docs --- docs/faq-generators.md | 404 +++++++++++++++++- docs/generators.md | 2 +- docs/generators/swift6.md | 2 +- .../languages/Swift5ClientCodegen.java | 5 + .../languages/Swift6ClientCodegen.java | 2 +- .../src/main/resources/swift5/README.mustache | 246 +++++++++++ .../src/main/resources/swift6/README.mustache | 136 ++++++ .../src/main/resources/swift6/api.mustache | 6 +- .../swift5/alamofireLibrary/README.md | 86 ++++ .../swift5/asyncAwaitLibrary/README.md | 157 +++++++ .../petstore/swift5/combineLibrary/README.md | 157 +++++++ .../client/petstore/swift5/default/README.md | 157 +++++++ .../petstore/swift5/objcCompatible/README.md | 157 +++++++ .../client/petstore/swift5/oneOf/README.md | 157 +++++++ .../swift5/promisekitLibrary/README.md | 157 +++++++ .../petstore/swift5/resultLibrary/README.md | 157 +++++++ .../petstore/swift5/rxswiftLibrary/README.md | 157 +++++++ .../swift5/urlsessionLibrary/README.md | 157 +++++++ .../petstore/swift5/validation/README.md | 157 +++++++ .../petstore/swift5/vaporLibrary/README.md | 1 + .../swift6/alamofireLibrary/README.md | 50 +++ .../PetstoreClient/APIs/AnotherFakeAPI.swift | 1 - .../Sources/PetstoreClient/APIs/FakeAPI.swift | 66 ++- .../APIs/FakeClassnameTags123API.swift | 1 - .../Sources/PetstoreClient/APIs/PetAPI.swift | 23 +- .../PetstoreClient/APIs/StoreAPI.swift | 4 - .../Sources/PetstoreClient/APIs/UserAPI.swift | 12 +- .../swift6/apiNonStaticMethod/README.md | 50 +++ .../PetstoreClient/APIs/AnotherFakeAPI.swift | 1 - .../Sources/PetstoreClient/APIs/FakeAPI.swift | 66 ++- .../APIs/FakeClassnameTags123API.swift | 1 - .../Sources/PetstoreClient/APIs/PetAPI.swift | 23 +- .../PetstoreClient/APIs/StoreAPI.swift | 4 - .../Sources/PetstoreClient/APIs/UserAPI.swift | 12 +- .../swift6/asyncAwaitLibrary/README.md | 83 ++++ .../PetstoreClient/APIs/AnotherFakeAPI.swift | 1 - .../Sources/PetstoreClient/APIs/FakeAPI.swift | 66 ++- .../APIs/FakeClassnameTags123API.swift | 1 - .../Sources/PetstoreClient/APIs/PetAPI.swift | 23 +- .../PetstoreClient/APIs/StoreAPI.swift | 4 - .../Sources/PetstoreClient/APIs/UserAPI.swift | 12 +- .../OpenAPIs/APIs/AnotherFakeAPI.swift | 1 - .../Classes/OpenAPIs/APIs/FakeAPI.swift | 66 ++- .../APIs/FakeClassnameTags123API.swift | 1 - .../Classes/OpenAPIs/APIs/PetAPI.swift | 23 +- .../Classes/OpenAPIs/APIs/StoreAPI.swift | 4 - .../Classes/OpenAPIs/APIs/UserAPI.swift | 12 +- .../swift6/combineDeferredLibrary/README.md | 83 ++++ .../petstore/swift6/combineLibrary/README.md | 83 ++++ .../CombineLibrary/APIs/AnotherFakeAPI.swift | 1 - .../Sources/CombineLibrary/APIs/FakeAPI.swift | 66 ++- .../APIs/FakeClassnameTags123API.swift | 1 - .../Sources/CombineLibrary/APIs/PetAPI.swift | 23 +- .../CombineLibrary/APIs/StoreAPI.swift | 4 - .../Sources/CombineLibrary/APIs/UserAPI.swift | 12 +- .../client/petstore/swift6/default/README.md | 83 ++++ .../PetstoreClient/APIs/AnotherFakeAPI.swift | 3 +- .../Sources/PetstoreClient/APIs/FakeAPI.swift | 76 ++-- .../APIs/FakeClassnameTags123API.swift | 1 - .../Sources/PetstoreClient/APIs/PetAPI.swift | 23 +- .../PetstoreClient/APIs/StoreAPI.swift | 4 - .../Sources/PetstoreClient/APIs/UserAPI.swift | 12 +- .../petstore/swift6/objcCompatible/README.md | 83 ++++ .../PetstoreClient/APIs/AnotherFakeAPI.swift | 1 - .../Sources/PetstoreClient/APIs/FakeAPI.swift | 66 ++- .../APIs/FakeClassnameTags123API.swift | 1 - .../Sources/PetstoreClient/APIs/PetAPI.swift | 23 +- .../PetstoreClient/APIs/StoreAPI.swift | 4 - .../Sources/PetstoreClient/APIs/UserAPI.swift | 12 +- .../Classes/OpenAPIs/APIs/DefaultAPI.swift | 1 - .../client/petstore/swift6/oneOf/README.md | 83 ++++ .../OpenAPIs/APIs/AnotherFakeAPI.swift | 1 - .../Classes/OpenAPIs/APIs/FakeAPI.swift | 66 ++- .../APIs/FakeClassnameTags123API.swift | 1 - .../Classes/OpenAPIs/APIs/PetAPI.swift | 23 +- .../Classes/OpenAPIs/APIs/StoreAPI.swift | 4 - .../Classes/OpenAPIs/APIs/UserAPI.swift | 12 +- .../swift6/promisekitLibrary/README.md | 83 ++++ .../OpenAPIs/APIs/AnotherFakeAPI.swift | 1 - .../Classes/OpenAPIs/APIs/FakeAPI.swift | 66 ++- .../APIs/FakeClassnameTags123API.swift | 1 - .../Classes/OpenAPIs/APIs/PetAPI.swift | 23 +- .../Classes/OpenAPIs/APIs/StoreAPI.swift | 4 - .../Classes/OpenAPIs/APIs/UserAPI.swift | 12 +- .../petstore/swift6/resultLibrary/README.md | 83 ++++ .../OpenAPIs/APIs/AnotherFakeAPI.swift | 1 - .../Classes/OpenAPIs/APIs/FakeAPI.swift | 66 ++- .../APIs/FakeClassnameTags123API.swift | 1 - .../Classes/OpenAPIs/APIs/PetAPI.swift | 23 +- .../Classes/OpenAPIs/APIs/StoreAPI.swift | 4 - .../Classes/OpenAPIs/APIs/UserAPI.swift | 12 +- .../petstore/swift6/rxswiftLibrary/README.md | 83 ++++ .../swift6/urlsessionLibrary/README.md | 83 ++++ .../PetstoreClient/APIs/AnotherFakeAPI.swift | 1 - .../Sources/PetstoreClient/APIs/FakeAPI.swift | 66 ++- .../APIs/FakeClassnameTags123API.swift | 1 - .../Sources/PetstoreClient/APIs/PetAPI.swift | 23 +- .../PetstoreClient/APIs/StoreAPI.swift | 4 - .../Sources/PetstoreClient/APIs/UserAPI.swift | 12 +- .../SwaggerClient/BearerTokenHandler.swift | 10 +- .../Classes/OpenAPIs/APIs/DefaultAPI.swift | 1 - .../petstore/swift6/validation/README.md | 83 ++++ .../petstore/swift6/vaporLibrary/README.md | 1 + 103 files changed, 3863 insertions(+), 812 deletions(-) diff --git a/docs/faq-generators.md b/docs/faq-generators.md index c54f151372bd..7023e595a3cb 100644 --- a/docs/faq-generators.md +++ b/docs/faq-generators.md @@ -92,16 +92,402 @@ git clone https://github.com/openapitools/openapi-generator.git cd openapi-generator/samples/client/petstore/swift/default/OpenAPIClientTests mvn integration-test ``` -Besides `default` (folder), there's another folder `promisekit` for Swift API client with [PromiseKit support](https://github.com/mxcl/PromiseKit) -``` -git clone https://github.com/openapitools/openapi-generator.git -cd openapi-generator/samples/client/petstore/swift/promisekit/OpenAPIClientTests -mvn integration-test -``` - -### Is Swift (2.x) generator still actively maintained? -No, please use `swift3` or `swift4` generator instead as we want to focus on Swift 3.x, 4.x. +### Which Swift generator is still actively maintained? + +Please use `swift5` generator because Swift 4.x is deprecated. +There is a new `swift6` generator, that is currently in beta, try it and give us your feedback. + +### How do I implement bearer token authentication with URLSession on the Swift 5 API client? + +
+ First you subclass RequestBuilderFactory + + class BearerRequestBuilderFactory: RequestBuilderFactory { + func getNonDecodableBuilder() -> RequestBuilder.Type { + BearerRequestBuilder.self + } + + func getBuilder() -> RequestBuilder.Type { + BearerDecodableRequestBuilder.self + } + } +
+ +
+ Then you subclass URLSessionRequestBuilder and URLSessionDecodableRequestBuilder + + class BearerRequestBuilder: URLSessionRequestBuilder { + @discardableResult + override func execute(_ apiResponseQueue: DispatchQueue = PetstoreClientAPI.apiResponseQueue, _ completion: @escaping (Result, 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: URLSessionDecodableRequestBuilder { + @discardableResult + override func execute(_ apiResponseQueue: DispatchQueue = PetstoreClientAPI.apiResponseQueue, _ completion: @escaping (Result, 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) + +### How do I implement bearer token authentication with Alamofire on the Swift 5 API client? + +
+ First you subclass RequestBuilderFactory + + class BearerRequestBuilderFactory: RequestBuilderFactory { + func getNonDecodableBuilder() -> RequestBuilder.Type { + BearerRequestBuilder.self + } + + func getBuilder() -> RequestBuilder.Type { + BearerDecodableRequestBuilder.self + } + } +
+ +
+ Then you subclass AlamofireRequestBuilder and AlamofireDecodableRequestBuilder + + class BearerRequestBuilder: AlamofireRequestBuilder { + override func createSessionManager() -> SessionManager { + let sessionManager = super.createSessionManager() + + let bearerTokenHandler = BearerTokenHandler() + sessionManager.adapter = bearerTokenHandler + sessionManager.retrier = bearerTokenHandler + + return sessionManager + } + } + + class BearerDecodableRequestBuilder: AlamofireDecodableRequestBuilder { + 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) + +### How do I implement bearer token authentication with URLSession on the Swift 6 API client? + +
+ First you implement the `OpenAPIInterceptor` protocol. +public class BearerOpenAPIInterceptor: OpenAPIInterceptor { + public init() {} + + public func intercept(urlRequest: URLRequest, urlSession: URLSessionProtocol, openAPIClient: OpenAPIClient, completion: @escaping (Result) -> 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) + +### How do I implement bearer token authentication with Alamofire on the Swift 6 API client? + +
+ First implement the `Alamofire` `RequestInterceptor` protocol. +class BearerTokenHandler: RequestInterceptor, @unchecked Sendable { + private var bearerToken: String? = nil + + func adapt(_ urlRequest: URLRequest, for session: Session, completion: @escaping (Result) -> 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) + +### How do I migrate from the Swift 5 generator to the swift 6 generator? + +- 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 `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`. +- A new configuration, `apiStaticMethod`, allows you to use instance methods instead of class methods for API calls. For more information, check the sample project [apiNonStaticMethod](https://github.com/OpenAPITools/openapi-generator/tree/master/samples/client/petstore/swift6/apiNonStaticMethod). +- The new default response is based on async/await. To revert to the previous behavior, set the `responseAs` flag to `ObjcBlock`. +- The default project structure now follows the SPM (Swift Package Manager) structure. To revert to the old structure, set the `useSPMFileStructure` flag to `false`. +- The former `{{projectName}}API` is now called `OpenAPIClient`. +- You can now set a request interceptor and retrier by configuring `OpenAPIClient.shared.interceptor`, making authenticated requests easier to manage. ## TypeScript diff --git a/docs/generators.md b/docs/generators.md index 82fb5ed72926..eea91149e51c 100644 --- a/docs/generators.md +++ b/docs/generators.md @@ -66,7 +66,7 @@ The following generators are available: * [scalaz](generators/scalaz.md) * [swift-combine](generators/swift-combine.md) * [swift5](generators/swift5.md) -* [swift6 (experimental)](generators/swift6.md) +* [swift6 (beta)](generators/swift6.md) * [typescript (experimental)](generators/typescript.md) * [typescript-angular](generators/typescript-angular.md) * [typescript-aurelia](generators/typescript-aurelia.md) diff --git a/docs/generators/swift6.md b/docs/generators/swift6.md index 3828b2d89d6c..c86c4c6739de 100644 --- a/docs/generators/swift6.md +++ b/docs/generators/swift6.md @@ -7,7 +7,7 @@ title: Documentation for the swift6 Generator | Property | Value | Notes | | -------- | ----- | ----- | | generator name | swift6 | pass this to the generate command after -g | -| generator stability | EXPERIMENTAL | | +| generator stability | BETA | | | generator type | CLIENT | | | generator language | Swift | | | generator default templating engine | mustache | | diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/Swift5ClientCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/Swift5ClientCodegen.java index 00e727cf2dba..2ae6c75522dd 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/Swift5ClientCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/Swift5ClientCodegen.java @@ -1305,6 +1305,11 @@ public void postProcess() { System.out.println("# #"); 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("# #"); + 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("# https://openapi-generator.tech/docs/generators/swift6 #"); + 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("################################################################################"); } diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/Swift6ClientCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/Swift6ClientCodegen.java index 07eee1f2c05b..96d985e32594 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/Swift6ClientCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/Swift6ClientCodegen.java @@ -138,7 +138,7 @@ public Swift6ClientCodegen() { this.useOneOfInterfaces = true; generatorMetadata = GeneratorMetadata.newBuilder(generatorMetadata) - .stability(Stability.EXPERIMENTAL) + .stability(Stability.BETA) .build(); outputFolder = "generated-code" + File.separator + "swift"; diff --git a/modules/openapi-generator/src/main/resources/swift5/README.mustache b/modules/openapi-generator/src/main/resources/swift5/README.mustache index 0955144895ba..cbc83781b0a6 100644 --- a/modules/openapi-generator/src/main/resources/swift5/README.mustache +++ b/modules/openapi-generator/src/main/resources/swift5/README.mustache @@ -78,6 +78,252 @@ Class | Method | HTTP request | Description {{/authMethods}} +{{#useURLSession}} +### How do I implement bearer token authentication with URLSession on the Swift 5 API client? + +First you subclass RequestBuilderFactory +``` +class BearerRequestBuilderFactory: RequestBuilderFactory { + func getNonDecodableBuilder() -> RequestBuilder.Type { + BearerRequestBuilder.self + } + + func getBuilder() -> RequestBuilder.Type { + BearerDecodableRequestBuilder.self + } +} +``` + +Then you subclass URLSessionRequestBuilder and URLSessionDecodableRequestBuilder +``` +class BearerRequestBuilder: URLSessionRequestBuilder { + @discardableResult + override func execute(_ apiResponseQueue: DispatchQueue = PetstoreClientAPI.apiResponseQueue, _ completion: @escaping (Result, 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: URLSessionDecodableRequestBuilder { + @discardableResult + override func execute(_ apiResponseQueue: DispatchQueue = PetstoreClientAPI.apiResponseQueue, _ completion: @escaping (Result, 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}} +{{#useAlamofire}} +### How do I implement bearer token authentication with Alamofire on the Swift 5 API client? + +First you subclass RequestBuilderFactory +``` +class BearerRequestBuilderFactory: RequestBuilderFactory { + func getNonDecodableBuilder() -> RequestBuilder.Type { + BearerRequestBuilder.self + } + + func getBuilder() -> RequestBuilder.Type { + BearerDecodableRequestBuilder.self + } +} +``` + +Then you subclass AlamofireRequestBuilder and AlamofireDecodableRequestBuilder +``` +class BearerRequestBuilder: AlamofireRequestBuilder { + override func createSessionManager() -> SessionManager { + let sessionManager = super.createSessionManager() + + let bearerTokenHandler = BearerTokenHandler() + sessionManager.adapter = bearerTokenHandler + sessionManager.retrier = bearerTokenHandler + + return sessionManager + } +} + +class BearerDecodableRequestBuilder: AlamofireDecodableRequestBuilder { + 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}} + ## Author {{#apiInfo}}{{#apis}}{{#-last}}{{infoEmail}} diff --git a/modules/openapi-generator/src/main/resources/swift6/README.mustache b/modules/openapi-generator/src/main/resources/swift6/README.mustache index 0cda1ab0a794..190181e0d2a1 100644 --- a/modules/openapi-generator/src/main/resources/swift6/README.mustache +++ b/modules/openapi-generator/src/main/resources/swift6/README.mustache @@ -78,6 +78,142 @@ Class | Method | HTTP request | Description {{/authMethods}} +{{#useURLSession}} +### How do I implement bearer token authentication with URLSession on the Swift 6 API client? + +First you implement the `OpenAPIInterceptor` protocol. +``` +public class BearerOpenAPIInterceptor: OpenAPIInterceptor { + public init() {} + + public func intercept(urlRequest: URLRequest, urlSession: URLSessionProtocol, openAPIClient: OpenAPIClient, completion: @escaping (Result) -> 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}} +{{#useAlamofire}} +### How do I implement bearer token authentication with Alamofire on the Swift 6 API client? + +First implement the `Alamofire` `RequestInterceptor` protocol. +``` +class BearerTokenHandler: RequestInterceptor, @unchecked Sendable { + private var bearerToken: String? = nil + + func adapt(_ urlRequest: URLRequest, for session: Session, completion: @escaping (Result) -> 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}} + ## Author {{#apiInfo}}{{#apis}}{{#-last}}{{infoEmail}} diff --git a/modules/openapi-generator/src/main/resources/swift6/api.mustache b/modules/openapi-generator/src/main/resources/swift6/api.mustache index 06f4a945da4d..1ea5b5607946 100644 --- a/modules/openapi-generator/src/main/resources/swift6/api.mustache +++ b/modules/openapi-generator/src/main/resources/swift6/api.mustache @@ -270,8 +270,10 @@ extension {{projectName}}API { {{/externalDocs}} {{#allParams}} - parameter {{paramName}}: ({{#isFormParam}}form{{/isFormParam}}{{#isQueryParam}}query{{/isQueryParam}}{{#isPathParam}}path{{/isPathParam}}{{#isHeaderParam}}header{{/isHeaderParam}}{{#isBodyParam}}body{{/isBodyParam}}) {{description}} {{^required}}(optional{{#defaultValue}}, default to {{{.}}}{{/defaultValue}}){{/required}} - {{/allParams}}{{#apiStaticMethod}} - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request.{{/apiStaticMethod}} + {{/allParams}} + {{#apiStaticMethod}} + - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. + {{/apiStaticMethod}} - returns: RequestBuilder<{{{returnType}}}{{#returnType}}{{#isResponseOptional}}?{{/isResponseOptional}}{{/returnType}}{{^returnType}}Void{{/returnType}}> {{description}} */ {{#isDeprecated}} diff --git a/samples/client/petstore/swift5/alamofireLibrary/README.md b/samples/client/petstore/swift5/alamofireLibrary/README.md index 9f8565335da9..2839101862c4 100644 --- a/samples/client/petstore/swift5/alamofireLibrary/README.md +++ b/samples/client/petstore/swift5/alamofireLibrary/README.md @@ -140,6 +140,92 @@ Authentication schemes defined for the API: - **Type**: HTTP basic authentication +### How do I implement bearer token authentication with Alamofire on the Swift 5 API client? + +First you subclass RequestBuilderFactory +``` +class BearerRequestBuilderFactory: RequestBuilderFactory { + func getNonDecodableBuilder() -> RequestBuilder.Type { + BearerRequestBuilder.self + } + + func getBuilder() -> RequestBuilder.Type { + BearerDecodableRequestBuilder.self + } +} +``` + +Then you subclass AlamofireRequestBuilder and AlamofireDecodableRequestBuilder +``` +class BearerRequestBuilder: AlamofireRequestBuilder { + override func createSessionManager() -> SessionManager { + let sessionManager = super.createSessionManager() + + let bearerTokenHandler = BearerTokenHandler() + sessionManager.adapter = bearerTokenHandler + sessionManager.retrier = bearerTokenHandler + + return sessionManager + } +} + +class BearerDecodableRequestBuilder: AlamofireDecodableRequestBuilder { + 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 diff --git a/samples/client/petstore/swift5/asyncAwaitLibrary/README.md b/samples/client/petstore/swift5/asyncAwaitLibrary/README.md index 9f8565335da9..f0b3abd84c07 100644 --- a/samples/client/petstore/swift5/asyncAwaitLibrary/README.md +++ b/samples/client/petstore/swift5/asyncAwaitLibrary/README.md @@ -140,6 +140,163 @@ Authentication schemes defined for the API: - **Type**: HTTP basic authentication +### How do I implement bearer token authentication with URLSession on the Swift 5 API client? + +First you subclass RequestBuilderFactory +``` +class BearerRequestBuilderFactory: RequestBuilderFactory { + func getNonDecodableBuilder() -> RequestBuilder.Type { + BearerRequestBuilder.self + } + + func getBuilder() -> RequestBuilder.Type { + BearerDecodableRequestBuilder.self + } +} +``` + +Then you subclass URLSessionRequestBuilder and URLSessionDecodableRequestBuilder +``` +class BearerRequestBuilder: URLSessionRequestBuilder { + @discardableResult + override func execute(_ apiResponseQueue: DispatchQueue = PetstoreClientAPI.apiResponseQueue, _ completion: @escaping (Result, 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: URLSessionDecodableRequestBuilder { + @discardableResult + override func execute(_ apiResponseQueue: DispatchQueue = PetstoreClientAPI.apiResponseQueue, _ completion: @escaping (Result, 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 diff --git a/samples/client/petstore/swift5/combineLibrary/README.md b/samples/client/petstore/swift5/combineLibrary/README.md index 9f8565335da9..f0b3abd84c07 100644 --- a/samples/client/petstore/swift5/combineLibrary/README.md +++ b/samples/client/petstore/swift5/combineLibrary/README.md @@ -140,6 +140,163 @@ Authentication schemes defined for the API: - **Type**: HTTP basic authentication +### How do I implement bearer token authentication with URLSession on the Swift 5 API client? + +First you subclass RequestBuilderFactory +``` +class BearerRequestBuilderFactory: RequestBuilderFactory { + func getNonDecodableBuilder() -> RequestBuilder.Type { + BearerRequestBuilder.self + } + + func getBuilder() -> RequestBuilder.Type { + BearerDecodableRequestBuilder.self + } +} +``` + +Then you subclass URLSessionRequestBuilder and URLSessionDecodableRequestBuilder +``` +class BearerRequestBuilder: URLSessionRequestBuilder { + @discardableResult + override func execute(_ apiResponseQueue: DispatchQueue = PetstoreClientAPI.apiResponseQueue, _ completion: @escaping (Result, 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: URLSessionDecodableRequestBuilder { + @discardableResult + override func execute(_ apiResponseQueue: DispatchQueue = PetstoreClientAPI.apiResponseQueue, _ completion: @escaping (Result, 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 diff --git a/samples/client/petstore/swift5/default/README.md b/samples/client/petstore/swift5/default/README.md index c9984ae7ecb0..86e8063d7219 100644 --- a/samples/client/petstore/swift5/default/README.md +++ b/samples/client/petstore/swift5/default/README.md @@ -151,6 +151,163 @@ Authentication schemes defined for the API: - **Type**: HTTP basic authentication +### How do I implement bearer token authentication with URLSession on the Swift 5 API client? + +First you subclass RequestBuilderFactory +``` +class BearerRequestBuilderFactory: RequestBuilderFactory { + func getNonDecodableBuilder() -> RequestBuilder.Type { + BearerRequestBuilder.self + } + + func getBuilder() -> RequestBuilder.Type { + BearerDecodableRequestBuilder.self + } +} +``` + +Then you subclass URLSessionRequestBuilder and URLSessionDecodableRequestBuilder +``` +class BearerRequestBuilder: URLSessionRequestBuilder { + @discardableResult + override func execute(_ apiResponseQueue: DispatchQueue = PetstoreClientAPI.apiResponseQueue, _ completion: @escaping (Result, 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: URLSessionDecodableRequestBuilder { + @discardableResult + override func execute(_ apiResponseQueue: DispatchQueue = PetstoreClientAPI.apiResponseQueue, _ completion: @escaping (Result, 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 diff --git a/samples/client/petstore/swift5/objcCompatible/README.md b/samples/client/petstore/swift5/objcCompatible/README.md index 9f8565335da9..f0b3abd84c07 100644 --- a/samples/client/petstore/swift5/objcCompatible/README.md +++ b/samples/client/petstore/swift5/objcCompatible/README.md @@ -140,6 +140,163 @@ Authentication schemes defined for the API: - **Type**: HTTP basic authentication +### How do I implement bearer token authentication with URLSession on the Swift 5 API client? + +First you subclass RequestBuilderFactory +``` +class BearerRequestBuilderFactory: RequestBuilderFactory { + func getNonDecodableBuilder() -> RequestBuilder.Type { + BearerRequestBuilder.self + } + + func getBuilder() -> RequestBuilder.Type { + BearerDecodableRequestBuilder.self + } +} +``` + +Then you subclass URLSessionRequestBuilder and URLSessionDecodableRequestBuilder +``` +class BearerRequestBuilder: URLSessionRequestBuilder { + @discardableResult + override func execute(_ apiResponseQueue: DispatchQueue = PetstoreClientAPI.apiResponseQueue, _ completion: @escaping (Result, 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: URLSessionDecodableRequestBuilder { + @discardableResult + override func execute(_ apiResponseQueue: DispatchQueue = PetstoreClientAPI.apiResponseQueue, _ completion: @escaping (Result, 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 diff --git a/samples/client/petstore/swift5/oneOf/README.md b/samples/client/petstore/swift5/oneOf/README.md index c7d7e59c6da3..7797dedfb7db 100644 --- a/samples/client/petstore/swift5/oneOf/README.md +++ b/samples/client/petstore/swift5/oneOf/README.md @@ -42,6 +42,163 @@ Class | Method | HTTP request | Description Endpoints do not require authorization. +### How do I implement bearer token authentication with URLSession on the Swift 5 API client? + +First you subclass RequestBuilderFactory +``` +class BearerRequestBuilderFactory: RequestBuilderFactory { + func getNonDecodableBuilder() -> RequestBuilder.Type { + BearerRequestBuilder.self + } + + func getBuilder() -> RequestBuilder.Type { + BearerDecodableRequestBuilder.self + } +} +``` + +Then you subclass URLSessionRequestBuilder and URLSessionDecodableRequestBuilder +``` +class BearerRequestBuilder: URLSessionRequestBuilder { + @discardableResult + override func execute(_ apiResponseQueue: DispatchQueue = PetstoreClientAPI.apiResponseQueue, _ completion: @escaping (Result, 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: URLSessionDecodableRequestBuilder { + @discardableResult + override func execute(_ apiResponseQueue: DispatchQueue = PetstoreClientAPI.apiResponseQueue, _ completion: @escaping (Result, 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 diff --git a/samples/client/petstore/swift5/promisekitLibrary/README.md b/samples/client/petstore/swift5/promisekitLibrary/README.md index 9f8565335da9..f0b3abd84c07 100644 --- a/samples/client/petstore/swift5/promisekitLibrary/README.md +++ b/samples/client/petstore/swift5/promisekitLibrary/README.md @@ -140,6 +140,163 @@ Authentication schemes defined for the API: - **Type**: HTTP basic authentication +### How do I implement bearer token authentication with URLSession on the Swift 5 API client? + +First you subclass RequestBuilderFactory +``` +class BearerRequestBuilderFactory: RequestBuilderFactory { + func getNonDecodableBuilder() -> RequestBuilder.Type { + BearerRequestBuilder.self + } + + func getBuilder() -> RequestBuilder.Type { + BearerDecodableRequestBuilder.self + } +} +``` + +Then you subclass URLSessionRequestBuilder and URLSessionDecodableRequestBuilder +``` +class BearerRequestBuilder: URLSessionRequestBuilder { + @discardableResult + override func execute(_ apiResponseQueue: DispatchQueue = PetstoreClientAPI.apiResponseQueue, _ completion: @escaping (Result, 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: URLSessionDecodableRequestBuilder { + @discardableResult + override func execute(_ apiResponseQueue: DispatchQueue = PetstoreClientAPI.apiResponseQueue, _ completion: @escaping (Result, 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 diff --git a/samples/client/petstore/swift5/resultLibrary/README.md b/samples/client/petstore/swift5/resultLibrary/README.md index 9f8565335da9..f0b3abd84c07 100644 --- a/samples/client/petstore/swift5/resultLibrary/README.md +++ b/samples/client/petstore/swift5/resultLibrary/README.md @@ -140,6 +140,163 @@ Authentication schemes defined for the API: - **Type**: HTTP basic authentication +### How do I implement bearer token authentication with URLSession on the Swift 5 API client? + +First you subclass RequestBuilderFactory +``` +class BearerRequestBuilderFactory: RequestBuilderFactory { + func getNonDecodableBuilder() -> RequestBuilder.Type { + BearerRequestBuilder.self + } + + func getBuilder() -> RequestBuilder.Type { + BearerDecodableRequestBuilder.self + } +} +``` + +Then you subclass URLSessionRequestBuilder and URLSessionDecodableRequestBuilder +``` +class BearerRequestBuilder: URLSessionRequestBuilder { + @discardableResult + override func execute(_ apiResponseQueue: DispatchQueue = PetstoreClientAPI.apiResponseQueue, _ completion: @escaping (Result, 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: URLSessionDecodableRequestBuilder { + @discardableResult + override func execute(_ apiResponseQueue: DispatchQueue = PetstoreClientAPI.apiResponseQueue, _ completion: @escaping (Result, 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 diff --git a/samples/client/petstore/swift5/rxswiftLibrary/README.md b/samples/client/petstore/swift5/rxswiftLibrary/README.md index 9f8565335da9..f0b3abd84c07 100644 --- a/samples/client/petstore/swift5/rxswiftLibrary/README.md +++ b/samples/client/petstore/swift5/rxswiftLibrary/README.md @@ -140,6 +140,163 @@ Authentication schemes defined for the API: - **Type**: HTTP basic authentication +### How do I implement bearer token authentication with URLSession on the Swift 5 API client? + +First you subclass RequestBuilderFactory +``` +class BearerRequestBuilderFactory: RequestBuilderFactory { + func getNonDecodableBuilder() -> RequestBuilder.Type { + BearerRequestBuilder.self + } + + func getBuilder() -> RequestBuilder.Type { + BearerDecodableRequestBuilder.self + } +} +``` + +Then you subclass URLSessionRequestBuilder and URLSessionDecodableRequestBuilder +``` +class BearerRequestBuilder: URLSessionRequestBuilder { + @discardableResult + override func execute(_ apiResponseQueue: DispatchQueue = PetstoreClientAPI.apiResponseQueue, _ completion: @escaping (Result, 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: URLSessionDecodableRequestBuilder { + @discardableResult + override func execute(_ apiResponseQueue: DispatchQueue = PetstoreClientAPI.apiResponseQueue, _ completion: @escaping (Result, 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 diff --git a/samples/client/petstore/swift5/urlsessionLibrary/README.md b/samples/client/petstore/swift5/urlsessionLibrary/README.md index 9f8565335da9..f0b3abd84c07 100644 --- a/samples/client/petstore/swift5/urlsessionLibrary/README.md +++ b/samples/client/petstore/swift5/urlsessionLibrary/README.md @@ -140,6 +140,163 @@ Authentication schemes defined for the API: - **Type**: HTTP basic authentication +### How do I implement bearer token authentication with URLSession on the Swift 5 API client? + +First you subclass RequestBuilderFactory +``` +class BearerRequestBuilderFactory: RequestBuilderFactory { + func getNonDecodableBuilder() -> RequestBuilder.Type { + BearerRequestBuilder.self + } + + func getBuilder() -> RequestBuilder.Type { + BearerDecodableRequestBuilder.self + } +} +``` + +Then you subclass URLSessionRequestBuilder and URLSessionDecodableRequestBuilder +``` +class BearerRequestBuilder: URLSessionRequestBuilder { + @discardableResult + override func execute(_ apiResponseQueue: DispatchQueue = PetstoreClientAPI.apiResponseQueue, _ completion: @escaping (Result, 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: URLSessionDecodableRequestBuilder { + @discardableResult + override func execute(_ apiResponseQueue: DispatchQueue = PetstoreClientAPI.apiResponseQueue, _ completion: @escaping (Result, 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 diff --git a/samples/client/petstore/swift5/validation/README.md b/samples/client/petstore/swift5/validation/README.md index 5f7afab21352..432b470300ed 100644 --- a/samples/client/petstore/swift5/validation/README.md +++ b/samples/client/petstore/swift5/validation/README.md @@ -40,6 +40,163 @@ Class | Method | HTTP request | Description Endpoints do not require authorization. +### How do I implement bearer token authentication with URLSession on the Swift 5 API client? + +First you subclass RequestBuilderFactory +``` +class BearerRequestBuilderFactory: RequestBuilderFactory { + func getNonDecodableBuilder() -> RequestBuilder.Type { + BearerRequestBuilder.self + } + + func getBuilder() -> RequestBuilder.Type { + BearerDecodableRequestBuilder.self + } +} +``` + +Then you subclass URLSessionRequestBuilder and URLSessionDecodableRequestBuilder +``` +class BearerRequestBuilder: URLSessionRequestBuilder { + @discardableResult + override func execute(_ apiResponseQueue: DispatchQueue = PetstoreClientAPI.apiResponseQueue, _ completion: @escaping (Result, 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: URLSessionDecodableRequestBuilder { + @discardableResult + override func execute(_ apiResponseQueue: DispatchQueue = PetstoreClientAPI.apiResponseQueue, _ completion: @escaping (Result, 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 diff --git a/samples/client/petstore/swift5/vaporLibrary/README.md b/samples/client/petstore/swift5/vaporLibrary/README.md index 5810830738cb..db92a52b8c65 100644 --- a/samples/client/petstore/swift5/vaporLibrary/README.md +++ b/samples/client/petstore/swift5/vaporLibrary/README.md @@ -147,6 +147,7 @@ Authentication schemes defined for the API: - **Type**: HTTP basic authentication + ## Author diff --git a/samples/client/petstore/swift6/alamofireLibrary/README.md b/samples/client/petstore/swift6/alamofireLibrary/README.md index 25f3ad847445..65e6db79b583 100644 --- a/samples/client/petstore/swift6/alamofireLibrary/README.md +++ b/samples/client/petstore/swift6/alamofireLibrary/README.md @@ -140,6 +140,56 @@ Authentication schemes defined for the API: - **Type**: HTTP basic authentication +### How do I implement bearer token authentication with Alamofire on the Swift 6 API client? + +First implement the `Alamofire` `RequestInterceptor` protocol. +``` +class BearerTokenHandler: RequestInterceptor, @unchecked Sendable { + private var bearerToken: String? = nil + + func adapt(_ urlRequest: URLRequest, for session: Session, completion: @escaping (Result) -> 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 diff --git a/samples/client/petstore/swift6/alamofireLibrary/Sources/PetstoreClient/APIs/AnotherFakeAPI.swift b/samples/client/petstore/swift6/alamofireLibrary/Sources/PetstoreClient/APIs/AnotherFakeAPI.swift index 3ebeb738ae03..ad54ab52b727 100644 --- a/samples/client/petstore/swift6/alamofireLibrary/Sources/PetstoreClient/APIs/AnotherFakeAPI.swift +++ b/samples/client/petstore/swift6/alamofireLibrary/Sources/PetstoreClient/APIs/AnotherFakeAPI.swift @@ -33,7 +33,6 @@ open class AnotherFakeAPI { - PATCH /another-fake/dummy - To test special tags and operation ID starting with number - parameter body: (body) client model - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ diff --git a/samples/client/petstore/swift6/alamofireLibrary/Sources/PetstoreClient/APIs/FakeAPI.swift b/samples/client/petstore/swift6/alamofireLibrary/Sources/PetstoreClient/APIs/FakeAPI.swift index 95f1510e907d..40e7ae87fbd1 100644 --- a/samples/client/petstore/swift6/alamofireLibrary/Sources/PetstoreClient/APIs/FakeAPI.swift +++ b/samples/client/petstore/swift6/alamofireLibrary/Sources/PetstoreClient/APIs/FakeAPI.swift @@ -31,7 +31,6 @@ open class FakeAPI { - POST /fake/outer/boolean - Test serialization of outer boolean types - parameter body: (body) Input boolean as post body (optional) - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -75,7 +74,6 @@ open class FakeAPI { - POST /fake/outer/composite - Test serialization of object with outer number type - parameter body: (body) Input composite as post body (optional) - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -119,7 +117,6 @@ open class FakeAPI { - POST /fake/outer/number - Test serialization of outer number types - parameter body: (body) Input number as post body (optional) - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -163,7 +160,6 @@ open class FakeAPI { - POST /fake/outer/string - Test serialization of outer string types - parameter body: (body) Input string as post body (optional) - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -207,7 +203,6 @@ open class FakeAPI { - PUT /fake/body-with-file-schema - For this test, the body for this request much reference a schema named `File`. - parameter body: (body) - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -251,8 +246,7 @@ open class FakeAPI { /** - PUT /fake/body-with-query-params - parameter query: (query) - - parameter body: (body) - + - parameter body: (body) - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -301,7 +295,6 @@ open class FakeAPI { - PATCH /fake - To test \"client\" model - parameter body: (body) client model - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -363,20 +356,19 @@ open class FakeAPI { - type: http - name: http_basic_test - parameter number: (form) None - - parameter double: (form) None - - parameter patternWithoutDelimiter: (form) None - - parameter byte: (form) None - - parameter integer: (form) None (optional) - - parameter int32: (form) None (optional) - - parameter int64: (form) None (optional) - - parameter float: (form) None (optional) - - parameter string: (form) None (optional) - - parameter binary: (form) None (optional) - - parameter date: (form) None (optional) - - parameter dateTime: (form) None (optional) - - parameter password: (form) None (optional) - - parameter callback: (form) None (optional) - + - parameter double: (form) None + - parameter patternWithoutDelimiter: (form) None + - parameter byte: (form) None + - parameter integer: (form) None (optional) + - parameter int32: (form) None (optional) + - parameter int64: (form) None (optional) + - parameter float: (form) None (optional) + - parameter string: (form) None (optional) + - parameter binary: (form) None (optional) + - parameter date: (form) None (optional) + - parameter dateTime: (form) None (optional) + - parameter password: (form) None (optional) + - parameter callback: (form) None (optional) - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -514,14 +506,13 @@ open class FakeAPI { - GET /fake - To test enum parameters - parameter enumHeaderStringArray: (header) Header parameter enum test (string array) (optional) - - parameter enumHeaderString: (header) Header parameter enum test (string) (optional, default to .efg) - - parameter enumQueryStringArray: (query) Query parameter enum test (string array) (optional) - - parameter enumQueryString: (query) Query parameter enum test (string) (optional, default to .efg) - - parameter enumQueryInteger: (query) Query parameter enum test (double) (optional) - - parameter enumQueryDouble: (query) Query parameter enum test (double) (optional) - - parameter enumFormStringArray: (form) Form parameter enum test (string array) (optional, default to .dollar) - - parameter enumFormString: (form) Form parameter enum test (string) (optional, default to .efg) - + - parameter enumHeaderString: (header) Header parameter enum test (string) (optional, default to .efg) + - parameter enumQueryStringArray: (query) Query parameter enum test (string array) (optional) + - parameter enumQueryString: (query) Query parameter enum test (string) (optional, default to .efg) + - parameter enumQueryInteger: (query) Query parameter enum test (double) (optional) + - parameter enumQueryDouble: (query) Query parameter enum test (double) (optional) + - parameter enumFormStringArray: (form) Form parameter enum test (string array) (optional, default to .dollar) + - parameter enumFormString: (form) Form parameter enum test (string) (optional, default to .efg) - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -586,12 +577,11 @@ open class FakeAPI { - DELETE /fake - Fake endpoint to test group parameters (optional) - parameter requiredStringGroup: (query) Required String in group parameters - - parameter requiredBooleanGroup: (header) Required Boolean in group parameters - - parameter requiredInt64Group: (query) Required Integer in group parameters - - parameter stringGroup: (query) String in group parameters (optional) - - parameter booleanGroup: (header) Boolean in group parameters (optional) - - parameter int64Group: (query) Integer in group parameters (optional) - + - parameter requiredBooleanGroup: (header) Required Boolean in group parameters + - parameter requiredInt64Group: (query) Required Integer in group parameters + - parameter stringGroup: (query) String in group parameters (optional) + - parameter booleanGroup: (header) Boolean in group parameters (optional) + - parameter int64Group: (query) Integer in group parameters (optional) - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -643,7 +633,6 @@ open class FakeAPI { test inline additionalProperties - POST /fake/inline-additionalProperties - parameter param: (body) request body - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -689,8 +678,7 @@ open class FakeAPI { test json serialization of form data - GET /fake/jsonFormData - parameter param: (form) field1 - - parameter param2: (form) field2 - + - parameter param2: (form) field2 - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ diff --git a/samples/client/petstore/swift6/alamofireLibrary/Sources/PetstoreClient/APIs/FakeClassnameTags123API.swift b/samples/client/petstore/swift6/alamofireLibrary/Sources/PetstoreClient/APIs/FakeClassnameTags123API.swift index ef0c898b1f30..5d1433ef632d 100644 --- a/samples/client/petstore/swift6/alamofireLibrary/Sources/PetstoreClient/APIs/FakeClassnameTags123API.swift +++ b/samples/client/petstore/swift6/alamofireLibrary/Sources/PetstoreClient/APIs/FakeClassnameTags123API.swift @@ -36,7 +36,6 @@ open class FakeClassnameTags123API { - type: apiKey api_key_query (QUERY) - name: api_key_query - parameter body: (body) client model - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ diff --git a/samples/client/petstore/swift6/alamofireLibrary/Sources/PetstoreClient/APIs/PetAPI.swift b/samples/client/petstore/swift6/alamofireLibrary/Sources/PetstoreClient/APIs/PetAPI.swift index c8c4d01ec492..5d03cf93ff4e 100644 --- a/samples/client/petstore/swift6/alamofireLibrary/Sources/PetstoreClient/APIs/PetAPI.swift +++ b/samples/client/petstore/swift6/alamofireLibrary/Sources/PetstoreClient/APIs/PetAPI.swift @@ -38,7 +38,6 @@ open class PetAPI { - type: apiKey api_key_query (QUERY) - name: api_key_query - parameter body: (body) Pet object that needs to be added to the store - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -87,8 +86,7 @@ open class PetAPI { - type: oauth2 - name: petstore_auth - parameter petId: (path) Pet id to delete - - parameter apiKey: (header) (optional) - + - parameter apiKey: (header) (optional) - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -149,7 +147,6 @@ open class PetAPI { - type: oauth2 - name: petstore_auth - parameter status: (query) Status values that need to be considered for filter - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder<[Pet]> */ @@ -202,7 +199,6 @@ open class PetAPI { - type: oauth2 - name: petstore_auth - parameter tags: (query) Tags to filter by - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder<[Pet]> */ @@ -255,7 +251,6 @@ open class PetAPI { - type: apiKey api_key (HEADER) - name: api_key - parameter petId: (path) ID of pet to return - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -306,7 +301,6 @@ open class PetAPI { - type: oauth2 - name: petstore_auth - parameter body: (body) Pet object that needs to be added to the store - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -356,9 +350,8 @@ open class PetAPI { - type: oauth2 - name: petstore_auth - parameter petId: (path) ID of pet that needs to be updated - - parameter name: (form) Updated name of the pet (optional) - - parameter status: (form) Updated status of the pet (optional) - + - parameter name: (form) Updated name of the pet (optional) + - parameter status: (form) Updated status of the pet (optional) - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -417,9 +410,8 @@ open class PetAPI { - type: oauth2 - name: petstore_auth - parameter petId: (path) ID of pet to update - - parameter additionalMetadata: (form) Additional data to pass to server (optional) - - parameter file: (form) file to upload (optional) - + - parameter additionalMetadata: (form) Additional data to pass to server (optional) + - parameter file: (form) file to upload (optional) - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -478,9 +470,8 @@ open class PetAPI { - type: oauth2 - name: petstore_auth - parameter petId: (path) ID of pet to update - - parameter requiredFile: (form) file to upload - - parameter additionalMetadata: (form) Additional data to pass to server (optional) - + - parameter requiredFile: (form) file to upload + - parameter additionalMetadata: (form) Additional data to pass to server (optional) - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ diff --git a/samples/client/petstore/swift6/alamofireLibrary/Sources/PetstoreClient/APIs/StoreAPI.swift b/samples/client/petstore/swift6/alamofireLibrary/Sources/PetstoreClient/APIs/StoreAPI.swift index d35fd14c0907..69d16b42e3c8 100644 --- a/samples/client/petstore/swift6/alamofireLibrary/Sources/PetstoreClient/APIs/StoreAPI.swift +++ b/samples/client/petstore/swift6/alamofireLibrary/Sources/PetstoreClient/APIs/StoreAPI.swift @@ -33,7 +33,6 @@ open class StoreAPI { - DELETE /store/order/{order_id} - For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors - parameter orderId: (path) ID of the order that needs to be deleted - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -83,7 +82,6 @@ open class StoreAPI { - API Key: - type: apiKey api_key (HEADER) - name: api_key - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder<[String: Int]> */ @@ -129,7 +127,6 @@ open class StoreAPI { - GET /store/order/{order_id} - For valid response try integer IDs with value <= 5 or > 10. Other values will generate exceptions - parameter orderId: (path) ID of pet that needs to be fetched - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -177,7 +174,6 @@ open class StoreAPI { Place an order for a pet - POST /store/order - parameter body: (body) order placed for purchasing the pet - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ diff --git a/samples/client/petstore/swift6/alamofireLibrary/Sources/PetstoreClient/APIs/UserAPI.swift b/samples/client/petstore/swift6/alamofireLibrary/Sources/PetstoreClient/APIs/UserAPI.swift index b14a8eb251dc..5383d60d29b8 100644 --- a/samples/client/petstore/swift6/alamofireLibrary/Sources/PetstoreClient/APIs/UserAPI.swift +++ b/samples/client/petstore/swift6/alamofireLibrary/Sources/PetstoreClient/APIs/UserAPI.swift @@ -33,7 +33,6 @@ open class UserAPI { - POST /user - This can only be done by the logged in user. - parameter body: (body) Created user object - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -78,7 +77,6 @@ open class UserAPI { Creates list of users with given input array - POST /user/createWithArray - parameter body: (body) List of user object - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -123,7 +121,6 @@ open class UserAPI { Creates list of users with given input array - POST /user/createWithList - parameter body: (body) List of user object - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -169,7 +166,6 @@ open class UserAPI { - DELETE /user/{username} - This can only be done by the logged in user. - parameter username: (path) The name that needs to be deleted - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -217,7 +213,6 @@ open class UserAPI { Get user by user name - GET /user/{username} - parameter username: (path) The name that needs to be fetched. Use user1 for testing. - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -267,8 +262,7 @@ open class UserAPI { - GET /user/login - responseHeaders: [X-Rate-Limit(Int), X-Expires-After(Date)] - parameter username: (query) The user name for login - - parameter password: (query) The password for login in clear text - + - parameter password: (query) The password for login in clear text - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -315,7 +309,6 @@ open class UserAPI { /** Logs out current logged in user session - GET /user/logout - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -362,8 +355,7 @@ open class UserAPI { - PUT /user/{username} - This can only be done by the logged in user. - parameter username: (path) name that need to be deleted - - parameter body: (body) Updated user object - + - parameter body: (body) Updated user object - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ diff --git a/samples/client/petstore/swift6/apiNonStaticMethod/README.md b/samples/client/petstore/swift6/apiNonStaticMethod/README.md index 6db3a096d9f2..8c72d330a2ad 100644 --- a/samples/client/petstore/swift6/apiNonStaticMethod/README.md +++ b/samples/client/petstore/swift6/apiNonStaticMethod/README.md @@ -138,6 +138,56 @@ Authentication schemes defined for the API: - **Type**: HTTP basic authentication +### How do I implement bearer token authentication with Alamofire on the Swift 6 API client? + +First implement the `Alamofire` `RequestInterceptor` protocol. +``` +class BearerTokenHandler: RequestInterceptor, @unchecked Sendable { + private var bearerToken: String? = nil + + func adapt(_ urlRequest: URLRequest, for session: Session, completion: @escaping (Result) -> 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 diff --git a/samples/client/petstore/swift6/apiNonStaticMethod/Sources/PetstoreClient/APIs/AnotherFakeAPI.swift b/samples/client/petstore/swift6/apiNonStaticMethod/Sources/PetstoreClient/APIs/AnotherFakeAPI.swift index 4fbae86056a4..e833a6db629d 100644 --- a/samples/client/petstore/swift6/apiNonStaticMethod/Sources/PetstoreClient/APIs/AnotherFakeAPI.swift +++ b/samples/client/petstore/swift6/apiNonStaticMethod/Sources/PetstoreClient/APIs/AnotherFakeAPI.swift @@ -144,7 +144,6 @@ open class AnotherFakeAPI { - PATCH /another-fake/dummy - To test special tags and operation ID starting with number - parameter body: (body) client model - - returns: RequestBuilder */ open func call123testSpecialTagsWithRequestBuilder(body: Client) -> RequestBuilder { diff --git a/samples/client/petstore/swift6/apiNonStaticMethod/Sources/PetstoreClient/APIs/FakeAPI.swift b/samples/client/petstore/swift6/apiNonStaticMethod/Sources/PetstoreClient/APIs/FakeAPI.swift index e846df31d38d..8548c9d3e213 100644 --- a/samples/client/petstore/swift6/apiNonStaticMethod/Sources/PetstoreClient/APIs/FakeAPI.swift +++ b/samples/client/petstore/swift6/apiNonStaticMethod/Sources/PetstoreClient/APIs/FakeAPI.swift @@ -137,7 +137,6 @@ open class FakeAPI { - POST /fake/outer/boolean - Test serialization of outer boolean types - parameter body: (body) Input boolean as post body (optional) - - returns: RequestBuilder */ open func fakeOuterBooleanSerializeWithRequestBuilder(body: Bool? = nil) -> RequestBuilder { @@ -277,7 +276,6 @@ open class FakeAPI { - POST /fake/outer/composite - Test serialization of object with outer number type - parameter body: (body) Input composite as post body (optional) - - returns: RequestBuilder */ open func fakeOuterCompositeSerializeWithRequestBuilder(body: OuterComposite? = nil) -> RequestBuilder { @@ -417,7 +415,6 @@ open class FakeAPI { - POST /fake/outer/number - Test serialization of outer number types - parameter body: (body) Input number as post body (optional) - - returns: RequestBuilder */ open func fakeOuterNumberSerializeWithRequestBuilder(body: Double? = nil) -> RequestBuilder { @@ -557,7 +554,6 @@ open class FakeAPI { - POST /fake/outer/string - Test serialization of outer string types - parameter body: (body) Input string as post body (optional) - - returns: RequestBuilder */ open func fakeOuterStringSerializeWithRequestBuilder(body: String? = nil) -> RequestBuilder { @@ -697,7 +693,6 @@ open class FakeAPI { - PUT /fake/body-with-file-schema - For this test, the body for this request much reference a schema named `File`. - parameter body: (body) - - returns: RequestBuilder */ open func testBodyWithFileSchemaWithRequestBuilder(body: FileSchemaTestClass) -> RequestBuilder { @@ -842,8 +837,7 @@ open class FakeAPI { /** - PUT /fake/body-with-query-params - parameter query: (query) - - parameter body: (body) - + - parameter body: (body) - returns: RequestBuilder */ open func testBodyWithQueryParamsWithRequestBuilder(query: String, body: User) -> RequestBuilder { @@ -993,7 +987,6 @@ open class FakeAPI { - PATCH /fake - To test \"client\" model - parameter body: (body) client model - - returns: RequestBuilder */ open func testClientModelWithRequestBuilder(body: Client) -> RequestBuilder { @@ -1221,20 +1214,19 @@ open class FakeAPI { - type: http - name: http_basic_test - parameter number: (form) None - - parameter double: (form) None - - parameter patternWithoutDelimiter: (form) None - - parameter byte: (form) None - - parameter integer: (form) None (optional) - - parameter int32: (form) None (optional) - - parameter int64: (form) None (optional) - - parameter float: (form) None (optional) - - parameter string: (form) None (optional) - - parameter binary: (form) None (optional) - - parameter date: (form) None (optional) - - parameter dateTime: (form) None (optional) - - parameter password: (form) None (optional) - - parameter callback: (form) None (optional) - + - parameter double: (form) None + - parameter patternWithoutDelimiter: (form) None + - parameter byte: (form) None + - parameter integer: (form) None (optional) + - parameter int32: (form) None (optional) + - parameter int64: (form) None (optional) + - parameter float: (form) None (optional) + - parameter string: (form) None (optional) + - parameter binary: (form) None (optional) + - parameter date: (form) None (optional) + - parameter dateTime: (form) None (optional) + - parameter password: (form) None (optional) + - parameter callback: (form) None (optional) - returns: RequestBuilder */ open func testEndpointParametersWithRequestBuilder(number: Double, double: Double, patternWithoutDelimiter: String, byte: Data, integer: Int? = nil, int32: Int? = nil, int64: Int64? = nil, float: Float? = nil, string: String? = nil, binary: Data? = nil, date: Date? = nil, dateTime: Date? = nil, password: String? = nil, callback: String? = nil) -> RequestBuilder { @@ -1508,14 +1500,13 @@ open class FakeAPI { - GET /fake - To test enum parameters - parameter enumHeaderStringArray: (header) Header parameter enum test (string array) (optional) - - parameter enumHeaderString: (header) Header parameter enum test (string) (optional, default to .efg) - - parameter enumQueryStringArray: (query) Query parameter enum test (string array) (optional) - - parameter enumQueryString: (query) Query parameter enum test (string) (optional, default to .efg) - - parameter enumQueryInteger: (query) Query parameter enum test (double) (optional) - - parameter enumQueryDouble: (query) Query parameter enum test (double) (optional) - - parameter enumFormStringArray: (form) Form parameter enum test (string array) (optional, default to .dollar) - - parameter enumFormString: (form) Form parameter enum test (string) (optional, default to .efg) - + - parameter enumHeaderString: (header) Header parameter enum test (string) (optional, default to .efg) + - parameter enumQueryStringArray: (query) Query parameter enum test (string array) (optional) + - parameter enumQueryString: (query) Query parameter enum test (string) (optional, default to .efg) + - parameter enumQueryInteger: (query) Query parameter enum test (double) (optional) + - parameter enumQueryDouble: (query) Query parameter enum test (double) (optional) + - parameter enumFormStringArray: (form) Form parameter enum test (string array) (optional, default to .dollar) + - parameter enumFormString: (form) Form parameter enum test (string) (optional, default to .efg) - returns: RequestBuilder */ open func testEnumParametersWithRequestBuilder(enumHeaderStringArray: [EnumHeaderStringArray_testEnumParameters]? = nil, enumHeaderString: EnumHeaderString_testEnumParameters? = nil, enumQueryStringArray: [EnumQueryStringArray_testEnumParameters]? = nil, enumQueryString: EnumQueryString_testEnumParameters? = nil, enumQueryInteger: EnumQueryInteger_testEnumParameters? = nil, enumQueryDouble: EnumQueryDouble_testEnumParameters? = nil, enumFormStringArray: [EnumFormStringArray_testEnumParameters]? = nil, enumFormString: EnumFormString_testEnumParameters? = nil) -> RequestBuilder { @@ -1706,12 +1697,11 @@ open class FakeAPI { - DELETE /fake - Fake endpoint to test group parameters (optional) - parameter requiredStringGroup: (query) Required String in group parameters - - parameter requiredBooleanGroup: (header) Required Boolean in group parameters - - parameter requiredInt64Group: (query) Required Integer in group parameters - - parameter stringGroup: (query) String in group parameters (optional) - - parameter booleanGroup: (header) Boolean in group parameters (optional) - - parameter int64Group: (query) Integer in group parameters (optional) - + - parameter requiredBooleanGroup: (header) Required Boolean in group parameters + - parameter requiredInt64Group: (query) Required Integer in group parameters + - parameter stringGroup: (query) String in group parameters (optional) + - parameter booleanGroup: (header) Boolean in group parameters (optional) + - parameter int64Group: (query) Integer in group parameters (optional) - returns: RequestBuilder */ open func testGroupParametersWithRequestBuilder(requiredStringGroup: Int, requiredBooleanGroup: Bool, requiredInt64Group: Int64, stringGroup: Int? = nil, booleanGroup: Bool? = nil, int64Group: Int64? = nil) -> RequestBuilder { @@ -1864,7 +1854,6 @@ open class FakeAPI { test inline additionalProperties - POST /fake/inline-additionalProperties - parameter param: (body) request body - - returns: RequestBuilder */ open func testInlineAdditionalPropertiesWithRequestBuilder(param: [String: String]) -> RequestBuilder { @@ -2016,8 +2005,7 @@ open class FakeAPI { test json serialization of form data - GET /fake/jsonFormData - parameter param: (form) field1 - - parameter param2: (form) field2 - + - parameter param2: (form) field2 - returns: RequestBuilder */ open func testJsonFormDataWithRequestBuilder(param: String, param2: String) -> RequestBuilder { diff --git a/samples/client/petstore/swift6/apiNonStaticMethod/Sources/PetstoreClient/APIs/FakeClassnameTags123API.swift b/samples/client/petstore/swift6/apiNonStaticMethod/Sources/PetstoreClient/APIs/FakeClassnameTags123API.swift index 399468da170b..371d6b4421c9 100644 --- a/samples/client/petstore/swift6/apiNonStaticMethod/Sources/PetstoreClient/APIs/FakeClassnameTags123API.swift +++ b/samples/client/petstore/swift6/apiNonStaticMethod/Sources/PetstoreClient/APIs/FakeClassnameTags123API.swift @@ -147,7 +147,6 @@ open class FakeClassnameTags123API { - type: apiKey api_key_query (QUERY) - name: api_key_query - parameter body: (body) client model - - returns: RequestBuilder */ open func testClassnameWithRequestBuilder(body: Client) -> RequestBuilder { diff --git a/samples/client/petstore/swift6/apiNonStaticMethod/Sources/PetstoreClient/APIs/PetAPI.swift b/samples/client/petstore/swift6/apiNonStaticMethod/Sources/PetstoreClient/APIs/PetAPI.swift index 208d8d4de221..61cd0b04916b 100644 --- a/samples/client/petstore/swift6/apiNonStaticMethod/Sources/PetstoreClient/APIs/PetAPI.swift +++ b/samples/client/petstore/swift6/apiNonStaticMethod/Sources/PetstoreClient/APIs/PetAPI.swift @@ -149,7 +149,6 @@ open class PetAPI { - type: apiKey api_key_query (QUERY) - name: api_key_query - parameter body: (body) Pet object that needs to be added to the store - - returns: RequestBuilder */ open func addPetWithRequestBuilder(body: Pet) -> RequestBuilder { @@ -304,8 +303,7 @@ open class PetAPI { - type: oauth2 - name: petstore_auth - parameter petId: (path) Pet id to delete - - parameter apiKey: (header) (optional) - + - parameter apiKey: (header) (optional) - returns: RequestBuilder */ open func deletePetWithRequestBuilder(petId: Int64, apiKey: String? = nil) -> RequestBuilder { @@ -467,7 +465,6 @@ open class PetAPI { - type: oauth2 - name: petstore_auth - parameter status: (query) Status values that need to be considered for filter - - returns: RequestBuilder<[Pet]> */ open func findPetsByStatusWithRequestBuilder(status: [Status_findPetsByStatus]) -> RequestBuilder<[Pet]> { @@ -626,7 +623,6 @@ open class PetAPI { - type: oauth2 - name: petstore_auth - parameter tags: (query) Tags to filter by - - returns: RequestBuilder<[Pet]> */ @available(*, deprecated, message: "This operation is deprecated.") @@ -780,7 +776,6 @@ open class PetAPI { - type: apiKey api_key (HEADER) - name: api_key - parameter petId: (path) ID of pet to return - - returns: RequestBuilder */ open func getPetByIdWithRequestBuilder(petId: Int64) -> RequestBuilder { @@ -932,7 +927,6 @@ open class PetAPI { - type: oauth2 - name: petstore_auth - parameter body: (body) Pet object that needs to be added to the store - - returns: RequestBuilder */ open func updatePetWithRequestBuilder(body: Pet) -> RequestBuilder { @@ -1093,9 +1087,8 @@ open class PetAPI { - type: oauth2 - name: petstore_auth - parameter petId: (path) ID of pet that needs to be updated - - parameter name: (form) Updated name of the pet (optional) - - parameter status: (form) Updated status of the pet (optional) - + - parameter name: (form) Updated name of the pet (optional) + - parameter status: (form) Updated status of the pet (optional) - returns: RequestBuilder */ open func updatePetWithFormWithRequestBuilder(petId: Int64, name: String? = nil, status: String? = nil) -> RequestBuilder { @@ -1265,9 +1258,8 @@ open class PetAPI { - type: oauth2 - name: petstore_auth - parameter petId: (path) ID of pet to update - - parameter additionalMetadata: (form) Additional data to pass to server (optional) - - parameter file: (form) file to upload (optional) - + - parameter additionalMetadata: (form) Additional data to pass to server (optional) + - parameter file: (form) file to upload (optional) - returns: RequestBuilder */ open func uploadFileWithRequestBuilder(petId: Int64, additionalMetadata: String? = nil, file: Data? = nil) -> RequestBuilder { @@ -1437,9 +1429,8 @@ open class PetAPI { - type: oauth2 - name: petstore_auth - parameter petId: (path) ID of pet to update - - parameter requiredFile: (form) file to upload - - parameter additionalMetadata: (form) Additional data to pass to server (optional) - + - parameter requiredFile: (form) file to upload + - parameter additionalMetadata: (form) Additional data to pass to server (optional) - returns: RequestBuilder */ open func uploadFileWithRequiredFileWithRequestBuilder(petId: Int64, requiredFile: Data, additionalMetadata: String? = nil) -> RequestBuilder { diff --git a/samples/client/petstore/swift6/apiNonStaticMethod/Sources/PetstoreClient/APIs/StoreAPI.swift b/samples/client/petstore/swift6/apiNonStaticMethod/Sources/PetstoreClient/APIs/StoreAPI.swift index 9cabfec8135b..66868cb89f13 100644 --- a/samples/client/petstore/swift6/apiNonStaticMethod/Sources/PetstoreClient/APIs/StoreAPI.swift +++ b/samples/client/petstore/swift6/apiNonStaticMethod/Sources/PetstoreClient/APIs/StoreAPI.swift @@ -144,7 +144,6 @@ open class StoreAPI { - DELETE /store/order/{order_id} - For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors - parameter orderId: (path) ID of the order that needs to be deleted - - returns: RequestBuilder */ open func deleteOrderWithRequestBuilder(orderId: String) -> RequestBuilder { @@ -290,7 +289,6 @@ open class StoreAPI { - API Key: - type: apiKey api_key (HEADER) - name: api_key - - returns: RequestBuilder<[String: Int]> */ open func getInventoryWithRequestBuilder() -> RequestBuilder<[String: Int]> { @@ -437,7 +435,6 @@ open class StoreAPI { - GET /store/order/{order_id} - For valid response try integer IDs with value <= 5 or > 10. Other values will generate exceptions - parameter orderId: (path) ID of pet that needs to be fetched - - returns: RequestBuilder */ open func getOrderByIdWithRequestBuilder(orderId: Int64) -> RequestBuilder { @@ -586,7 +583,6 @@ open class StoreAPI { Place an order for a pet - POST /store/order - parameter body: (body) order placed for purchasing the pet - - returns: RequestBuilder */ open func placeOrderWithRequestBuilder(body: Order) -> RequestBuilder { diff --git a/samples/client/petstore/swift6/apiNonStaticMethod/Sources/PetstoreClient/APIs/UserAPI.swift b/samples/client/petstore/swift6/apiNonStaticMethod/Sources/PetstoreClient/APIs/UserAPI.swift index e12157a6d7d9..4bb1fbdb5161 100644 --- a/samples/client/petstore/swift6/apiNonStaticMethod/Sources/PetstoreClient/APIs/UserAPI.swift +++ b/samples/client/petstore/swift6/apiNonStaticMethod/Sources/PetstoreClient/APIs/UserAPI.swift @@ -144,7 +144,6 @@ open class UserAPI { - POST /user - This can only be done by the logged in user. - parameter body: (body) Created user object - - returns: RequestBuilder */ open func createUserWithRequestBuilder(body: User) -> RequestBuilder { @@ -290,7 +289,6 @@ open class UserAPI { Creates list of users with given input array - POST /user/createWithArray - parameter body: (body) List of user object - - returns: RequestBuilder */ open func createUsersWithArrayInputWithRequestBuilder(body: [User]) -> RequestBuilder { @@ -436,7 +434,6 @@ open class UserAPI { Creates list of users with given input array - POST /user/createWithList - parameter body: (body) List of user object - - returns: RequestBuilder */ open func createUsersWithListInputWithRequestBuilder(body: [User]) -> RequestBuilder { @@ -583,7 +580,6 @@ open class UserAPI { - DELETE /user/{username} - This can only be done by the logged in user. - parameter username: (path) The name that needs to be deleted - - returns: RequestBuilder */ open func deleteUserWithRequestBuilder(username: String) -> RequestBuilder { @@ -732,7 +728,6 @@ open class UserAPI { Get user by user name - GET /user/{username} - parameter username: (path) The name that needs to be fetched. Use user1 for testing. - - returns: RequestBuilder */ open func getUserByNameWithRequestBuilder(username: String) -> RequestBuilder { @@ -888,8 +883,7 @@ open class UserAPI { - GET /user/login - responseHeaders: [X-Rate-Limit(Int), X-Expires-After(Date)] - parameter username: (query) The user name for login - - parameter password: (query) The password for login in clear text - + - parameter password: (query) The password for login in clear text - returns: RequestBuilder */ open func loginUserWithRequestBuilder(username: String, password: String) -> RequestBuilder { @@ -1032,7 +1026,6 @@ open class UserAPI { /** Logs out current logged in user session - GET /user/logout - - returns: RequestBuilder */ open func logoutUserWithRequestBuilder() -> RequestBuilder { @@ -1185,8 +1178,7 @@ open class UserAPI { - PUT /user/{username} - This can only be done by the logged in user. - parameter username: (path) name that need to be deleted - - parameter body: (body) Updated user object - + - parameter body: (body) Updated user object - returns: RequestBuilder */ open func updateUserWithRequestBuilder(username: String, body: User) -> RequestBuilder { diff --git a/samples/client/petstore/swift6/asyncAwaitLibrary/README.md b/samples/client/petstore/swift6/asyncAwaitLibrary/README.md index 25f3ad847445..0b9710436990 100644 --- a/samples/client/petstore/swift6/asyncAwaitLibrary/README.md +++ b/samples/client/petstore/swift6/asyncAwaitLibrary/README.md @@ -140,6 +140,89 @@ Authentication schemes defined for the API: - **Type**: HTTP basic authentication +### How do I implement bearer token authentication with URLSession on the Swift 6 API client? + +First you implement the `OpenAPIInterceptor` protocol. +``` +public class BearerOpenAPIInterceptor: OpenAPIInterceptor { + public init() {} + + public func intercept(urlRequest: URLRequest, urlSession: URLSessionProtocol, openAPIClient: OpenAPIClient, completion: @escaping (Result) -> 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 diff --git a/samples/client/petstore/swift6/asyncAwaitLibrary/Sources/PetstoreClient/APIs/AnotherFakeAPI.swift b/samples/client/petstore/swift6/asyncAwaitLibrary/Sources/PetstoreClient/APIs/AnotherFakeAPI.swift index 0b126ab8c36f..0862742c75e6 100644 --- a/samples/client/petstore/swift6/asyncAwaitLibrary/Sources/PetstoreClient/APIs/AnotherFakeAPI.swift +++ b/samples/client/petstore/swift6/asyncAwaitLibrary/Sources/PetstoreClient/APIs/AnotherFakeAPI.swift @@ -26,7 +26,6 @@ open class AnotherFakeAPI { - PATCH /another-fake/dummy - To test special tags and operation ID starting with number - parameter body: (body) client model - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ diff --git a/samples/client/petstore/swift6/asyncAwaitLibrary/Sources/PetstoreClient/APIs/FakeAPI.swift b/samples/client/petstore/swift6/asyncAwaitLibrary/Sources/PetstoreClient/APIs/FakeAPI.swift index cee6a25aab64..064e28b98ca6 100644 --- a/samples/client/petstore/swift6/asyncAwaitLibrary/Sources/PetstoreClient/APIs/FakeAPI.swift +++ b/samples/client/petstore/swift6/asyncAwaitLibrary/Sources/PetstoreClient/APIs/FakeAPI.swift @@ -24,7 +24,6 @@ open class FakeAPI { - POST /fake/outer/boolean - Test serialization of outer boolean types - parameter body: (body) Input boolean as post body (optional) - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -61,7 +60,6 @@ open class FakeAPI { - POST /fake/outer/composite - Test serialization of object with outer number type - parameter body: (body) Input composite as post body (optional) - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -98,7 +96,6 @@ open class FakeAPI { - POST /fake/outer/number - Test serialization of outer number types - parameter body: (body) Input number as post body (optional) - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -135,7 +132,6 @@ open class FakeAPI { - POST /fake/outer/string - Test serialization of outer string types - parameter body: (body) Input string as post body (optional) - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -172,7 +168,6 @@ open class FakeAPI { - PUT /fake/body-with-file-schema - For this test, the body for this request much reference a schema named `File`. - parameter body: (body) - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -209,8 +204,7 @@ open class FakeAPI { /** - PUT /fake/body-with-query-params - parameter query: (query) - - parameter body: (body) - + - parameter body: (body) - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -252,7 +246,6 @@ open class FakeAPI { - PATCH /fake - To test \"client\" model - parameter body: (body) client model - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -307,20 +300,19 @@ open class FakeAPI { - type: http - name: http_basic_test - parameter number: (form) None - - parameter double: (form) None - - parameter patternWithoutDelimiter: (form) None - - parameter byte: (form) None - - parameter integer: (form) None (optional) - - parameter int32: (form) None (optional) - - parameter int64: (form) None (optional) - - parameter float: (form) None (optional) - - parameter string: (form) None (optional) - - parameter binary: (form) None (optional) - - parameter date: (form) None (optional) - - parameter dateTime: (form) None (optional) - - parameter password: (form) None (optional) - - parameter callback: (form) None (optional) - + - parameter double: (form) None + - parameter patternWithoutDelimiter: (form) None + - parameter byte: (form) None + - parameter integer: (form) None (optional) + - parameter int32: (form) None (optional) + - parameter int64: (form) None (optional) + - parameter float: (form) None (optional) + - parameter string: (form) None (optional) + - parameter binary: (form) None (optional) + - parameter date: (form) None (optional) + - parameter dateTime: (form) None (optional) + - parameter password: (form) None (optional) + - parameter callback: (form) None (optional) - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -451,14 +443,13 @@ open class FakeAPI { - GET /fake - To test enum parameters - parameter enumHeaderStringArray: (header) Header parameter enum test (string array) (optional) - - parameter enumHeaderString: (header) Header parameter enum test (string) (optional, default to .efg) - - parameter enumQueryStringArray: (query) Query parameter enum test (string array) (optional) - - parameter enumQueryString: (query) Query parameter enum test (string) (optional, default to .efg) - - parameter enumQueryInteger: (query) Query parameter enum test (double) (optional) - - parameter enumQueryDouble: (query) Query parameter enum test (double) (optional) - - parameter enumFormStringArray: (form) Form parameter enum test (string array) (optional, default to .dollar) - - parameter enumFormString: (form) Form parameter enum test (string) (optional, default to .efg) - + - parameter enumHeaderString: (header) Header parameter enum test (string) (optional, default to .efg) + - parameter enumQueryStringArray: (query) Query parameter enum test (string array) (optional) + - parameter enumQueryString: (query) Query parameter enum test (string) (optional, default to .efg) + - parameter enumQueryInteger: (query) Query parameter enum test (double) (optional) + - parameter enumQueryDouble: (query) Query parameter enum test (double) (optional) + - parameter enumFormStringArray: (form) Form parameter enum test (string array) (optional, default to .dollar) + - parameter enumFormString: (form) Form parameter enum test (string) (optional, default to .efg) - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -516,12 +507,11 @@ open class FakeAPI { - DELETE /fake - Fake endpoint to test group parameters (optional) - parameter requiredStringGroup: (query) Required String in group parameters - - parameter requiredBooleanGroup: (header) Required Boolean in group parameters - - parameter requiredInt64Group: (query) Required Integer in group parameters - - parameter stringGroup: (query) String in group parameters (optional) - - parameter booleanGroup: (header) Boolean in group parameters (optional) - - parameter int64Group: (query) Integer in group parameters (optional) - + - parameter requiredBooleanGroup: (header) Required Boolean in group parameters + - parameter requiredInt64Group: (query) Required Integer in group parameters + - parameter stringGroup: (query) String in group parameters (optional) + - parameter booleanGroup: (header) Boolean in group parameters (optional) + - parameter int64Group: (query) Integer in group parameters (optional) - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -566,7 +556,6 @@ open class FakeAPI { test inline additionalProperties - POST /fake/inline-additionalProperties - parameter param: (body) request body - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -605,8 +594,7 @@ open class FakeAPI { test json serialization of form data - GET /fake/jsonFormData - parameter param: (form) field1 - - parameter param2: (form) field2 - + - parameter param2: (form) field2 - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ diff --git a/samples/client/petstore/swift6/asyncAwaitLibrary/Sources/PetstoreClient/APIs/FakeClassnameTags123API.swift b/samples/client/petstore/swift6/asyncAwaitLibrary/Sources/PetstoreClient/APIs/FakeClassnameTags123API.swift index e311db6721c6..1ea172c5e854 100644 --- a/samples/client/petstore/swift6/asyncAwaitLibrary/Sources/PetstoreClient/APIs/FakeClassnameTags123API.swift +++ b/samples/client/petstore/swift6/asyncAwaitLibrary/Sources/PetstoreClient/APIs/FakeClassnameTags123API.swift @@ -29,7 +29,6 @@ open class FakeClassnameTags123API { - type: apiKey api_key_query (QUERY) - name: api_key_query - parameter body: (body) client model - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ diff --git a/samples/client/petstore/swift6/asyncAwaitLibrary/Sources/PetstoreClient/APIs/PetAPI.swift b/samples/client/petstore/swift6/asyncAwaitLibrary/Sources/PetstoreClient/APIs/PetAPI.swift index 85e402b67525..4cb91830b4dd 100644 --- a/samples/client/petstore/swift6/asyncAwaitLibrary/Sources/PetstoreClient/APIs/PetAPI.swift +++ b/samples/client/petstore/swift6/asyncAwaitLibrary/Sources/PetstoreClient/APIs/PetAPI.swift @@ -31,7 +31,6 @@ open class PetAPI { - type: apiKey api_key_query (QUERY) - name: api_key_query - parameter body: (body) Pet object that needs to be added to the store - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -73,8 +72,7 @@ open class PetAPI { - type: oauth2 - name: petstore_auth - parameter petId: (path) Pet id to delete - - parameter apiKey: (header) (optional) - + - parameter apiKey: (header) (optional) - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -128,7 +126,6 @@ open class PetAPI { - type: oauth2 - name: petstore_auth - parameter status: (query) Status values that need to be considered for filter - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder<[Pet]> */ @@ -174,7 +171,6 @@ open class PetAPI { - type: oauth2 - name: petstore_auth - parameter tags: (query) Tags to filter by - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder<[Pet]> */ @@ -220,7 +216,6 @@ open class PetAPI { - type: apiKey api_key (HEADER) - name: api_key - parameter petId: (path) ID of pet to return - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -264,7 +259,6 @@ open class PetAPI { - type: oauth2 - name: petstore_auth - parameter body: (body) Pet object that needs to be added to the store - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -307,9 +301,8 @@ open class PetAPI { - type: oauth2 - name: petstore_auth - parameter petId: (path) ID of pet that needs to be updated - - parameter name: (form) Updated name of the pet (optional) - - parameter status: (form) Updated status of the pet (optional) - + - parameter name: (form) Updated name of the pet (optional) + - parameter status: (form) Updated status of the pet (optional) - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -361,9 +354,8 @@ open class PetAPI { - type: oauth2 - name: petstore_auth - parameter petId: (path) ID of pet to update - - parameter additionalMetadata: (form) Additional data to pass to server (optional) - - parameter file: (form) file to upload (optional) - + - parameter additionalMetadata: (form) Additional data to pass to server (optional) + - parameter file: (form) file to upload (optional) - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -415,9 +407,8 @@ open class PetAPI { - type: oauth2 - name: petstore_auth - parameter petId: (path) ID of pet to update - - parameter requiredFile: (form) file to upload - - parameter additionalMetadata: (form) Additional data to pass to server (optional) - + - parameter requiredFile: (form) file to upload + - parameter additionalMetadata: (form) Additional data to pass to server (optional) - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ diff --git a/samples/client/petstore/swift6/asyncAwaitLibrary/Sources/PetstoreClient/APIs/StoreAPI.swift b/samples/client/petstore/swift6/asyncAwaitLibrary/Sources/PetstoreClient/APIs/StoreAPI.swift index 783666b1a695..db645dd19a91 100644 --- a/samples/client/petstore/swift6/asyncAwaitLibrary/Sources/PetstoreClient/APIs/StoreAPI.swift +++ b/samples/client/petstore/swift6/asyncAwaitLibrary/Sources/PetstoreClient/APIs/StoreAPI.swift @@ -26,7 +26,6 @@ open class StoreAPI { - DELETE /store/order/{order_id} - For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors - parameter orderId: (path) ID of the order that needs to be deleted - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -69,7 +68,6 @@ open class StoreAPI { - API Key: - type: apiKey api_key (HEADER) - name: api_key - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder<[String: Int]> */ @@ -108,7 +106,6 @@ open class StoreAPI { - GET /store/order/{order_id} - For valid response try integer IDs with value <= 5 or > 10. Other values will generate exceptions - parameter orderId: (path) ID of pet that needs to be fetched - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -149,7 +146,6 @@ open class StoreAPI { Place an order for a pet - POST /store/order - parameter body: (body) order placed for purchasing the pet - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ diff --git a/samples/client/petstore/swift6/asyncAwaitLibrary/Sources/PetstoreClient/APIs/UserAPI.swift b/samples/client/petstore/swift6/asyncAwaitLibrary/Sources/PetstoreClient/APIs/UserAPI.swift index c4ec09e3d0e7..76a300f7840c 100644 --- a/samples/client/petstore/swift6/asyncAwaitLibrary/Sources/PetstoreClient/APIs/UserAPI.swift +++ b/samples/client/petstore/swift6/asyncAwaitLibrary/Sources/PetstoreClient/APIs/UserAPI.swift @@ -26,7 +26,6 @@ open class UserAPI { - POST /user - This can only be done by the logged in user. - parameter body: (body) Created user object - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -64,7 +63,6 @@ open class UserAPI { Creates list of users with given input array - POST /user/createWithArray - parameter body: (body) List of user object - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -102,7 +100,6 @@ open class UserAPI { Creates list of users with given input array - POST /user/createWithList - parameter body: (body) List of user object - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -141,7 +138,6 @@ open class UserAPI { - DELETE /user/{username} - This can only be done by the logged in user. - parameter username: (path) The name that needs to be deleted - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -182,7 +178,6 @@ open class UserAPI { Get user by user name - GET /user/{username} - parameter username: (path) The name that needs to be fetched. Use user1 for testing. - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -225,8 +220,7 @@ open class UserAPI { - GET /user/login - responseHeaders: [X-Rate-Limit(Int), X-Expires-After(Date)] - parameter username: (query) The user name for login - - parameter password: (query) The password for login in clear text - + - parameter password: (query) The password for login in clear text - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -266,7 +260,6 @@ open class UserAPI { /** Logs out current logged in user session - GET /user/logout - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -306,8 +299,7 @@ open class UserAPI { - PUT /user/{username} - This can only be done by the logged in user. - parameter username: (path) name that need to be deleted - - parameter body: (body) Updated user object - + - parameter body: (body) Updated user object - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ diff --git a/samples/client/petstore/swift6/combineDeferredLibrary/PetstoreClient/Classes/OpenAPIs/APIs/AnotherFakeAPI.swift b/samples/client/petstore/swift6/combineDeferredLibrary/PetstoreClient/Classes/OpenAPIs/APIs/AnotherFakeAPI.swift index a37c8c6230e2..f603d527d622 100644 --- a/samples/client/petstore/swift6/combineDeferredLibrary/PetstoreClient/Classes/OpenAPIs/APIs/AnotherFakeAPI.swift +++ b/samples/client/petstore/swift6/combineDeferredLibrary/PetstoreClient/Classes/OpenAPIs/APIs/AnotherFakeAPI.swift @@ -49,7 +49,6 @@ open class AnotherFakeAPI { - PATCH /another-fake/dummy - To test special tags and operation ID starting with number - parameter body: (body) client model - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ diff --git a/samples/client/petstore/swift6/combineDeferredLibrary/PetstoreClient/Classes/OpenAPIs/APIs/FakeAPI.swift b/samples/client/petstore/swift6/combineDeferredLibrary/PetstoreClient/Classes/OpenAPIs/APIs/FakeAPI.swift index 9cd690a8e2d4..349d7fc51c25 100644 --- a/samples/client/petstore/swift6/combineDeferredLibrary/PetstoreClient/Classes/OpenAPIs/APIs/FakeAPI.swift +++ b/samples/client/petstore/swift6/combineDeferredLibrary/PetstoreClient/Classes/OpenAPIs/APIs/FakeAPI.swift @@ -47,7 +47,6 @@ open class FakeAPI { - POST /fake/outer/boolean - Test serialization of outer boolean types - parameter body: (body) Input boolean as post body (optional) - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -104,7 +103,6 @@ open class FakeAPI { - POST /fake/outer/composite - Test serialization of object with outer number type - parameter body: (body) Input composite as post body (optional) - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -161,7 +159,6 @@ open class FakeAPI { - POST /fake/outer/number - Test serialization of outer number types - parameter body: (body) Input number as post body (optional) - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -218,7 +215,6 @@ open class FakeAPI { - POST /fake/outer/string - Test serialization of outer string types - parameter body: (body) Input string as post body (optional) - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -275,7 +271,6 @@ open class FakeAPI { - PUT /fake/body-with-file-schema - For this test, the body for this request much reference a schema named `File`. - parameter body: (body) - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -332,8 +327,7 @@ open class FakeAPI { /** - PUT /fake/body-with-query-params - parameter query: (query) - - parameter body: (body) - + - parameter body: (body) - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -395,7 +389,6 @@ open class FakeAPI { - PATCH /fake - To test \"client\" model - parameter body: (body) client model - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -470,20 +463,19 @@ open class FakeAPI { - type: http - name: http_basic_test - parameter number: (form) None - - parameter double: (form) None - - parameter patternWithoutDelimiter: (form) None - - parameter byte: (form) None - - parameter integer: (form) None (optional) - - parameter int32: (form) None (optional) - - parameter int64: (form) None (optional) - - parameter float: (form) None (optional) - - parameter string: (form) None (optional) - - parameter binary: (form) None (optional) - - parameter date: (form) None (optional) - - parameter dateTime: (form) None (optional) - - parameter password: (form) None (optional) - - parameter callback: (form) None (optional) - + - parameter double: (form) None + - parameter patternWithoutDelimiter: (form) None + - parameter byte: (form) None + - parameter integer: (form) None (optional) + - parameter int32: (form) None (optional) + - parameter int64: (form) None (optional) + - parameter float: (form) None (optional) + - parameter string: (form) None (optional) + - parameter binary: (form) None (optional) + - parameter date: (form) None (optional) + - parameter dateTime: (form) None (optional) + - parameter password: (form) None (optional) + - parameter callback: (form) None (optional) - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -634,14 +626,13 @@ open class FakeAPI { - GET /fake - To test enum parameters - parameter enumHeaderStringArray: (header) Header parameter enum test (string array) (optional) - - parameter enumHeaderString: (header) Header parameter enum test (string) (optional, default to .efg) - - parameter enumQueryStringArray: (query) Query parameter enum test (string array) (optional) - - parameter enumQueryString: (query) Query parameter enum test (string) (optional, default to .efg) - - parameter enumQueryInteger: (query) Query parameter enum test (double) (optional) - - parameter enumQueryDouble: (query) Query parameter enum test (double) (optional) - - parameter enumFormStringArray: (form) Form parameter enum test (string array) (optional, default to .dollar) - - parameter enumFormString: (form) Form parameter enum test (string) (optional, default to .efg) - + - parameter enumHeaderString: (header) Header parameter enum test (string) (optional, default to .efg) + - parameter enumQueryStringArray: (query) Query parameter enum test (string array) (optional) + - parameter enumQueryString: (query) Query parameter enum test (string) (optional, default to .efg) + - parameter enumQueryInteger: (query) Query parameter enum test (double) (optional) + - parameter enumQueryDouble: (query) Query parameter enum test (double) (optional) + - parameter enumFormStringArray: (form) Form parameter enum test (string array) (optional, default to .dollar) + - parameter enumFormString: (form) Form parameter enum test (string) (optional, default to .efg) - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -719,12 +710,11 @@ open class FakeAPI { - DELETE /fake - Fake endpoint to test group parameters (optional) - parameter requiredStringGroup: (query) Required String in group parameters - - parameter requiredBooleanGroup: (header) Required Boolean in group parameters - - parameter requiredInt64Group: (query) Required Integer in group parameters - - parameter stringGroup: (query) String in group parameters (optional) - - parameter booleanGroup: (header) Boolean in group parameters (optional) - - parameter int64Group: (query) Integer in group parameters (optional) - + - parameter requiredBooleanGroup: (header) Required Boolean in group parameters + - parameter requiredInt64Group: (query) Required Integer in group parameters + - parameter stringGroup: (query) String in group parameters (optional) + - parameter booleanGroup: (header) Boolean in group parameters (optional) + - parameter int64Group: (query) Integer in group parameters (optional) - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -789,7 +779,6 @@ open class FakeAPI { test inline additionalProperties - POST /fake/inline-additionalProperties - parameter param: (body) request body - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -848,8 +837,7 @@ open class FakeAPI { test json serialization of form data - GET /fake/jsonFormData - parameter param: (form) field1 - - parameter param2: (form) field2 - + - parameter param2: (form) field2 - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ diff --git a/samples/client/petstore/swift6/combineDeferredLibrary/PetstoreClient/Classes/OpenAPIs/APIs/FakeClassnameTags123API.swift b/samples/client/petstore/swift6/combineDeferredLibrary/PetstoreClient/Classes/OpenAPIs/APIs/FakeClassnameTags123API.swift index 1f6e55082b9c..a84e66d9251d 100644 --- a/samples/client/petstore/swift6/combineDeferredLibrary/PetstoreClient/Classes/OpenAPIs/APIs/FakeClassnameTags123API.swift +++ b/samples/client/petstore/swift6/combineDeferredLibrary/PetstoreClient/Classes/OpenAPIs/APIs/FakeClassnameTags123API.swift @@ -52,7 +52,6 @@ open class FakeClassnameTags123API { - type: apiKey api_key_query (QUERY) - name: api_key_query - parameter body: (body) client model - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ diff --git a/samples/client/petstore/swift6/combineDeferredLibrary/PetstoreClient/Classes/OpenAPIs/APIs/PetAPI.swift b/samples/client/petstore/swift6/combineDeferredLibrary/PetstoreClient/Classes/OpenAPIs/APIs/PetAPI.swift index ca7b4eda2058..13facaf8462b 100644 --- a/samples/client/petstore/swift6/combineDeferredLibrary/PetstoreClient/Classes/OpenAPIs/APIs/PetAPI.swift +++ b/samples/client/petstore/swift6/combineDeferredLibrary/PetstoreClient/Classes/OpenAPIs/APIs/PetAPI.swift @@ -54,7 +54,6 @@ open class PetAPI { - type: apiKey api_key_query (QUERY) - name: api_key_query - parameter body: (body) Pet object that needs to be added to the store - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -116,8 +115,7 @@ open class PetAPI { - type: oauth2 - name: petstore_auth - parameter petId: (path) Pet id to delete - - parameter apiKey: (header) (optional) - + - parameter apiKey: (header) (optional) - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -191,7 +189,6 @@ open class PetAPI { - type: oauth2 - name: petstore_auth - parameter status: (query) Status values that need to be considered for filter - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder<[Pet]> */ @@ -257,7 +254,6 @@ open class PetAPI { - type: oauth2 - name: petstore_auth - parameter tags: (query) Tags to filter by - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder<[Pet]> */ @@ -323,7 +319,6 @@ open class PetAPI { - type: apiKey api_key (HEADER) - name: api_key - parameter petId: (path) ID of pet to return - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -387,7 +382,6 @@ open class PetAPI { - type: oauth2 - name: petstore_auth - parameter body: (body) Pet object that needs to be added to the store - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -450,9 +444,8 @@ open class PetAPI { - type: oauth2 - name: petstore_auth - parameter petId: (path) ID of pet that needs to be updated - - parameter name: (form) Updated name of the pet (optional) - - parameter status: (form) Updated status of the pet (optional) - + - parameter name: (form) Updated name of the pet (optional) + - parameter status: (form) Updated status of the pet (optional) - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -524,9 +517,8 @@ open class PetAPI { - type: oauth2 - name: petstore_auth - parameter petId: (path) ID of pet to update - - parameter additionalMetadata: (form) Additional data to pass to server (optional) - - parameter file: (form) file to upload (optional) - + - parameter additionalMetadata: (form) Additional data to pass to server (optional) + - parameter file: (form) file to upload (optional) - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -598,9 +590,8 @@ open class PetAPI { - type: oauth2 - name: petstore_auth - parameter petId: (path) ID of pet to update - - parameter requiredFile: (form) file to upload - - parameter additionalMetadata: (form) Additional data to pass to server (optional) - + - parameter requiredFile: (form) file to upload + - parameter additionalMetadata: (form) Additional data to pass to server (optional) - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ diff --git a/samples/client/petstore/swift6/combineDeferredLibrary/PetstoreClient/Classes/OpenAPIs/APIs/StoreAPI.swift b/samples/client/petstore/swift6/combineDeferredLibrary/PetstoreClient/Classes/OpenAPIs/APIs/StoreAPI.swift index f3bcc4806ba2..3ec77a974a29 100644 --- a/samples/client/petstore/swift6/combineDeferredLibrary/PetstoreClient/Classes/OpenAPIs/APIs/StoreAPI.swift +++ b/samples/client/petstore/swift6/combineDeferredLibrary/PetstoreClient/Classes/OpenAPIs/APIs/StoreAPI.swift @@ -49,7 +49,6 @@ open class StoreAPI { - DELETE /store/order/{order_id} - For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors - parameter orderId: (path) ID of the order that needs to be deleted - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -112,7 +111,6 @@ open class StoreAPI { - API Key: - type: apiKey api_key (HEADER) - name: api_key - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder<[String: Int]> */ @@ -171,7 +169,6 @@ open class StoreAPI { - GET /store/order/{order_id} - For valid response try integer IDs with value <= 5 or > 10. Other values will generate exceptions - parameter orderId: (path) ID of pet that needs to be fetched - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -232,7 +229,6 @@ open class StoreAPI { Place an order for a pet - POST /store/order - parameter body: (body) order placed for purchasing the pet - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ diff --git a/samples/client/petstore/swift6/combineDeferredLibrary/PetstoreClient/Classes/OpenAPIs/APIs/UserAPI.swift b/samples/client/petstore/swift6/combineDeferredLibrary/PetstoreClient/Classes/OpenAPIs/APIs/UserAPI.swift index 34482e26d823..a60203d73597 100644 --- a/samples/client/petstore/swift6/combineDeferredLibrary/PetstoreClient/Classes/OpenAPIs/APIs/UserAPI.swift +++ b/samples/client/petstore/swift6/combineDeferredLibrary/PetstoreClient/Classes/OpenAPIs/APIs/UserAPI.swift @@ -49,7 +49,6 @@ open class UserAPI { - POST /user - This can only be done by the logged in user. - parameter body: (body) Created user object - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -107,7 +106,6 @@ open class UserAPI { Creates list of users with given input array - POST /user/createWithArray - parameter body: (body) List of user object - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -165,7 +163,6 @@ open class UserAPI { Creates list of users with given input array - POST /user/createWithList - parameter body: (body) List of user object - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -224,7 +221,6 @@ open class UserAPI { - DELETE /user/{username} - This can only be done by the logged in user. - parameter username: (path) The name that needs to be deleted - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -285,7 +281,6 @@ open class UserAPI { Get user by user name - GET /user/{username} - parameter username: (path) The name that needs to be fetched. Use user1 for testing. - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -348,8 +343,7 @@ open class UserAPI { - GET /user/login - responseHeaders: [X-Rate-Limit(Int), X-Expires-After(Date)] - parameter username: (query) The user name for login - - parameter password: (query) The password for login in clear text - + - parameter password: (query) The password for login in clear text - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -409,7 +403,6 @@ open class UserAPI { /** Logs out current logged in user session - GET /user/logout - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -469,8 +462,7 @@ open class UserAPI { - PUT /user/{username} - This can only be done by the logged in user. - parameter username: (path) name that need to be deleted - - parameter body: (body) Updated user object - + - parameter body: (body) Updated user object - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ diff --git a/samples/client/petstore/swift6/combineDeferredLibrary/README.md b/samples/client/petstore/swift6/combineDeferredLibrary/README.md index 25f3ad847445..0b9710436990 100644 --- a/samples/client/petstore/swift6/combineDeferredLibrary/README.md +++ b/samples/client/petstore/swift6/combineDeferredLibrary/README.md @@ -140,6 +140,89 @@ Authentication schemes defined for the API: - **Type**: HTTP basic authentication +### How do I implement bearer token authentication with URLSession on the Swift 6 API client? + +First you implement the `OpenAPIInterceptor` protocol. +``` +public class BearerOpenAPIInterceptor: OpenAPIInterceptor { + public init() {} + + public func intercept(urlRequest: URLRequest, urlSession: URLSessionProtocol, openAPIClient: OpenAPIClient, completion: @escaping (Result) -> 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 diff --git a/samples/client/petstore/swift6/combineLibrary/README.md b/samples/client/petstore/swift6/combineLibrary/README.md index 25f3ad847445..0b9710436990 100644 --- a/samples/client/petstore/swift6/combineLibrary/README.md +++ b/samples/client/petstore/swift6/combineLibrary/README.md @@ -140,6 +140,89 @@ Authentication schemes defined for the API: - **Type**: HTTP basic authentication +### How do I implement bearer token authentication with URLSession on the Swift 6 API client? + +First you implement the `OpenAPIInterceptor` protocol. +``` +public class BearerOpenAPIInterceptor: OpenAPIInterceptor { + public init() {} + + public func intercept(urlRequest: URLRequest, urlSession: URLSessionProtocol, openAPIClient: OpenAPIClient, completion: @escaping (Result) -> 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 diff --git a/samples/client/petstore/swift6/combineLibrary/Sources/CombineLibrary/APIs/AnotherFakeAPI.swift b/samples/client/petstore/swift6/combineLibrary/Sources/CombineLibrary/APIs/AnotherFakeAPI.swift index 4f4dc815c942..8fb1fb069756 100644 --- a/samples/client/petstore/swift6/combineLibrary/Sources/CombineLibrary/APIs/AnotherFakeAPI.swift +++ b/samples/client/petstore/swift6/combineLibrary/Sources/CombineLibrary/APIs/AnotherFakeAPI.swift @@ -47,7 +47,6 @@ open class AnotherFakeAPI { - PATCH /another-fake/dummy - To test special tags and operation ID starting with number - parameter body: (body) client model - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ diff --git a/samples/client/petstore/swift6/combineLibrary/Sources/CombineLibrary/APIs/FakeAPI.swift b/samples/client/petstore/swift6/combineLibrary/Sources/CombineLibrary/APIs/FakeAPI.swift index b7adab145cb1..72e1ba9b7665 100644 --- a/samples/client/petstore/swift6/combineLibrary/Sources/CombineLibrary/APIs/FakeAPI.swift +++ b/samples/client/petstore/swift6/combineLibrary/Sources/CombineLibrary/APIs/FakeAPI.swift @@ -45,7 +45,6 @@ open class FakeAPI { - POST /fake/outer/boolean - Test serialization of outer boolean types - parameter body: (body) Input boolean as post body (optional) - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -100,7 +99,6 @@ open class FakeAPI { - POST /fake/outer/composite - Test serialization of object with outer number type - parameter body: (body) Input composite as post body (optional) - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -155,7 +153,6 @@ open class FakeAPI { - POST /fake/outer/number - Test serialization of outer number types - parameter body: (body) Input number as post body (optional) - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -210,7 +207,6 @@ open class FakeAPI { - POST /fake/outer/string - Test serialization of outer string types - parameter body: (body) Input string as post body (optional) - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -265,7 +261,6 @@ open class FakeAPI { - PUT /fake/body-with-file-schema - For this test, the body for this request much reference a schema named `File`. - parameter body: (body) - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -320,8 +315,7 @@ open class FakeAPI { /** - PUT /fake/body-with-query-params - parameter query: (query) - - parameter body: (body) - + - parameter body: (body) - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -381,7 +375,6 @@ open class FakeAPI { - PATCH /fake - To test \"client\" model - parameter body: (body) client model - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -454,20 +447,19 @@ open class FakeAPI { - type: http - name: http_basic_test - parameter number: (form) None - - parameter double: (form) None - - parameter patternWithoutDelimiter: (form) None - - parameter byte: (form) None - - parameter integer: (form) None (optional) - - parameter int32: (form) None (optional) - - parameter int64: (form) None (optional) - - parameter float: (form) None (optional) - - parameter string: (form) None (optional) - - parameter binary: (form) None (optional) - - parameter date: (form) None (optional) - - parameter dateTime: (form) None (optional) - - parameter password: (form) None (optional) - - parameter callback: (form) None (optional) - + - parameter double: (form) None + - parameter patternWithoutDelimiter: (form) None + - parameter byte: (form) None + - parameter integer: (form) None (optional) + - parameter int32: (form) None (optional) + - parameter int64: (form) None (optional) + - parameter float: (form) None (optional) + - parameter string: (form) None (optional) + - parameter binary: (form) None (optional) + - parameter date: (form) None (optional) + - parameter dateTime: (form) None (optional) + - parameter password: (form) None (optional) + - parameter callback: (form) None (optional) - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -616,14 +608,13 @@ open class FakeAPI { - GET /fake - To test enum parameters - parameter enumHeaderStringArray: (header) Header parameter enum test (string array) (optional) - - parameter enumHeaderString: (header) Header parameter enum test (string) (optional, default to .efg) - - parameter enumQueryStringArray: (query) Query parameter enum test (string array) (optional) - - parameter enumQueryString: (query) Query parameter enum test (string) (optional, default to .efg) - - parameter enumQueryInteger: (query) Query parameter enum test (double) (optional) - - parameter enumQueryDouble: (query) Query parameter enum test (double) (optional) - - parameter enumFormStringArray: (form) Form parameter enum test (string array) (optional, default to .dollar) - - parameter enumFormString: (form) Form parameter enum test (string) (optional, default to .efg) - + - parameter enumHeaderString: (header) Header parameter enum test (string) (optional, default to .efg) + - parameter enumQueryStringArray: (query) Query parameter enum test (string array) (optional) + - parameter enumQueryString: (query) Query parameter enum test (string) (optional, default to .efg) + - parameter enumQueryInteger: (query) Query parameter enum test (double) (optional) + - parameter enumQueryDouble: (query) Query parameter enum test (double) (optional) + - parameter enumFormStringArray: (form) Form parameter enum test (string array) (optional, default to .dollar) + - parameter enumFormString: (form) Form parameter enum test (string) (optional, default to .efg) - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -699,12 +690,11 @@ open class FakeAPI { - DELETE /fake - Fake endpoint to test group parameters (optional) - parameter requiredStringGroup: (query) Required String in group parameters - - parameter requiredBooleanGroup: (header) Required Boolean in group parameters - - parameter requiredInt64Group: (query) Required Integer in group parameters - - parameter stringGroup: (query) String in group parameters (optional) - - parameter booleanGroup: (header) Boolean in group parameters (optional) - - parameter int64Group: (query) Integer in group parameters (optional) - + - parameter requiredBooleanGroup: (header) Required Boolean in group parameters + - parameter requiredInt64Group: (query) Required Integer in group parameters + - parameter stringGroup: (query) String in group parameters (optional) + - parameter booleanGroup: (header) Boolean in group parameters (optional) + - parameter int64Group: (query) Integer in group parameters (optional) - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -767,7 +757,6 @@ open class FakeAPI { test inline additionalProperties - POST /fake/inline-additionalProperties - parameter param: (body) request body - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -824,8 +813,7 @@ open class FakeAPI { test json serialization of form data - GET /fake/jsonFormData - parameter param: (form) field1 - - parameter param2: (form) field2 - + - parameter param2: (form) field2 - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ diff --git a/samples/client/petstore/swift6/combineLibrary/Sources/CombineLibrary/APIs/FakeClassnameTags123API.swift b/samples/client/petstore/swift6/combineLibrary/Sources/CombineLibrary/APIs/FakeClassnameTags123API.swift index d89814c969ef..57a1987447b2 100644 --- a/samples/client/petstore/swift6/combineLibrary/Sources/CombineLibrary/APIs/FakeClassnameTags123API.swift +++ b/samples/client/petstore/swift6/combineLibrary/Sources/CombineLibrary/APIs/FakeClassnameTags123API.swift @@ -50,7 +50,6 @@ open class FakeClassnameTags123API { - type: apiKey api_key_query (QUERY) - name: api_key_query - parameter body: (body) client model - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ diff --git a/samples/client/petstore/swift6/combineLibrary/Sources/CombineLibrary/APIs/PetAPI.swift b/samples/client/petstore/swift6/combineLibrary/Sources/CombineLibrary/APIs/PetAPI.swift index 7def35ea4388..52e06462861a 100644 --- a/samples/client/petstore/swift6/combineLibrary/Sources/CombineLibrary/APIs/PetAPI.swift +++ b/samples/client/petstore/swift6/combineLibrary/Sources/CombineLibrary/APIs/PetAPI.swift @@ -52,7 +52,6 @@ open class PetAPI { - type: apiKey api_key_query (QUERY) - name: api_key_query - parameter body: (body) Pet object that needs to be added to the store - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -112,8 +111,7 @@ open class PetAPI { - type: oauth2 - name: petstore_auth - parameter petId: (path) Pet id to delete - - parameter apiKey: (header) (optional) - + - parameter apiKey: (header) (optional) - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -185,7 +183,6 @@ open class PetAPI { - type: oauth2 - name: petstore_auth - parameter status: (query) Status values that need to be considered for filter - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder<[Pet]> */ @@ -249,7 +246,6 @@ open class PetAPI { - type: oauth2 - name: petstore_auth - parameter tags: (query) Tags to filter by - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder<[Pet]> */ @@ -313,7 +309,6 @@ open class PetAPI { - type: apiKey api_key (HEADER) - name: api_key - parameter petId: (path) ID of pet to return - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -375,7 +370,6 @@ open class PetAPI { - type: oauth2 - name: petstore_auth - parameter body: (body) Pet object that needs to be added to the store - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -436,9 +430,8 @@ open class PetAPI { - type: oauth2 - name: petstore_auth - parameter petId: (path) ID of pet that needs to be updated - - parameter name: (form) Updated name of the pet (optional) - - parameter status: (form) Updated status of the pet (optional) - + - parameter name: (form) Updated name of the pet (optional) + - parameter status: (form) Updated status of the pet (optional) - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -508,9 +501,8 @@ open class PetAPI { - type: oauth2 - name: petstore_auth - parameter petId: (path) ID of pet to update - - parameter additionalMetadata: (form) Additional data to pass to server (optional) - - parameter file: (form) file to upload (optional) - + - parameter additionalMetadata: (form) Additional data to pass to server (optional) + - parameter file: (form) file to upload (optional) - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -580,9 +572,8 @@ open class PetAPI { - type: oauth2 - name: petstore_auth - parameter petId: (path) ID of pet to update - - parameter requiredFile: (form) file to upload - - parameter additionalMetadata: (form) Additional data to pass to server (optional) - + - parameter requiredFile: (form) file to upload + - parameter additionalMetadata: (form) Additional data to pass to server (optional) - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ diff --git a/samples/client/petstore/swift6/combineLibrary/Sources/CombineLibrary/APIs/StoreAPI.swift b/samples/client/petstore/swift6/combineLibrary/Sources/CombineLibrary/APIs/StoreAPI.swift index d6b827685e59..24d20d6cb0aa 100644 --- a/samples/client/petstore/swift6/combineLibrary/Sources/CombineLibrary/APIs/StoreAPI.swift +++ b/samples/client/petstore/swift6/combineLibrary/Sources/CombineLibrary/APIs/StoreAPI.swift @@ -47,7 +47,6 @@ open class StoreAPI { - DELETE /store/order/{order_id} - For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors - parameter orderId: (path) ID of the order that needs to be deleted - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -108,7 +107,6 @@ open class StoreAPI { - API Key: - type: apiKey api_key (HEADER) - name: api_key - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder<[String: Int]> */ @@ -165,7 +163,6 @@ open class StoreAPI { - GET /store/order/{order_id} - For valid response try integer IDs with value <= 5 or > 10. Other values will generate exceptions - parameter orderId: (path) ID of pet that needs to be fetched - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -224,7 +221,6 @@ open class StoreAPI { Place an order for a pet - POST /store/order - parameter body: (body) order placed for purchasing the pet - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ diff --git a/samples/client/petstore/swift6/combineLibrary/Sources/CombineLibrary/APIs/UserAPI.swift b/samples/client/petstore/swift6/combineLibrary/Sources/CombineLibrary/APIs/UserAPI.swift index be2388b874f8..69561044a07f 100644 --- a/samples/client/petstore/swift6/combineLibrary/Sources/CombineLibrary/APIs/UserAPI.swift +++ b/samples/client/petstore/swift6/combineLibrary/Sources/CombineLibrary/APIs/UserAPI.swift @@ -47,7 +47,6 @@ open class UserAPI { - POST /user - This can only be done by the logged in user. - parameter body: (body) Created user object - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -103,7 +102,6 @@ open class UserAPI { Creates list of users with given input array - POST /user/createWithArray - parameter body: (body) List of user object - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -159,7 +157,6 @@ open class UserAPI { Creates list of users with given input array - POST /user/createWithList - parameter body: (body) List of user object - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -216,7 +213,6 @@ open class UserAPI { - DELETE /user/{username} - This can only be done by the logged in user. - parameter username: (path) The name that needs to be deleted - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -275,7 +271,6 @@ open class UserAPI { Get user by user name - GET /user/{username} - parameter username: (path) The name that needs to be fetched. Use user1 for testing. - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -336,8 +331,7 @@ open class UserAPI { - GET /user/login - responseHeaders: [X-Rate-Limit(Int), X-Expires-After(Date)] - parameter username: (query) The user name for login - - parameter password: (query) The password for login in clear text - + - parameter password: (query) The password for login in clear text - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -395,7 +389,6 @@ open class UserAPI { /** Logs out current logged in user session - GET /user/logout - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -453,8 +446,7 @@ open class UserAPI { - PUT /user/{username} - This can only be done by the logged in user. - parameter username: (path) name that need to be deleted - - parameter body: (body) Updated user object - + - parameter body: (body) Updated user object - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ diff --git a/samples/client/petstore/swift6/default/README.md b/samples/client/petstore/swift6/default/README.md index 0dba8658f948..c697be6f101e 100644 --- a/samples/client/petstore/swift6/default/README.md +++ b/samples/client/petstore/swift6/default/README.md @@ -151,6 +151,89 @@ Authentication schemes defined for the API: - **Type**: HTTP basic authentication +### How do I implement bearer token authentication with URLSession on the Swift 6 API client? + +First you implement the `OpenAPIInterceptor` protocol. +``` +public class BearerOpenAPIInterceptor: OpenAPIInterceptor { + public init() {} + + public func intercept(urlRequest: URLRequest, urlSession: URLSessionProtocol, openAPIClient: OpenAPIClient, completion: @escaping (Result) -> 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 diff --git a/samples/client/petstore/swift6/default/Sources/PetstoreClient/APIs/AnotherFakeAPI.swift b/samples/client/petstore/swift6/default/Sources/PetstoreClient/APIs/AnotherFakeAPI.swift index a35d06684b92..55f01a97cf32 100644 --- a/samples/client/petstore/swift6/default/Sources/PetstoreClient/APIs/AnotherFakeAPI.swift +++ b/samples/client/petstore/swift6/default/Sources/PetstoreClient/APIs/AnotherFakeAPI.swift @@ -27,8 +27,7 @@ open class AnotherFakeAPI { - PATCH /another-fake/dummy - To test special tags and operation ID starting with number - parameter uuidTest: (header) to test uuid example value - - parameter body: (body) client model - + - parameter body: (body) client model - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ diff --git a/samples/client/petstore/swift6/default/Sources/PetstoreClient/APIs/FakeAPI.swift b/samples/client/petstore/swift6/default/Sources/PetstoreClient/APIs/FakeAPI.swift index 6cc849c4d085..9d3e3a4ade7e 100644 --- a/samples/client/petstore/swift6/default/Sources/PetstoreClient/APIs/FakeAPI.swift +++ b/samples/client/petstore/swift6/default/Sources/PetstoreClient/APIs/FakeAPI.swift @@ -26,7 +26,6 @@ open class FakeAPI { - POST /fake/create_xml_item - this route creates an XmlItem - parameter xmlItem: (body) XmlItem Body - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -63,7 +62,6 @@ open class FakeAPI { - POST /fake/outer/boolean - Test serialization of outer boolean types - parameter body: (body) Input boolean as post body (optional) - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -100,7 +98,6 @@ open class FakeAPI { - POST /fake/outer/composite - Test serialization of object with outer number type - parameter body: (body) Input composite as post body (optional) - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -137,7 +134,6 @@ open class FakeAPI { - POST /fake/outer/number - Test serialization of outer number types - parameter body: (body) Input number as post body (optional) - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -174,7 +170,6 @@ open class FakeAPI { - POST /fake/outer/string - Test serialization of outer string types - parameter body: (body) Input string as post body (optional) - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -211,7 +206,6 @@ open class FakeAPI { - PUT /fake/body-with-file-schema - For this test, the body for this request much reference a schema named `File`. - parameter body: (body) - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -248,8 +242,7 @@ open class FakeAPI { /** - PUT /fake/body-with-query-params - parameter query: (query) - - parameter body: (body) - + - parameter body: (body) - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -291,7 +284,6 @@ open class FakeAPI { - PATCH /fake - To test \"client\" model - parameter body: (body) client model - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -346,20 +338,19 @@ open class FakeAPI { - type: http - name: http_basic_test - parameter number: (form) None - - parameter double: (form) None - - parameter patternWithoutDelimiter: (form) None - - parameter byte: (form) None - - parameter integer: (form) None (optional) - - parameter int32: (form) None (optional) - - parameter int64: (form) None (optional) - - parameter float: (form) None (optional) - - parameter string: (form) None (optional) - - parameter binary: (form) None (optional) - - parameter date: (form) None (optional) - - parameter dateTime: (form) None (optional) - - parameter password: (form) None (optional) - - parameter callback: (form) None (optional) - + - parameter double: (form) None + - parameter patternWithoutDelimiter: (form) None + - parameter byte: (form) None + - parameter integer: (form) None (optional) + - parameter int32: (form) None (optional) + - parameter int64: (form) None (optional) + - parameter float: (form) None (optional) + - parameter string: (form) None (optional) + - parameter binary: (form) None (optional) + - parameter date: (form) None (optional) + - parameter dateTime: (form) None (optional) + - parameter password: (form) None (optional) + - parameter callback: (form) None (optional) - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -490,14 +481,13 @@ open class FakeAPI { - GET /fake - To test enum parameters - parameter enumHeaderStringArray: (header) Header parameter enum test (string array) (optional) - - parameter enumHeaderString: (header) Header parameter enum test (string) (optional, default to .efg) - - parameter enumQueryStringArray: (query) Query parameter enum test (string array) (optional) - - parameter enumQueryString: (query) Query parameter enum test (string) (optional, default to .efg) - - parameter enumQueryInteger: (query) Query parameter enum test (double) (optional) - - parameter enumQueryDouble: (query) Query parameter enum test (double) (optional) - - parameter enumFormStringArray: (form) Form parameter enum test (string array) (optional, default to .dollar) - - parameter enumFormString: (form) Form parameter enum test (string) (optional, default to .efg) - + - parameter enumHeaderString: (header) Header parameter enum test (string) (optional, default to .efg) + - parameter enumQueryStringArray: (query) Query parameter enum test (string array) (optional) + - parameter enumQueryString: (query) Query parameter enum test (string) (optional, default to .efg) + - parameter enumQueryInteger: (query) Query parameter enum test (double) (optional) + - parameter enumQueryDouble: (query) Query parameter enum test (double) (optional) + - parameter enumFormStringArray: (form) Form parameter enum test (string array) (optional, default to .dollar) + - parameter enumFormString: (form) Form parameter enum test (string) (optional, default to .efg) - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -555,12 +545,11 @@ open class FakeAPI { - DELETE /fake - Fake endpoint to test group parameters (optional) - parameter requiredStringGroup: (query) Required String in group parameters - - parameter requiredBooleanGroup: (header) Required Boolean in group parameters - - parameter requiredInt64Group: (query) Required Integer in group parameters - - parameter stringGroup: (query) String in group parameters (optional) - - parameter booleanGroup: (header) Boolean in group parameters (optional) - - parameter int64Group: (query) Integer in group parameters (optional) - + - parameter requiredBooleanGroup: (header) Required Boolean in group parameters + - parameter requiredInt64Group: (query) Required Integer in group parameters + - parameter stringGroup: (query) String in group parameters (optional) + - parameter booleanGroup: (header) Boolean in group parameters (optional) + - parameter int64Group: (query) Integer in group parameters (optional) - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -605,7 +594,6 @@ open class FakeAPI { test inline additionalProperties - POST /fake/inline-additionalProperties - parameter param: (body) request body - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -644,8 +632,7 @@ open class FakeAPI { test json serialization of form data - GET /fake/jsonFormData - parameter param: (form) field1 - - parameter param2: (form) field2 - + - parameter param2: (form) field2 - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -692,11 +679,10 @@ open class FakeAPI { - PUT /fake/test-query-parameters - To test the collection format in query parameters - parameter pipe: (query) - - parameter ioutil: (query) - - parameter http: (query) - - parameter url: (query) - - parameter context: (query) - + - parameter ioutil: (query) + - parameter http: (query) + - parameter url: (query) + - parameter context: (query) - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ diff --git a/samples/client/petstore/swift6/default/Sources/PetstoreClient/APIs/FakeClassnameTags123API.swift b/samples/client/petstore/swift6/default/Sources/PetstoreClient/APIs/FakeClassnameTags123API.swift index e311db6721c6..1ea172c5e854 100644 --- a/samples/client/petstore/swift6/default/Sources/PetstoreClient/APIs/FakeClassnameTags123API.swift +++ b/samples/client/petstore/swift6/default/Sources/PetstoreClient/APIs/FakeClassnameTags123API.swift @@ -29,7 +29,6 @@ open class FakeClassnameTags123API { - type: apiKey api_key_query (QUERY) - name: api_key_query - parameter body: (body) client model - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ diff --git a/samples/client/petstore/swift6/default/Sources/PetstoreClient/APIs/PetAPI.swift b/samples/client/petstore/swift6/default/Sources/PetstoreClient/APIs/PetAPI.swift index c5655345a40a..79e51af03c8c 100644 --- a/samples/client/petstore/swift6/default/Sources/PetstoreClient/APIs/PetAPI.swift +++ b/samples/client/petstore/swift6/default/Sources/PetstoreClient/APIs/PetAPI.swift @@ -28,7 +28,6 @@ open class PetAPI { - type: oauth2 - name: petstore_auth - parameter body: (body) Pet object that needs to be added to the store - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -70,8 +69,7 @@ open class PetAPI { - type: oauth2 - name: petstore_auth - parameter petId: (path) Pet id to delete - - parameter apiKey: (header) (optional) - + - parameter apiKey: (header) (optional) - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -125,7 +123,6 @@ open class PetAPI { - type: oauth2 - name: petstore_auth - parameter status: (query) Status values that need to be considered for filter - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder<[Pet]> */ @@ -171,7 +168,6 @@ open class PetAPI { - type: oauth2 - name: petstore_auth - parameter tags: (query) Tags to filter by - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder> */ @@ -217,7 +213,6 @@ open class PetAPI { - type: apiKey api_key (HEADER) - name: api_key - parameter petId: (path) ID of pet to return - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -261,7 +256,6 @@ open class PetAPI { - type: oauth2 - name: petstore_auth - parameter body: (body) Pet object that needs to be added to the store - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -304,9 +298,8 @@ open class PetAPI { - type: oauth2 - name: petstore_auth - parameter petId: (path) ID of pet that needs to be updated - - parameter name: (form) Updated name of the pet (optional) - - parameter status: (form) Updated status of the pet (optional) - + - parameter name: (form) Updated name of the pet (optional) + - parameter status: (form) Updated status of the pet (optional) - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -358,9 +351,8 @@ open class PetAPI { - type: oauth2 - name: petstore_auth - parameter petId: (path) ID of pet to update - - parameter additionalMetadata: (form) Additional data to pass to server (optional) - - parameter file: (form) file to upload (optional) - + - parameter additionalMetadata: (form) Additional data to pass to server (optional) + - parameter file: (form) file to upload (optional) - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -412,9 +404,8 @@ open class PetAPI { - type: oauth2 - name: petstore_auth - parameter petId: (path) ID of pet to update - - parameter requiredFile: (form) file to upload - - parameter additionalMetadata: (form) Additional data to pass to server (optional) - + - parameter requiredFile: (form) file to upload + - parameter additionalMetadata: (form) Additional data to pass to server (optional) - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ diff --git a/samples/client/petstore/swift6/default/Sources/PetstoreClient/APIs/StoreAPI.swift b/samples/client/petstore/swift6/default/Sources/PetstoreClient/APIs/StoreAPI.swift index 783666b1a695..db645dd19a91 100644 --- a/samples/client/petstore/swift6/default/Sources/PetstoreClient/APIs/StoreAPI.swift +++ b/samples/client/petstore/swift6/default/Sources/PetstoreClient/APIs/StoreAPI.swift @@ -26,7 +26,6 @@ open class StoreAPI { - DELETE /store/order/{order_id} - For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors - parameter orderId: (path) ID of the order that needs to be deleted - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -69,7 +68,6 @@ open class StoreAPI { - API Key: - type: apiKey api_key (HEADER) - name: api_key - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder<[String: Int]> */ @@ -108,7 +106,6 @@ open class StoreAPI { - GET /store/order/{order_id} - For valid response try integer IDs with value <= 5 or > 10. Other values will generate exceptions - parameter orderId: (path) ID of pet that needs to be fetched - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -149,7 +146,6 @@ open class StoreAPI { Place an order for a pet - POST /store/order - parameter body: (body) order placed for purchasing the pet - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ diff --git a/samples/client/petstore/swift6/default/Sources/PetstoreClient/APIs/UserAPI.swift b/samples/client/petstore/swift6/default/Sources/PetstoreClient/APIs/UserAPI.swift index c4ec09e3d0e7..76a300f7840c 100644 --- a/samples/client/petstore/swift6/default/Sources/PetstoreClient/APIs/UserAPI.swift +++ b/samples/client/petstore/swift6/default/Sources/PetstoreClient/APIs/UserAPI.swift @@ -26,7 +26,6 @@ open class UserAPI { - POST /user - This can only be done by the logged in user. - parameter body: (body) Created user object - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -64,7 +63,6 @@ open class UserAPI { Creates list of users with given input array - POST /user/createWithArray - parameter body: (body) List of user object - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -102,7 +100,6 @@ open class UserAPI { Creates list of users with given input array - POST /user/createWithList - parameter body: (body) List of user object - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -141,7 +138,6 @@ open class UserAPI { - DELETE /user/{username} - This can only be done by the logged in user. - parameter username: (path) The name that needs to be deleted - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -182,7 +178,6 @@ open class UserAPI { Get user by user name - GET /user/{username} - parameter username: (path) The name that needs to be fetched. Use user1 for testing. - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -225,8 +220,7 @@ open class UserAPI { - GET /user/login - responseHeaders: [X-Rate-Limit(Int), X-Expires-After(Date)] - parameter username: (query) The user name for login - - parameter password: (query) The password for login in clear text - + - parameter password: (query) The password for login in clear text - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -266,7 +260,6 @@ open class UserAPI { /** Logs out current logged in user session - GET /user/logout - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -306,8 +299,7 @@ open class UserAPI { - PUT /user/{username} - This can only be done by the logged in user. - parameter username: (path) name that need to be deleted - - parameter body: (body) Updated user object - + - parameter body: (body) Updated user object - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ diff --git a/samples/client/petstore/swift6/objcCompatible/README.md b/samples/client/petstore/swift6/objcCompatible/README.md index 25f3ad847445..0b9710436990 100644 --- a/samples/client/petstore/swift6/objcCompatible/README.md +++ b/samples/client/petstore/swift6/objcCompatible/README.md @@ -140,6 +140,89 @@ Authentication schemes defined for the API: - **Type**: HTTP basic authentication +### How do I implement bearer token authentication with URLSession on the Swift 6 API client? + +First you implement the `OpenAPIInterceptor` protocol. +``` +public class BearerOpenAPIInterceptor: OpenAPIInterceptor { + public init() {} + + public func intercept(urlRequest: URLRequest, urlSession: URLSessionProtocol, openAPIClient: OpenAPIClient, completion: @escaping (Result) -> 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 diff --git a/samples/client/petstore/swift6/objcCompatible/Sources/PetstoreClient/APIs/AnotherFakeAPI.swift b/samples/client/petstore/swift6/objcCompatible/Sources/PetstoreClient/APIs/AnotherFakeAPI.swift index 89621e7ff0e5..33441729bb64 100644 --- a/samples/client/petstore/swift6/objcCompatible/Sources/PetstoreClient/APIs/AnotherFakeAPI.swift +++ b/samples/client/petstore/swift6/objcCompatible/Sources/PetstoreClient/APIs/AnotherFakeAPI.swift @@ -33,7 +33,6 @@ import Foundation - PATCH /another-fake/dummy - To test special tags and operation ID starting with number - parameter body: (body) client model - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ diff --git a/samples/client/petstore/swift6/objcCompatible/Sources/PetstoreClient/APIs/FakeAPI.swift b/samples/client/petstore/swift6/objcCompatible/Sources/PetstoreClient/APIs/FakeAPI.swift index 5fd0ac8bd7c2..10f0902bf485 100644 --- a/samples/client/petstore/swift6/objcCompatible/Sources/PetstoreClient/APIs/FakeAPI.swift +++ b/samples/client/petstore/swift6/objcCompatible/Sources/PetstoreClient/APIs/FakeAPI.swift @@ -31,7 +31,6 @@ import Foundation - POST /fake/outer/boolean - Test serialization of outer boolean types - parameter body: (body) Input boolean as post body (optional) - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -75,7 +74,6 @@ import Foundation - POST /fake/outer/composite - Test serialization of object with outer number type - parameter body: (body) Input composite as post body (optional) - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -119,7 +117,6 @@ import Foundation - POST /fake/outer/number - Test serialization of outer number types - parameter body: (body) Input number as post body (optional) - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -163,7 +160,6 @@ import Foundation - POST /fake/outer/string - Test serialization of outer string types - parameter body: (body) Input string as post body (optional) - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -207,7 +203,6 @@ import Foundation - PUT /fake/body-with-file-schema - For this test, the body for this request much reference a schema named `File`. - parameter body: (body) - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -251,8 +246,7 @@ import Foundation /** - PUT /fake/body-with-query-params - parameter query: (query) - - parameter body: (body) - + - parameter body: (body) - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -301,7 +295,6 @@ import Foundation - PATCH /fake - To test \"client\" model - parameter body: (body) client model - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -363,20 +356,19 @@ import Foundation - type: http - name: http_basic_test - parameter number: (form) None - - parameter double: (form) None - - parameter patternWithoutDelimiter: (form) None - - parameter byte: (form) None - - parameter integer: (form) None (optional) - - parameter int32: (form) None (optional) - - parameter int64: (form) None (optional) - - parameter float: (form) None (optional) - - parameter string: (form) None (optional) - - parameter binary: (form) None (optional) - - parameter date: (form) None (optional) - - parameter dateTime: (form) None (optional) - - parameter password: (form) None (optional) - - parameter callback: (form) None (optional) - + - parameter double: (form) None + - parameter patternWithoutDelimiter: (form) None + - parameter byte: (form) None + - parameter integer: (form) None (optional) + - parameter int32: (form) None (optional) + - parameter int64: (form) None (optional) + - parameter float: (form) None (optional) + - parameter string: (form) None (optional) + - parameter binary: (form) None (optional) + - parameter date: (form) None (optional) + - parameter dateTime: (form) None (optional) + - parameter password: (form) None (optional) + - parameter callback: (form) None (optional) - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -514,14 +506,13 @@ import Foundation - GET /fake - To test enum parameters - parameter enumHeaderStringArray: (header) Header parameter enum test (string array) (optional) - - parameter enumHeaderString: (header) Header parameter enum test (string) (optional, default to .efg) - - parameter enumQueryStringArray: (query) Query parameter enum test (string array) (optional) - - parameter enumQueryString: (query) Query parameter enum test (string) (optional, default to .efg) - - parameter enumQueryInteger: (query) Query parameter enum test (double) (optional) - - parameter enumQueryDouble: (query) Query parameter enum test (double) (optional) - - parameter enumFormStringArray: (form) Form parameter enum test (string array) (optional, default to .dollar) - - parameter enumFormString: (form) Form parameter enum test (string) (optional, default to .efg) - + - parameter enumHeaderString: (header) Header parameter enum test (string) (optional, default to .efg) + - parameter enumQueryStringArray: (query) Query parameter enum test (string array) (optional) + - parameter enumQueryString: (query) Query parameter enum test (string) (optional, default to .efg) + - parameter enumQueryInteger: (query) Query parameter enum test (double) (optional) + - parameter enumQueryDouble: (query) Query parameter enum test (double) (optional) + - parameter enumFormStringArray: (form) Form parameter enum test (string array) (optional, default to .dollar) + - parameter enumFormString: (form) Form parameter enum test (string) (optional, default to .efg) - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -586,12 +577,11 @@ import Foundation - DELETE /fake - Fake endpoint to test group parameters (optional) - parameter requiredStringGroup: (query) Required String in group parameters - - parameter requiredBooleanGroup: (header) Required Boolean in group parameters - - parameter requiredInt64Group: (query) Required Integer in group parameters - - parameter stringGroup: (query) String in group parameters (optional) - - parameter booleanGroup: (header) Boolean in group parameters (optional) - - parameter int64Group: (query) Integer in group parameters (optional) - + - parameter requiredBooleanGroup: (header) Required Boolean in group parameters + - parameter requiredInt64Group: (query) Required Integer in group parameters + - parameter stringGroup: (query) String in group parameters (optional) + - parameter booleanGroup: (header) Boolean in group parameters (optional) + - parameter int64Group: (query) Integer in group parameters (optional) - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -643,7 +633,6 @@ import Foundation test inline additionalProperties - POST /fake/inline-additionalProperties - parameter param: (body) request body - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -689,8 +678,7 @@ import Foundation test json serialization of form data - GET /fake/jsonFormData - parameter param: (form) field1 - - parameter param2: (form) field2 - + - parameter param2: (form) field2 - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ diff --git a/samples/client/petstore/swift6/objcCompatible/Sources/PetstoreClient/APIs/FakeClassnameTags123API.swift b/samples/client/petstore/swift6/objcCompatible/Sources/PetstoreClient/APIs/FakeClassnameTags123API.swift index 72ac07963f84..951a009fee07 100644 --- a/samples/client/petstore/swift6/objcCompatible/Sources/PetstoreClient/APIs/FakeClassnameTags123API.swift +++ b/samples/client/petstore/swift6/objcCompatible/Sources/PetstoreClient/APIs/FakeClassnameTags123API.swift @@ -36,7 +36,6 @@ import Foundation - type: apiKey api_key_query (QUERY) - name: api_key_query - parameter body: (body) client model - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ diff --git a/samples/client/petstore/swift6/objcCompatible/Sources/PetstoreClient/APIs/PetAPI.swift b/samples/client/petstore/swift6/objcCompatible/Sources/PetstoreClient/APIs/PetAPI.swift index a8be265073bf..8aab10afd44e 100644 --- a/samples/client/petstore/swift6/objcCompatible/Sources/PetstoreClient/APIs/PetAPI.swift +++ b/samples/client/petstore/swift6/objcCompatible/Sources/PetstoreClient/APIs/PetAPI.swift @@ -38,7 +38,6 @@ import Foundation - type: apiKey api_key_query (QUERY) - name: api_key_query - parameter body: (body) Pet object that needs to be added to the store - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -87,8 +86,7 @@ import Foundation - type: oauth2 - name: petstore_auth - parameter petId: (path) Pet id to delete - - parameter apiKey: (header) (optional) - + - parameter apiKey: (header) (optional) - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -149,7 +147,6 @@ import Foundation - type: oauth2 - name: petstore_auth - parameter status: (query) Status values that need to be considered for filter - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder<[Pet]> */ @@ -202,7 +199,6 @@ import Foundation - type: oauth2 - name: petstore_auth - parameter tags: (query) Tags to filter by - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder<[Pet]> */ @@ -255,7 +251,6 @@ import Foundation - type: apiKey api_key (HEADER) - name: api_key - parameter petId: (path) ID of pet to return - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -306,7 +301,6 @@ import Foundation - type: oauth2 - name: petstore_auth - parameter body: (body) Pet object that needs to be added to the store - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -356,9 +350,8 @@ import Foundation - type: oauth2 - name: petstore_auth - parameter petId: (path) ID of pet that needs to be updated - - parameter name: (form) Updated name of the pet (optional) - - parameter status: (form) Updated status of the pet (optional) - + - parameter name: (form) Updated name of the pet (optional) + - parameter status: (form) Updated status of the pet (optional) - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -417,9 +410,8 @@ import Foundation - type: oauth2 - name: petstore_auth - parameter petId: (path) ID of pet to update - - parameter additionalMetadata: (form) Additional data to pass to server (optional) - - parameter file: (form) file to upload (optional) - + - parameter additionalMetadata: (form) Additional data to pass to server (optional) + - parameter file: (form) file to upload (optional) - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -478,9 +470,8 @@ import Foundation - type: oauth2 - name: petstore_auth - parameter petId: (path) ID of pet to update - - parameter requiredFile: (form) file to upload - - parameter additionalMetadata: (form) Additional data to pass to server (optional) - + - parameter requiredFile: (form) file to upload + - parameter additionalMetadata: (form) Additional data to pass to server (optional) - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ diff --git a/samples/client/petstore/swift6/objcCompatible/Sources/PetstoreClient/APIs/StoreAPI.swift b/samples/client/petstore/swift6/objcCompatible/Sources/PetstoreClient/APIs/StoreAPI.swift index d09b05e6e738..36e4143ec300 100644 --- a/samples/client/petstore/swift6/objcCompatible/Sources/PetstoreClient/APIs/StoreAPI.swift +++ b/samples/client/petstore/swift6/objcCompatible/Sources/PetstoreClient/APIs/StoreAPI.swift @@ -33,7 +33,6 @@ import Foundation - DELETE /store/order/{order_id} - For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors - parameter orderId: (path) ID of the order that needs to be deleted - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -83,7 +82,6 @@ import Foundation - API Key: - type: apiKey api_key (HEADER) - name: api_key - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder<[String: Int]> */ @@ -129,7 +127,6 @@ import Foundation - GET /store/order/{order_id} - For valid response try integer IDs with value <= 5 or > 10. Other values will generate exceptions - parameter orderId: (path) ID of pet that needs to be fetched - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -177,7 +174,6 @@ import Foundation Place an order for a pet - POST /store/order - parameter body: (body) order placed for purchasing the pet - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ diff --git a/samples/client/petstore/swift6/objcCompatible/Sources/PetstoreClient/APIs/UserAPI.swift b/samples/client/petstore/swift6/objcCompatible/Sources/PetstoreClient/APIs/UserAPI.swift index 57fcc2212a0f..3b28786ce946 100644 --- a/samples/client/petstore/swift6/objcCompatible/Sources/PetstoreClient/APIs/UserAPI.swift +++ b/samples/client/petstore/swift6/objcCompatible/Sources/PetstoreClient/APIs/UserAPI.swift @@ -33,7 +33,6 @@ import Foundation - POST /user - This can only be done by the logged in user. - parameter body: (body) Created user object - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -78,7 +77,6 @@ import Foundation Creates list of users with given input array - POST /user/createWithArray - parameter body: (body) List of user object - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -123,7 +121,6 @@ import Foundation Creates list of users with given input array - POST /user/createWithList - parameter body: (body) List of user object - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -169,7 +166,6 @@ import Foundation - DELETE /user/{username} - This can only be done by the logged in user. - parameter username: (path) The name that needs to be deleted - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -217,7 +213,6 @@ import Foundation Get user by user name - GET /user/{username} - parameter username: (path) The name that needs to be fetched. Use user1 for testing. - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -267,8 +262,7 @@ import Foundation - GET /user/login - responseHeaders: [X-Rate-Limit(Int), X-Expires-After(Date)] - parameter username: (query) The user name for login - - parameter password: (query) The password for login in clear text - + - parameter password: (query) The password for login in clear text - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -315,7 +309,6 @@ import Foundation /** Logs out current logged in user session - GET /user/logout - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -362,8 +355,7 @@ import Foundation - PUT /user/{username} - This can only be done by the logged in user. - parameter username: (path) name that need to be deleted - - parameter body: (body) Updated user object - + - parameter body: (body) Updated user object - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ diff --git a/samples/client/petstore/swift6/oneOf/PetstoreClient/Classes/OpenAPIs/APIs/DefaultAPI.swift b/samples/client/petstore/swift6/oneOf/PetstoreClient/Classes/OpenAPIs/APIs/DefaultAPI.swift index 0e58f588924a..2c88f461f9d4 100644 --- a/samples/client/petstore/swift6/oneOf/PetstoreClient/Classes/OpenAPIs/APIs/DefaultAPI.swift +++ b/samples/client/petstore/swift6/oneOf/PetstoreClient/Classes/OpenAPIs/APIs/DefaultAPI.swift @@ -28,7 +28,6 @@ open class DefaultAPI { /** - GET / - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ diff --git a/samples/client/petstore/swift6/oneOf/README.md b/samples/client/petstore/swift6/oneOf/README.md index 4ef0197ba881..08f144338b5e 100644 --- a/samples/client/petstore/swift6/oneOf/README.md +++ b/samples/client/petstore/swift6/oneOf/README.md @@ -42,6 +42,89 @@ Class | Method | HTTP request | Description Endpoints do not require authorization. +### How do I implement bearer token authentication with URLSession on the Swift 6 API client? + +First you implement the `OpenAPIInterceptor` protocol. +``` +public class BearerOpenAPIInterceptor: OpenAPIInterceptor { + public init() {} + + public func intercept(urlRequest: URLRequest, urlSession: URLSessionProtocol, openAPIClient: OpenAPIClient, completion: @escaping (Result) -> 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 diff --git a/samples/client/petstore/swift6/promisekitLibrary/PetstoreClient/Classes/OpenAPIs/APIs/AnotherFakeAPI.swift b/samples/client/petstore/swift6/promisekitLibrary/PetstoreClient/Classes/OpenAPIs/APIs/AnotherFakeAPI.swift index 867cf549aeb7..8540fe07846a 100644 --- a/samples/client/petstore/swift6/promisekitLibrary/PetstoreClient/Classes/OpenAPIs/APIs/AnotherFakeAPI.swift +++ b/samples/client/petstore/swift6/promisekitLibrary/PetstoreClient/Classes/OpenAPIs/APIs/AnotherFakeAPI.swift @@ -35,7 +35,6 @@ open class AnotherFakeAPI { - PATCH /another-fake/dummy - To test special tags and operation ID starting with number - parameter body: (body) client model - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ diff --git a/samples/client/petstore/swift6/promisekitLibrary/PetstoreClient/Classes/OpenAPIs/APIs/FakeAPI.swift b/samples/client/petstore/swift6/promisekitLibrary/PetstoreClient/Classes/OpenAPIs/APIs/FakeAPI.swift index 6efc49692f5e..5d41eda71d2b 100644 --- a/samples/client/petstore/swift6/promisekitLibrary/PetstoreClient/Classes/OpenAPIs/APIs/FakeAPI.swift +++ b/samples/client/petstore/swift6/promisekitLibrary/PetstoreClient/Classes/OpenAPIs/APIs/FakeAPI.swift @@ -33,7 +33,6 @@ open class FakeAPI { - POST /fake/outer/boolean - Test serialization of outer boolean types - parameter body: (body) Input boolean as post body (optional) - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -78,7 +77,6 @@ open class FakeAPI { - POST /fake/outer/composite - Test serialization of object with outer number type - parameter body: (body) Input composite as post body (optional) - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -123,7 +121,6 @@ open class FakeAPI { - POST /fake/outer/number - Test serialization of outer number types - parameter body: (body) Input number as post body (optional) - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -168,7 +165,6 @@ open class FakeAPI { - POST /fake/outer/string - Test serialization of outer string types - parameter body: (body) Input string as post body (optional) - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -213,7 +209,6 @@ open class FakeAPI { - PUT /fake/body-with-file-schema - For this test, the body for this request much reference a schema named `File`. - parameter body: (body) - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -258,8 +253,7 @@ open class FakeAPI { /** - PUT /fake/body-with-query-params - parameter query: (query) - - parameter body: (body) - + - parameter body: (body) - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -309,7 +303,6 @@ open class FakeAPI { - PATCH /fake - To test \"client\" model - parameter body: (body) client model - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -372,20 +365,19 @@ open class FakeAPI { - type: http - name: http_basic_test - parameter number: (form) None - - parameter double: (form) None - - parameter patternWithoutDelimiter: (form) None - - parameter byte: (form) None - - parameter integer: (form) None (optional) - - parameter int32: (form) None (optional) - - parameter int64: (form) None (optional) - - parameter float: (form) None (optional) - - parameter string: (form) None (optional) - - parameter binary: (form) None (optional) - - parameter date: (form) None (optional) - - parameter dateTime: (form) None (optional) - - parameter password: (form) None (optional) - - parameter callback: (form) None (optional) - + - parameter double: (form) None + - parameter patternWithoutDelimiter: (form) None + - parameter byte: (form) None + - parameter integer: (form) None (optional) + - parameter int32: (form) None (optional) + - parameter int64: (form) None (optional) + - parameter float: (form) None (optional) + - parameter string: (form) None (optional) + - parameter binary: (form) None (optional) + - parameter date: (form) None (optional) + - parameter dateTime: (form) None (optional) + - parameter password: (form) None (optional) + - parameter callback: (form) None (optional) - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -524,14 +516,13 @@ open class FakeAPI { - GET /fake - To test enum parameters - parameter enumHeaderStringArray: (header) Header parameter enum test (string array) (optional) - - parameter enumHeaderString: (header) Header parameter enum test (string) (optional, default to .efg) - - parameter enumQueryStringArray: (query) Query parameter enum test (string array) (optional) - - parameter enumQueryString: (query) Query parameter enum test (string) (optional, default to .efg) - - parameter enumQueryInteger: (query) Query parameter enum test (double) (optional) - - parameter enumQueryDouble: (query) Query parameter enum test (double) (optional) - - parameter enumFormStringArray: (form) Form parameter enum test (string array) (optional, default to .dollar) - - parameter enumFormString: (form) Form parameter enum test (string) (optional, default to .efg) - + - parameter enumHeaderString: (header) Header parameter enum test (string) (optional, default to .efg) + - parameter enumQueryStringArray: (query) Query parameter enum test (string array) (optional) + - parameter enumQueryString: (query) Query parameter enum test (string) (optional, default to .efg) + - parameter enumQueryInteger: (query) Query parameter enum test (double) (optional) + - parameter enumQueryDouble: (query) Query parameter enum test (double) (optional) + - parameter enumFormStringArray: (form) Form parameter enum test (string array) (optional, default to .dollar) + - parameter enumFormString: (form) Form parameter enum test (string) (optional, default to .efg) - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -597,12 +588,11 @@ open class FakeAPI { - DELETE /fake - Fake endpoint to test group parameters (optional) - parameter requiredStringGroup: (query) Required String in group parameters - - parameter requiredBooleanGroup: (header) Required Boolean in group parameters - - parameter requiredInt64Group: (query) Required Integer in group parameters - - parameter stringGroup: (query) String in group parameters (optional) - - parameter booleanGroup: (header) Boolean in group parameters (optional) - - parameter int64Group: (query) Integer in group parameters (optional) - + - parameter requiredBooleanGroup: (header) Required Boolean in group parameters + - parameter requiredInt64Group: (query) Required Integer in group parameters + - parameter stringGroup: (query) String in group parameters (optional) + - parameter booleanGroup: (header) Boolean in group parameters (optional) + - parameter int64Group: (query) Integer in group parameters (optional) - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -655,7 +645,6 @@ open class FakeAPI { test inline additionalProperties - POST /fake/inline-additionalProperties - parameter param: (body) request body - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -702,8 +691,7 @@ open class FakeAPI { test json serialization of form data - GET /fake/jsonFormData - parameter param: (form) field1 - - parameter param2: (form) field2 - + - parameter param2: (form) field2 - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ diff --git a/samples/client/petstore/swift6/promisekitLibrary/PetstoreClient/Classes/OpenAPIs/APIs/FakeClassnameTags123API.swift b/samples/client/petstore/swift6/promisekitLibrary/PetstoreClient/Classes/OpenAPIs/APIs/FakeClassnameTags123API.swift index 800a6a936485..9baae6e1b77e 100644 --- a/samples/client/petstore/swift6/promisekitLibrary/PetstoreClient/Classes/OpenAPIs/APIs/FakeClassnameTags123API.swift +++ b/samples/client/petstore/swift6/promisekitLibrary/PetstoreClient/Classes/OpenAPIs/APIs/FakeClassnameTags123API.swift @@ -38,7 +38,6 @@ open class FakeClassnameTags123API { - type: apiKey api_key_query (QUERY) - name: api_key_query - parameter body: (body) client model - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ diff --git a/samples/client/petstore/swift6/promisekitLibrary/PetstoreClient/Classes/OpenAPIs/APIs/PetAPI.swift b/samples/client/petstore/swift6/promisekitLibrary/PetstoreClient/Classes/OpenAPIs/APIs/PetAPI.swift index f4996b843bac..49c2cb23b53e 100644 --- a/samples/client/petstore/swift6/promisekitLibrary/PetstoreClient/Classes/OpenAPIs/APIs/PetAPI.swift +++ b/samples/client/petstore/swift6/promisekitLibrary/PetstoreClient/Classes/OpenAPIs/APIs/PetAPI.swift @@ -40,7 +40,6 @@ open class PetAPI { - type: apiKey api_key_query (QUERY) - name: api_key_query - parameter body: (body) Pet object that needs to be added to the store - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -90,8 +89,7 @@ open class PetAPI { - type: oauth2 - name: petstore_auth - parameter petId: (path) Pet id to delete - - parameter apiKey: (header) (optional) - + - parameter apiKey: (header) (optional) - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -153,7 +151,6 @@ open class PetAPI { - type: oauth2 - name: petstore_auth - parameter status: (query) Status values that need to be considered for filter - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder<[Pet]> */ @@ -207,7 +204,6 @@ open class PetAPI { - type: oauth2 - name: petstore_auth - parameter tags: (query) Tags to filter by - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder<[Pet]> */ @@ -261,7 +257,6 @@ open class PetAPI { - type: apiKey api_key (HEADER) - name: api_key - parameter petId: (path) ID of pet to return - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -313,7 +308,6 @@ open class PetAPI { - type: oauth2 - name: petstore_auth - parameter body: (body) Pet object that needs to be added to the store - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -364,9 +358,8 @@ open class PetAPI { - type: oauth2 - name: petstore_auth - parameter petId: (path) ID of pet that needs to be updated - - parameter name: (form) Updated name of the pet (optional) - - parameter status: (form) Updated status of the pet (optional) - + - parameter name: (form) Updated name of the pet (optional) + - parameter status: (form) Updated status of the pet (optional) - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -426,9 +419,8 @@ open class PetAPI { - type: oauth2 - name: petstore_auth - parameter petId: (path) ID of pet to update - - parameter additionalMetadata: (form) Additional data to pass to server (optional) - - parameter file: (form) file to upload (optional) - + - parameter additionalMetadata: (form) Additional data to pass to server (optional) + - parameter file: (form) file to upload (optional) - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -488,9 +480,8 @@ open class PetAPI { - type: oauth2 - name: petstore_auth - parameter petId: (path) ID of pet to update - - parameter requiredFile: (form) file to upload - - parameter additionalMetadata: (form) Additional data to pass to server (optional) - + - parameter requiredFile: (form) file to upload + - parameter additionalMetadata: (form) Additional data to pass to server (optional) - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ diff --git a/samples/client/petstore/swift6/promisekitLibrary/PetstoreClient/Classes/OpenAPIs/APIs/StoreAPI.swift b/samples/client/petstore/swift6/promisekitLibrary/PetstoreClient/Classes/OpenAPIs/APIs/StoreAPI.swift index 6958614e4e53..4bef5e3e8a32 100644 --- a/samples/client/petstore/swift6/promisekitLibrary/PetstoreClient/Classes/OpenAPIs/APIs/StoreAPI.swift +++ b/samples/client/petstore/swift6/promisekitLibrary/PetstoreClient/Classes/OpenAPIs/APIs/StoreAPI.swift @@ -35,7 +35,6 @@ open class StoreAPI { - DELETE /store/order/{order_id} - For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors - parameter orderId: (path) ID of the order that needs to be deleted - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -86,7 +85,6 @@ open class StoreAPI { - API Key: - type: apiKey api_key (HEADER) - name: api_key - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder<[String: Int]> */ @@ -133,7 +131,6 @@ open class StoreAPI { - GET /store/order/{order_id} - For valid response try integer IDs with value <= 5 or > 10. Other values will generate exceptions - parameter orderId: (path) ID of pet that needs to be fetched - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -182,7 +179,6 @@ open class StoreAPI { Place an order for a pet - POST /store/order - parameter body: (body) order placed for purchasing the pet - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ diff --git a/samples/client/petstore/swift6/promisekitLibrary/PetstoreClient/Classes/OpenAPIs/APIs/UserAPI.swift b/samples/client/petstore/swift6/promisekitLibrary/PetstoreClient/Classes/OpenAPIs/APIs/UserAPI.swift index ec6b1e72ec14..6c7d90aa3a0c 100644 --- a/samples/client/petstore/swift6/promisekitLibrary/PetstoreClient/Classes/OpenAPIs/APIs/UserAPI.swift +++ b/samples/client/petstore/swift6/promisekitLibrary/PetstoreClient/Classes/OpenAPIs/APIs/UserAPI.swift @@ -35,7 +35,6 @@ open class UserAPI { - POST /user - This can only be done by the logged in user. - parameter body: (body) Created user object - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -81,7 +80,6 @@ open class UserAPI { Creates list of users with given input array - POST /user/createWithArray - parameter body: (body) List of user object - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -127,7 +125,6 @@ open class UserAPI { Creates list of users with given input array - POST /user/createWithList - parameter body: (body) List of user object - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -174,7 +171,6 @@ open class UserAPI { - DELETE /user/{username} - This can only be done by the logged in user. - parameter username: (path) The name that needs to be deleted - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -223,7 +219,6 @@ open class UserAPI { Get user by user name - GET /user/{username} - parameter username: (path) The name that needs to be fetched. Use user1 for testing. - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -274,8 +269,7 @@ open class UserAPI { - GET /user/login - responseHeaders: [X-Rate-Limit(Int), X-Expires-After(Date)] - parameter username: (query) The user name for login - - parameter password: (query) The password for login in clear text - + - parameter password: (query) The password for login in clear text - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -323,7 +317,6 @@ open class UserAPI { /** Logs out current logged in user session - GET /user/logout - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -371,8 +364,7 @@ open class UserAPI { - PUT /user/{username} - This can only be done by the logged in user. - parameter username: (path) name that need to be deleted - - parameter body: (body) Updated user object - + - parameter body: (body) Updated user object - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ diff --git a/samples/client/petstore/swift6/promisekitLibrary/README.md b/samples/client/petstore/swift6/promisekitLibrary/README.md index 25f3ad847445..0b9710436990 100644 --- a/samples/client/petstore/swift6/promisekitLibrary/README.md +++ b/samples/client/petstore/swift6/promisekitLibrary/README.md @@ -140,6 +140,89 @@ Authentication schemes defined for the API: - **Type**: HTTP basic authentication +### How do I implement bearer token authentication with URLSession on the Swift 6 API client? + +First you implement the `OpenAPIInterceptor` protocol. +``` +public class BearerOpenAPIInterceptor: OpenAPIInterceptor { + public init() {} + + public func intercept(urlRequest: URLRequest, urlSession: URLSessionProtocol, openAPIClient: OpenAPIClient, completion: @escaping (Result) -> 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 diff --git a/samples/client/petstore/swift6/resultLibrary/PetstoreClient/Classes/OpenAPIs/APIs/AnotherFakeAPI.swift b/samples/client/petstore/swift6/resultLibrary/PetstoreClient/Classes/OpenAPIs/APIs/AnotherFakeAPI.swift index ab33b704befa..c16cca10dc73 100644 --- a/samples/client/petstore/swift6/resultLibrary/PetstoreClient/Classes/OpenAPIs/APIs/AnotherFakeAPI.swift +++ b/samples/client/petstore/swift6/resultLibrary/PetstoreClient/Classes/OpenAPIs/APIs/AnotherFakeAPI.swift @@ -33,7 +33,6 @@ internal class AnotherFakeAPI { - PATCH /another-fake/dummy - To test special tags and operation ID starting with number - parameter body: (body) client model - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ diff --git a/samples/client/petstore/swift6/resultLibrary/PetstoreClient/Classes/OpenAPIs/APIs/FakeAPI.swift b/samples/client/petstore/swift6/resultLibrary/PetstoreClient/Classes/OpenAPIs/APIs/FakeAPI.swift index a28c02beb410..a3a036328a7a 100644 --- a/samples/client/petstore/swift6/resultLibrary/PetstoreClient/Classes/OpenAPIs/APIs/FakeAPI.swift +++ b/samples/client/petstore/swift6/resultLibrary/PetstoreClient/Classes/OpenAPIs/APIs/FakeAPI.swift @@ -31,7 +31,6 @@ internal class FakeAPI { - POST /fake/outer/boolean - Test serialization of outer boolean types - parameter body: (body) Input boolean as post body (optional) - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -75,7 +74,6 @@ internal class FakeAPI { - POST /fake/outer/composite - Test serialization of object with outer number type - parameter body: (body) Input composite as post body (optional) - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -119,7 +117,6 @@ internal class FakeAPI { - POST /fake/outer/number - Test serialization of outer number types - parameter body: (body) Input number as post body (optional) - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -163,7 +160,6 @@ internal class FakeAPI { - POST /fake/outer/string - Test serialization of outer string types - parameter body: (body) Input string as post body (optional) - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -207,7 +203,6 @@ internal class FakeAPI { - PUT /fake/body-with-file-schema - For this test, the body for this request much reference a schema named `File`. - parameter body: (body) - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -251,8 +246,7 @@ internal class FakeAPI { /** - PUT /fake/body-with-query-params - parameter query: (query) - - parameter body: (body) - + - parameter body: (body) - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -301,7 +295,6 @@ internal class FakeAPI { - PATCH /fake - To test \"client\" model - parameter body: (body) client model - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -363,20 +356,19 @@ internal class FakeAPI { - type: http - name: http_basic_test - parameter integer: (form) None (optional) - - parameter int32: (form) None (optional) - - parameter int64: (form) None (optional) - - parameter number: (form) None - - parameter float: (form) None (optional) - - parameter double: (form) None - - parameter string: (form) None (optional) - - parameter patternWithoutDelimiter: (form) None - - parameter byte: (form) None - - parameter binary: (form) None (optional) - - parameter date: (form) None (optional) - - parameter dateTime: (form) None (optional) - - parameter password: (form) None (optional) - - parameter callback: (form) None (optional) - + - parameter int32: (form) None (optional) + - parameter int64: (form) None (optional) + - parameter number: (form) None + - parameter float: (form) None (optional) + - parameter double: (form) None + - parameter string: (form) None (optional) + - parameter patternWithoutDelimiter: (form) None + - parameter byte: (form) None + - parameter binary: (form) None (optional) + - parameter date: (form) None (optional) + - parameter dateTime: (form) None (optional) + - parameter password: (form) None (optional) + - parameter callback: (form) None (optional) - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -514,14 +506,13 @@ internal class FakeAPI { - GET /fake - To test enum parameters - parameter enumHeaderStringArray: (header) Header parameter enum test (string array) (optional) - - parameter enumHeaderString: (header) Header parameter enum test (string) (optional, default to .efg) - - parameter enumQueryStringArray: (query) Query parameter enum test (string array) (optional) - - parameter enumQueryString: (query) Query parameter enum test (string) (optional, default to .efg) - - parameter enumQueryInteger: (query) Query parameter enum test (double) (optional) - - parameter enumQueryDouble: (query) Query parameter enum test (double) (optional) - - parameter enumFormStringArray: (form) Form parameter enum test (string array) (optional, default to .dollar) - - parameter enumFormString: (form) Form parameter enum test (string) (optional, default to .efg) - + - parameter enumHeaderString: (header) Header parameter enum test (string) (optional, default to .efg) + - parameter enumQueryStringArray: (query) Query parameter enum test (string array) (optional) + - parameter enumQueryString: (query) Query parameter enum test (string) (optional, default to .efg) + - parameter enumQueryInteger: (query) Query parameter enum test (double) (optional) + - parameter enumQueryDouble: (query) Query parameter enum test (double) (optional) + - parameter enumFormStringArray: (form) Form parameter enum test (string array) (optional, default to .dollar) + - parameter enumFormString: (form) Form parameter enum test (string) (optional, default to .efg) - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -586,12 +577,11 @@ internal class FakeAPI { - DELETE /fake - Fake endpoint to test group parameters (optional) - parameter requiredStringGroup: (query) Required String in group parameters - - parameter requiredBooleanGroup: (header) Required Boolean in group parameters - - parameter requiredInt64Group: (query) Required Integer in group parameters - - parameter stringGroup: (query) String in group parameters (optional) - - parameter booleanGroup: (header) Boolean in group parameters (optional) - - parameter int64Group: (query) Integer in group parameters (optional) - + - parameter requiredBooleanGroup: (header) Required Boolean in group parameters + - parameter requiredInt64Group: (query) Required Integer in group parameters + - parameter stringGroup: (query) String in group parameters (optional) + - parameter booleanGroup: (header) Boolean in group parameters (optional) + - parameter int64Group: (query) Integer in group parameters (optional) - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -643,7 +633,6 @@ internal class FakeAPI { test inline additionalProperties - POST /fake/inline-additionalProperties - parameter param: (body) request body - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -689,8 +678,7 @@ internal class FakeAPI { test json serialization of form data - GET /fake/jsonFormData - parameter param: (form) field1 - - parameter param2: (form) field2 - + - parameter param2: (form) field2 - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ diff --git a/samples/client/petstore/swift6/resultLibrary/PetstoreClient/Classes/OpenAPIs/APIs/FakeClassnameTags123API.swift b/samples/client/petstore/swift6/resultLibrary/PetstoreClient/Classes/OpenAPIs/APIs/FakeClassnameTags123API.swift index 88d58e913da1..58799c12c0c0 100644 --- a/samples/client/petstore/swift6/resultLibrary/PetstoreClient/Classes/OpenAPIs/APIs/FakeClassnameTags123API.swift +++ b/samples/client/petstore/swift6/resultLibrary/PetstoreClient/Classes/OpenAPIs/APIs/FakeClassnameTags123API.swift @@ -36,7 +36,6 @@ internal class FakeClassnameTags123API { - type: apiKey api_key_query (QUERY) - name: api_key_query - parameter body: (body) client model - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ diff --git a/samples/client/petstore/swift6/resultLibrary/PetstoreClient/Classes/OpenAPIs/APIs/PetAPI.swift b/samples/client/petstore/swift6/resultLibrary/PetstoreClient/Classes/OpenAPIs/APIs/PetAPI.swift index 68a1cdf9a6e5..6f3d13022e78 100644 --- a/samples/client/petstore/swift6/resultLibrary/PetstoreClient/Classes/OpenAPIs/APIs/PetAPI.swift +++ b/samples/client/petstore/swift6/resultLibrary/PetstoreClient/Classes/OpenAPIs/APIs/PetAPI.swift @@ -38,7 +38,6 @@ internal class PetAPI { - type: apiKey api_key_query (QUERY) - name: api_key_query - parameter body: (body) Pet object that needs to be added to the store - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -87,8 +86,7 @@ internal class PetAPI { - type: oauth2 - name: petstore_auth - parameter apiKey: (header) (optional) - - parameter petId: (path) Pet id to delete - + - parameter petId: (path) Pet id to delete - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -149,7 +147,6 @@ internal class PetAPI { - type: oauth2 - name: petstore_auth - parameter status: (query) Status values that need to be considered for filter - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder<[Pet]> */ @@ -202,7 +199,6 @@ internal class PetAPI { - type: oauth2 - name: petstore_auth - parameter tags: (query) Tags to filter by - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder<[Pet]> */ @@ -255,7 +251,6 @@ internal class PetAPI { - type: apiKey api_key (HEADER) - name: api_key - parameter petId: (path) ID of pet to return - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -306,7 +301,6 @@ internal class PetAPI { - type: oauth2 - name: petstore_auth - parameter body: (body) Pet object that needs to be added to the store - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -356,9 +350,8 @@ internal class PetAPI { - type: oauth2 - name: petstore_auth - parameter petId: (path) ID of pet that needs to be updated - - parameter name: (form) Updated name of the pet (optional) - - parameter status: (form) Updated status of the pet (optional) - + - parameter name: (form) Updated name of the pet (optional) + - parameter status: (form) Updated status of the pet (optional) - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -417,9 +410,8 @@ internal class PetAPI { - type: oauth2 - name: petstore_auth - parameter petId: (path) ID of pet to update - - parameter additionalMetadata: (form) Additional data to pass to server (optional) - - parameter file: (form) file to upload (optional) - + - parameter additionalMetadata: (form) Additional data to pass to server (optional) + - parameter file: (form) file to upload (optional) - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -478,9 +470,8 @@ internal class PetAPI { - type: oauth2 - name: petstore_auth - parameter petId: (path) ID of pet to update - - parameter additionalMetadata: (form) Additional data to pass to server (optional) - - parameter requiredFile: (form) file to upload - + - parameter additionalMetadata: (form) Additional data to pass to server (optional) + - parameter requiredFile: (form) file to upload - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ diff --git a/samples/client/petstore/swift6/resultLibrary/PetstoreClient/Classes/OpenAPIs/APIs/StoreAPI.swift b/samples/client/petstore/swift6/resultLibrary/PetstoreClient/Classes/OpenAPIs/APIs/StoreAPI.swift index 7a32c200bd52..69e4ec57859c 100644 --- a/samples/client/petstore/swift6/resultLibrary/PetstoreClient/Classes/OpenAPIs/APIs/StoreAPI.swift +++ b/samples/client/petstore/swift6/resultLibrary/PetstoreClient/Classes/OpenAPIs/APIs/StoreAPI.swift @@ -33,7 +33,6 @@ internal class StoreAPI { - DELETE /store/order/{order_id} - For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors - parameter orderId: (path) ID of the order that needs to be deleted - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -83,7 +82,6 @@ internal class StoreAPI { - API Key: - type: apiKey api_key (HEADER) - name: api_key - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder<[String: Int]> */ @@ -129,7 +127,6 @@ internal class StoreAPI { - GET /store/order/{order_id} - For valid response try integer IDs with value <= 5 or > 10. Other values will generate exceptions - parameter orderId: (path) ID of pet that needs to be fetched - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -177,7 +174,6 @@ internal class StoreAPI { Place an order for a pet - POST /store/order - parameter body: (body) order placed for purchasing the pet - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ diff --git a/samples/client/petstore/swift6/resultLibrary/PetstoreClient/Classes/OpenAPIs/APIs/UserAPI.swift b/samples/client/petstore/swift6/resultLibrary/PetstoreClient/Classes/OpenAPIs/APIs/UserAPI.swift index a2a9d33df94c..77125960b4f9 100644 --- a/samples/client/petstore/swift6/resultLibrary/PetstoreClient/Classes/OpenAPIs/APIs/UserAPI.swift +++ b/samples/client/petstore/swift6/resultLibrary/PetstoreClient/Classes/OpenAPIs/APIs/UserAPI.swift @@ -33,7 +33,6 @@ internal class UserAPI { - POST /user - This can only be done by the logged in user. - parameter body: (body) Created user object - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -78,7 +77,6 @@ internal class UserAPI { Creates list of users with given input array - POST /user/createWithArray - parameter body: (body) List of user object - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -123,7 +121,6 @@ internal class UserAPI { Creates list of users with given input array - POST /user/createWithList - parameter body: (body) List of user object - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -169,7 +166,6 @@ internal class UserAPI { - DELETE /user/{username} - This can only be done by the logged in user. - parameter username: (path) The name that needs to be deleted - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -217,7 +213,6 @@ internal class UserAPI { Get user by user name - GET /user/{username} - parameter username: (path) The name that needs to be fetched. Use user1 for testing. - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -267,8 +262,7 @@ internal class UserAPI { - GET /user/login - responseHeaders: [X-Rate-Limit(Int), X-Expires-After(Date)] - parameter username: (query) The user name for login - - parameter password: (query) The password for login in clear text - + - parameter password: (query) The password for login in clear text - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -315,7 +309,6 @@ internal class UserAPI { /** Logs out current logged in user session - GET /user/logout - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -362,8 +355,7 @@ internal class UserAPI { - PUT /user/{username} - This can only be done by the logged in user. - parameter username: (path) name that need to be deleted - - parameter body: (body) Updated user object - + - parameter body: (body) Updated user object - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ diff --git a/samples/client/petstore/swift6/resultLibrary/README.md b/samples/client/petstore/swift6/resultLibrary/README.md index 25f3ad847445..0b9710436990 100644 --- a/samples/client/petstore/swift6/resultLibrary/README.md +++ b/samples/client/petstore/swift6/resultLibrary/README.md @@ -140,6 +140,89 @@ Authentication schemes defined for the API: - **Type**: HTTP basic authentication +### How do I implement bearer token authentication with URLSession on the Swift 6 API client? + +First you implement the `OpenAPIInterceptor` protocol. +``` +public class BearerOpenAPIInterceptor: OpenAPIInterceptor { + public init() {} + + public func intercept(urlRequest: URLRequest, urlSession: URLSessionProtocol, openAPIClient: OpenAPIClient, completion: @escaping (Result) -> 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 diff --git a/samples/client/petstore/swift6/rxswiftLibrary/PetstoreClient/Classes/OpenAPIs/APIs/AnotherFakeAPI.swift b/samples/client/petstore/swift6/rxswiftLibrary/PetstoreClient/Classes/OpenAPIs/APIs/AnotherFakeAPI.swift index 57e2b73b36db..c5d2e1f0e087 100644 --- a/samples/client/petstore/swift6/rxswiftLibrary/PetstoreClient/Classes/OpenAPIs/APIs/AnotherFakeAPI.swift +++ b/samples/client/petstore/swift6/rxswiftLibrary/PetstoreClient/Classes/OpenAPIs/APIs/AnotherFakeAPI.swift @@ -40,7 +40,6 @@ open class AnotherFakeAPI { - PATCH /another-fake/dummy - To test special tags and operation ID starting with number - parameter body: (body) client model - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ diff --git a/samples/client/petstore/swift6/rxswiftLibrary/PetstoreClient/Classes/OpenAPIs/APIs/FakeAPI.swift b/samples/client/petstore/swift6/rxswiftLibrary/PetstoreClient/Classes/OpenAPIs/APIs/FakeAPI.swift index b30b6f05a13a..6e0ec88f2015 100644 --- a/samples/client/petstore/swift6/rxswiftLibrary/PetstoreClient/Classes/OpenAPIs/APIs/FakeAPI.swift +++ b/samples/client/petstore/swift6/rxswiftLibrary/PetstoreClient/Classes/OpenAPIs/APIs/FakeAPI.swift @@ -38,7 +38,6 @@ open class FakeAPI { - POST /fake/outer/boolean - Test serialization of outer boolean types - parameter body: (body) Input boolean as post body (optional) - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -88,7 +87,6 @@ open class FakeAPI { - POST /fake/outer/composite - Test serialization of object with outer number type - parameter body: (body) Input composite as post body (optional) - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -138,7 +136,6 @@ open class FakeAPI { - POST /fake/outer/number - Test serialization of outer number types - parameter body: (body) Input number as post body (optional) - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -188,7 +185,6 @@ open class FakeAPI { - POST /fake/outer/string - Test serialization of outer string types - parameter body: (body) Input string as post body (optional) - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -238,7 +234,6 @@ open class FakeAPI { - PUT /fake/body-with-file-schema - For this test, the body for this request much reference a schema named `File`. - parameter body: (body) - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -288,8 +283,7 @@ open class FakeAPI { /** - PUT /fake/body-with-query-params - parameter query: (query) - - parameter body: (body) - + - parameter body: (body) - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -344,7 +338,6 @@ open class FakeAPI { - PATCH /fake - To test \"client\" model - parameter body: (body) client model - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -412,20 +405,19 @@ open class FakeAPI { - type: http - name: http_basic_test - parameter number: (form) None - - parameter double: (form) None - - parameter patternWithoutDelimiter: (form) None - - parameter byte: (form) None - - parameter integer: (form) None (optional) - - parameter int32: (form) None (optional) - - parameter int64: (form) None (optional) - - parameter float: (form) None (optional) - - parameter string: (form) None (optional) - - parameter binary: (form) None (optional) - - parameter date: (form) None (optional) - - parameter dateTime: (form) None (optional) - - parameter password: (form) None (optional) - - parameter callback: (form) None (optional) - + - parameter double: (form) None + - parameter patternWithoutDelimiter: (form) None + - parameter byte: (form) None + - parameter integer: (form) None (optional) + - parameter int32: (form) None (optional) + - parameter int64: (form) None (optional) + - parameter float: (form) None (optional) + - parameter string: (form) None (optional) + - parameter binary: (form) None (optional) + - parameter date: (form) None (optional) + - parameter dateTime: (form) None (optional) + - parameter password: (form) None (optional) + - parameter callback: (form) None (optional) - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -569,14 +561,13 @@ open class FakeAPI { - GET /fake - To test enum parameters - parameter enumHeaderStringArray: (header) Header parameter enum test (string array) (optional) - - parameter enumHeaderString: (header) Header parameter enum test (string) (optional, default to .efg) - - parameter enumQueryStringArray: (query) Query parameter enum test (string array) (optional) - - parameter enumQueryString: (query) Query parameter enum test (string) (optional, default to .efg) - - parameter enumQueryInteger: (query) Query parameter enum test (double) (optional) - - parameter enumQueryDouble: (query) Query parameter enum test (double) (optional) - - parameter enumFormStringArray: (form) Form parameter enum test (string array) (optional, default to .dollar) - - parameter enumFormString: (form) Form parameter enum test (string) (optional, default to .efg) - + - parameter enumHeaderString: (header) Header parameter enum test (string) (optional, default to .efg) + - parameter enumQueryStringArray: (query) Query parameter enum test (string array) (optional) + - parameter enumQueryString: (query) Query parameter enum test (string) (optional, default to .efg) + - parameter enumQueryInteger: (query) Query parameter enum test (double) (optional) + - parameter enumQueryDouble: (query) Query parameter enum test (double) (optional) + - parameter enumFormStringArray: (form) Form parameter enum test (string array) (optional, default to .dollar) + - parameter enumFormString: (form) Form parameter enum test (string) (optional, default to .efg) - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -647,12 +638,11 @@ open class FakeAPI { - DELETE /fake - Fake endpoint to test group parameters (optional) - parameter requiredStringGroup: (query) Required String in group parameters - - parameter requiredBooleanGroup: (header) Required Boolean in group parameters - - parameter requiredInt64Group: (query) Required Integer in group parameters - - parameter stringGroup: (query) String in group parameters (optional) - - parameter booleanGroup: (header) Boolean in group parameters (optional) - - parameter int64Group: (query) Integer in group parameters (optional) - + - parameter requiredBooleanGroup: (header) Required Boolean in group parameters + - parameter requiredInt64Group: (query) Required Integer in group parameters + - parameter stringGroup: (query) String in group parameters (optional) + - parameter booleanGroup: (header) Boolean in group parameters (optional) + - parameter int64Group: (query) Integer in group parameters (optional) - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -710,7 +700,6 @@ open class FakeAPI { test inline additionalProperties - POST /fake/inline-additionalProperties - parameter param: (body) request body - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -762,8 +751,7 @@ open class FakeAPI { test json serialization of form data - GET /fake/jsonFormData - parameter param: (form) field1 - - parameter param2: (form) field2 - + - parameter param2: (form) field2 - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ diff --git a/samples/client/petstore/swift6/rxswiftLibrary/PetstoreClient/Classes/OpenAPIs/APIs/FakeClassnameTags123API.swift b/samples/client/petstore/swift6/rxswiftLibrary/PetstoreClient/Classes/OpenAPIs/APIs/FakeClassnameTags123API.swift index 7dfc83cfe915..38a9ee53a106 100644 --- a/samples/client/petstore/swift6/rxswiftLibrary/PetstoreClient/Classes/OpenAPIs/APIs/FakeClassnameTags123API.swift +++ b/samples/client/petstore/swift6/rxswiftLibrary/PetstoreClient/Classes/OpenAPIs/APIs/FakeClassnameTags123API.swift @@ -43,7 +43,6 @@ open class FakeClassnameTags123API { - type: apiKey api_key_query (QUERY) - name: api_key_query - parameter body: (body) client model - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ diff --git a/samples/client/petstore/swift6/rxswiftLibrary/PetstoreClient/Classes/OpenAPIs/APIs/PetAPI.swift b/samples/client/petstore/swift6/rxswiftLibrary/PetstoreClient/Classes/OpenAPIs/APIs/PetAPI.swift index 5bc02d9f5141..50b53724c797 100644 --- a/samples/client/petstore/swift6/rxswiftLibrary/PetstoreClient/Classes/OpenAPIs/APIs/PetAPI.swift +++ b/samples/client/petstore/swift6/rxswiftLibrary/PetstoreClient/Classes/OpenAPIs/APIs/PetAPI.swift @@ -45,7 +45,6 @@ open class PetAPI { - type: apiKey api_key_query (QUERY) - name: api_key_query - parameter body: (body) Pet object that needs to be added to the store - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -100,8 +99,7 @@ open class PetAPI { - type: oauth2 - name: petstore_auth - parameter petId: (path) Pet id to delete - - parameter apiKey: (header) (optional) - + - parameter apiKey: (header) (optional) - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -168,7 +166,6 @@ open class PetAPI { - type: oauth2 - name: petstore_auth - parameter status: (query) Status values that need to be considered for filter - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder<[Pet]> */ @@ -227,7 +224,6 @@ open class PetAPI { - type: oauth2 - name: petstore_auth - parameter tags: (query) Tags to filter by - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder<[Pet]> */ @@ -286,7 +282,6 @@ open class PetAPI { - type: apiKey api_key (HEADER) - name: api_key - parameter petId: (path) ID of pet to return - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -343,7 +338,6 @@ open class PetAPI { - type: oauth2 - name: petstore_auth - parameter body: (body) Pet object that needs to be added to the store - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -399,9 +393,8 @@ open class PetAPI { - type: oauth2 - name: petstore_auth - parameter petId: (path) ID of pet that needs to be updated - - parameter name: (form) Updated name of the pet (optional) - - parameter status: (form) Updated status of the pet (optional) - + - parameter name: (form) Updated name of the pet (optional) + - parameter status: (form) Updated status of the pet (optional) - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -466,9 +459,8 @@ open class PetAPI { - type: oauth2 - name: petstore_auth - parameter petId: (path) ID of pet to update - - parameter additionalMetadata: (form) Additional data to pass to server (optional) - - parameter file: (form) file to upload (optional) - + - parameter additionalMetadata: (form) Additional data to pass to server (optional) + - parameter file: (form) file to upload (optional) - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -533,9 +525,8 @@ open class PetAPI { - type: oauth2 - name: petstore_auth - parameter petId: (path) ID of pet to update - - parameter requiredFile: (form) file to upload - - parameter additionalMetadata: (form) Additional data to pass to server (optional) - + - parameter requiredFile: (form) file to upload + - parameter additionalMetadata: (form) Additional data to pass to server (optional) - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ diff --git a/samples/client/petstore/swift6/rxswiftLibrary/PetstoreClient/Classes/OpenAPIs/APIs/StoreAPI.swift b/samples/client/petstore/swift6/rxswiftLibrary/PetstoreClient/Classes/OpenAPIs/APIs/StoreAPI.swift index 7931468eef2a..0b600996ca6e 100644 --- a/samples/client/petstore/swift6/rxswiftLibrary/PetstoreClient/Classes/OpenAPIs/APIs/StoreAPI.swift +++ b/samples/client/petstore/swift6/rxswiftLibrary/PetstoreClient/Classes/OpenAPIs/APIs/StoreAPI.swift @@ -40,7 +40,6 @@ open class StoreAPI { - DELETE /store/order/{order_id} - For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors - parameter orderId: (path) ID of the order that needs to be deleted - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -96,7 +95,6 @@ open class StoreAPI { - API Key: - type: apiKey api_key (HEADER) - name: api_key - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder<[String: Int]> */ @@ -148,7 +146,6 @@ open class StoreAPI { - GET /store/order/{order_id} - For valid response try integer IDs with value <= 5 or > 10. Other values will generate exceptions - parameter orderId: (path) ID of pet that needs to be fetched - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -202,7 +199,6 @@ open class StoreAPI { Place an order for a pet - POST /store/order - parameter body: (body) order placed for purchasing the pet - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ diff --git a/samples/client/petstore/swift6/rxswiftLibrary/PetstoreClient/Classes/OpenAPIs/APIs/UserAPI.swift b/samples/client/petstore/swift6/rxswiftLibrary/PetstoreClient/Classes/OpenAPIs/APIs/UserAPI.swift index a20fed6a62c2..c4f38351a52d 100644 --- a/samples/client/petstore/swift6/rxswiftLibrary/PetstoreClient/Classes/OpenAPIs/APIs/UserAPI.swift +++ b/samples/client/petstore/swift6/rxswiftLibrary/PetstoreClient/Classes/OpenAPIs/APIs/UserAPI.swift @@ -40,7 +40,6 @@ open class UserAPI { - POST /user - This can only be done by the logged in user. - parameter body: (body) Created user object - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -91,7 +90,6 @@ open class UserAPI { Creates list of users with given input array - POST /user/createWithArray - parameter body: (body) List of user object - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -142,7 +140,6 @@ open class UserAPI { Creates list of users with given input array - POST /user/createWithList - parameter body: (body) List of user object - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -194,7 +191,6 @@ open class UserAPI { - DELETE /user/{username} - This can only be done by the logged in user. - parameter username: (path) The name that needs to be deleted - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -248,7 +244,6 @@ open class UserAPI { Get user by user name - GET /user/{username} - parameter username: (path) The name that needs to be fetched. Use user1 for testing. - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -304,8 +299,7 @@ open class UserAPI { - GET /user/login - responseHeaders: [X-Rate-Limit(Int), X-Expires-After(Date)] - parameter username: (query) The user name for login - - parameter password: (query) The password for login in clear text - + - parameter password: (query) The password for login in clear text - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -358,7 +352,6 @@ open class UserAPI { /** Logs out current logged in user session - GET /user/logout - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -411,8 +404,7 @@ open class UserAPI { - PUT /user/{username} - This can only be done by the logged in user. - parameter username: (path) name that need to be deleted - - parameter body: (body) Updated user object - + - parameter body: (body) Updated user object - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ diff --git a/samples/client/petstore/swift6/rxswiftLibrary/README.md b/samples/client/petstore/swift6/rxswiftLibrary/README.md index 25f3ad847445..0b9710436990 100644 --- a/samples/client/petstore/swift6/rxswiftLibrary/README.md +++ b/samples/client/petstore/swift6/rxswiftLibrary/README.md @@ -140,6 +140,89 @@ Authentication schemes defined for the API: - **Type**: HTTP basic authentication +### How do I implement bearer token authentication with URLSession on the Swift 6 API client? + +First you implement the `OpenAPIInterceptor` protocol. +``` +public class BearerOpenAPIInterceptor: OpenAPIInterceptor { + public init() {} + + public func intercept(urlRequest: URLRequest, urlSession: URLSessionProtocol, openAPIClient: OpenAPIClient, completion: @escaping (Result) -> 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 diff --git a/samples/client/petstore/swift6/urlsessionLibrary/README.md b/samples/client/petstore/swift6/urlsessionLibrary/README.md index 25f3ad847445..0b9710436990 100644 --- a/samples/client/petstore/swift6/urlsessionLibrary/README.md +++ b/samples/client/petstore/swift6/urlsessionLibrary/README.md @@ -140,6 +140,89 @@ Authentication schemes defined for the API: - **Type**: HTTP basic authentication +### How do I implement bearer token authentication with URLSession on the Swift 6 API client? + +First you implement the `OpenAPIInterceptor` protocol. +``` +public class BearerOpenAPIInterceptor: OpenAPIInterceptor { + public init() {} + + public func intercept(urlRequest: URLRequest, urlSession: URLSessionProtocol, openAPIClient: OpenAPIClient, completion: @escaping (Result) -> 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 diff --git a/samples/client/petstore/swift6/urlsessionLibrary/Sources/PetstoreClient/APIs/AnotherFakeAPI.swift b/samples/client/petstore/swift6/urlsessionLibrary/Sources/PetstoreClient/APIs/AnotherFakeAPI.swift index 01f923edfa0e..9837742a23b3 100644 --- a/samples/client/petstore/swift6/urlsessionLibrary/Sources/PetstoreClient/APIs/AnotherFakeAPI.swift +++ b/samples/client/petstore/swift6/urlsessionLibrary/Sources/PetstoreClient/APIs/AnotherFakeAPI.swift @@ -36,7 +36,6 @@ open class AnotherFakeAPI { - PATCH /another-fake/dummy - To test special tags and operation ID starting with number - parameter body: (body) client model - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ diff --git a/samples/client/petstore/swift6/urlsessionLibrary/Sources/PetstoreClient/APIs/FakeAPI.swift b/samples/client/petstore/swift6/urlsessionLibrary/Sources/PetstoreClient/APIs/FakeAPI.swift index 12fa67f70c97..e4091ba52a42 100644 --- a/samples/client/petstore/swift6/urlsessionLibrary/Sources/PetstoreClient/APIs/FakeAPI.swift +++ b/samples/client/petstore/swift6/urlsessionLibrary/Sources/PetstoreClient/APIs/FakeAPI.swift @@ -34,7 +34,6 @@ open class FakeAPI { - POST /fake/outer/boolean - Test serialization of outer boolean types - parameter body: (body) Input boolean as post body (optional) - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -78,7 +77,6 @@ open class FakeAPI { - POST /fake/outer/composite - Test serialization of object with outer number type - parameter body: (body) Input composite as post body (optional) - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -122,7 +120,6 @@ open class FakeAPI { - POST /fake/outer/number - Test serialization of outer number types - parameter body: (body) Input number as post body (optional) - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -166,7 +163,6 @@ open class FakeAPI { - POST /fake/outer/string - Test serialization of outer string types - parameter body: (body) Input string as post body (optional) - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -210,7 +206,6 @@ open class FakeAPI { - PUT /fake/body-with-file-schema - For this test, the body for this request much reference a schema named `File`. - parameter body: (body) - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -254,8 +249,7 @@ open class FakeAPI { /** - PUT /fake/body-with-query-params - parameter query: (query) - - parameter body: (body) - + - parameter body: (body) - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -304,7 +298,6 @@ open class FakeAPI { - PATCH /fake - To test \"client\" model - parameter body: (body) client model - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -366,20 +359,19 @@ open class FakeAPI { - type: http - name: http_basic_test - parameter number: (form) None - - parameter double: (form) None - - parameter patternWithoutDelimiter: (form) None - - parameter byte: (form) None - - parameter integer: (form) None (optional) - - parameter int32: (form) None (optional) - - parameter int64: (form) None (optional) - - parameter float: (form) None (optional) - - parameter string: (form) None (optional) - - parameter binary: (form) None (optional) - - parameter date: (form) None (optional) - - parameter dateTime: (form) None (optional) - - parameter password: (form) None (optional) - - parameter callback: (form) None (optional) - + - parameter double: (form) None + - parameter patternWithoutDelimiter: (form) None + - parameter byte: (form) None + - parameter integer: (form) None (optional) + - parameter int32: (form) None (optional) + - parameter int64: (form) None (optional) + - parameter float: (form) None (optional) + - parameter string: (form) None (optional) + - parameter binary: (form) None (optional) + - parameter date: (form) None (optional) + - parameter dateTime: (form) None (optional) + - parameter password: (form) None (optional) + - parameter callback: (form) None (optional) - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -517,14 +509,13 @@ open class FakeAPI { - GET /fake - To test enum parameters - parameter enumHeaderStringArray: (header) Header parameter enum test (string array) (optional) - - parameter enumHeaderString: (header) Header parameter enum test (string) (optional, default to .efg) - - parameter enumQueryStringArray: (query) Query parameter enum test (string array) (optional) - - parameter enumQueryString: (query) Query parameter enum test (string) (optional, default to .efg) - - parameter enumQueryInteger: (query) Query parameter enum test (double) (optional) - - parameter enumQueryDouble: (query) Query parameter enum test (double) (optional) - - parameter enumFormStringArray: (form) Form parameter enum test (string array) (optional, default to .dollar) - - parameter enumFormString: (form) Form parameter enum test (string) (optional, default to .efg) - + - parameter enumHeaderString: (header) Header parameter enum test (string) (optional, default to .efg) + - parameter enumQueryStringArray: (query) Query parameter enum test (string array) (optional) + - parameter enumQueryString: (query) Query parameter enum test (string) (optional, default to .efg) + - parameter enumQueryInteger: (query) Query parameter enum test (double) (optional) + - parameter enumQueryDouble: (query) Query parameter enum test (double) (optional) + - parameter enumFormStringArray: (form) Form parameter enum test (string array) (optional, default to .dollar) + - parameter enumFormString: (form) Form parameter enum test (string) (optional, default to .efg) - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -589,12 +580,11 @@ open class FakeAPI { - DELETE /fake - Fake endpoint to test group parameters (optional) - parameter requiredStringGroup: (query) Required String in group parameters - - parameter requiredBooleanGroup: (header) Required Boolean in group parameters - - parameter requiredInt64Group: (query) Required Integer in group parameters - - parameter stringGroup: (query) String in group parameters (optional) - - parameter booleanGroup: (header) Boolean in group parameters (optional) - - parameter int64Group: (query) Integer in group parameters (optional) - + - parameter requiredBooleanGroup: (header) Required Boolean in group parameters + - parameter requiredInt64Group: (query) Required Integer in group parameters + - parameter stringGroup: (query) String in group parameters (optional) + - parameter booleanGroup: (header) Boolean in group parameters (optional) + - parameter int64Group: (query) Integer in group parameters (optional) - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -646,7 +636,6 @@ open class FakeAPI { test inline additionalProperties - POST /fake/inline-additionalProperties - parameter param: (body) request body - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -692,8 +681,7 @@ open class FakeAPI { test json serialization of form data - GET /fake/jsonFormData - parameter param: (form) field1 - - parameter param2: (form) field2 - + - parameter param2: (form) field2 - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ diff --git a/samples/client/petstore/swift6/urlsessionLibrary/Sources/PetstoreClient/APIs/FakeClassnameTags123API.swift b/samples/client/petstore/swift6/urlsessionLibrary/Sources/PetstoreClient/APIs/FakeClassnameTags123API.swift index 0c22d54f3986..02d9328685ac 100644 --- a/samples/client/petstore/swift6/urlsessionLibrary/Sources/PetstoreClient/APIs/FakeClassnameTags123API.swift +++ b/samples/client/petstore/swift6/urlsessionLibrary/Sources/PetstoreClient/APIs/FakeClassnameTags123API.swift @@ -39,7 +39,6 @@ open class FakeClassnameTags123API { - type: apiKey api_key_query (QUERY) - name: api_key_query - parameter body: (body) client model - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ diff --git a/samples/client/petstore/swift6/urlsessionLibrary/Sources/PetstoreClient/APIs/PetAPI.swift b/samples/client/petstore/swift6/urlsessionLibrary/Sources/PetstoreClient/APIs/PetAPI.swift index 563d2e2794d3..c353281f7b4b 100644 --- a/samples/client/petstore/swift6/urlsessionLibrary/Sources/PetstoreClient/APIs/PetAPI.swift +++ b/samples/client/petstore/swift6/urlsessionLibrary/Sources/PetstoreClient/APIs/PetAPI.swift @@ -41,7 +41,6 @@ open class PetAPI { - type: apiKey api_key_query (QUERY) - name: api_key_query - parameter body: (body) Pet object that needs to be added to the store - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -90,8 +89,7 @@ open class PetAPI { - type: oauth2 - name: petstore_auth - parameter petId: (path) Pet id to delete - - parameter apiKey: (header) (optional) - + - parameter apiKey: (header) (optional) - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -152,7 +150,6 @@ open class PetAPI { - type: oauth2 - name: petstore_auth - parameter status: (query) Status values that need to be considered for filter - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder<[Pet]> */ @@ -205,7 +202,6 @@ open class PetAPI { - type: oauth2 - name: petstore_auth - parameter tags: (query) Tags to filter by - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder<[Pet]> */ @@ -258,7 +254,6 @@ open class PetAPI { - type: apiKey api_key (HEADER) - name: api_key - parameter petId: (path) ID of pet to return - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -309,7 +304,6 @@ open class PetAPI { - type: oauth2 - name: petstore_auth - parameter body: (body) Pet object that needs to be added to the store - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -359,9 +353,8 @@ open class PetAPI { - type: oauth2 - name: petstore_auth - parameter petId: (path) ID of pet that needs to be updated - - parameter name: (form) Updated name of the pet (optional) - - parameter status: (form) Updated status of the pet (optional) - + - parameter name: (form) Updated name of the pet (optional) + - parameter status: (form) Updated status of the pet (optional) - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -420,9 +413,8 @@ open class PetAPI { - type: oauth2 - name: petstore_auth - parameter petId: (path) ID of pet to update - - parameter additionalMetadata: (form) Additional data to pass to server (optional) - - parameter file: (form) file to upload (optional) - + - parameter additionalMetadata: (form) Additional data to pass to server (optional) + - parameter file: (form) file to upload (optional) - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -481,9 +473,8 @@ open class PetAPI { - type: oauth2 - name: petstore_auth - parameter petId: (path) ID of pet to update - - parameter requiredFile: (form) file to upload - - parameter additionalMetadata: (form) Additional data to pass to server (optional) - + - parameter requiredFile: (form) file to upload + - parameter additionalMetadata: (form) Additional data to pass to server (optional) - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ diff --git a/samples/client/petstore/swift6/urlsessionLibrary/Sources/PetstoreClient/APIs/StoreAPI.swift b/samples/client/petstore/swift6/urlsessionLibrary/Sources/PetstoreClient/APIs/StoreAPI.swift index 8546019a53a8..84b65132f6f0 100644 --- a/samples/client/petstore/swift6/urlsessionLibrary/Sources/PetstoreClient/APIs/StoreAPI.swift +++ b/samples/client/petstore/swift6/urlsessionLibrary/Sources/PetstoreClient/APIs/StoreAPI.swift @@ -36,7 +36,6 @@ open class StoreAPI { - DELETE /store/order/{order_id} - For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors - parameter orderId: (path) ID of the order that needs to be deleted - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -86,7 +85,6 @@ open class StoreAPI { - API Key: - type: apiKey api_key (HEADER) - name: api_key - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder<[String: Int]> */ @@ -132,7 +130,6 @@ open class StoreAPI { - GET /store/order/{order_id} - For valid response try integer IDs with value <= 5 or > 10. Other values will generate exceptions - parameter orderId: (path) ID of pet that needs to be fetched - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -180,7 +177,6 @@ open class StoreAPI { Place an order for a pet - POST /store/order - parameter body: (body) order placed for purchasing the pet - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ diff --git a/samples/client/petstore/swift6/urlsessionLibrary/Sources/PetstoreClient/APIs/UserAPI.swift b/samples/client/petstore/swift6/urlsessionLibrary/Sources/PetstoreClient/APIs/UserAPI.swift index 5f466e3c1227..ac5d901c051e 100644 --- a/samples/client/petstore/swift6/urlsessionLibrary/Sources/PetstoreClient/APIs/UserAPI.swift +++ b/samples/client/petstore/swift6/urlsessionLibrary/Sources/PetstoreClient/APIs/UserAPI.swift @@ -36,7 +36,6 @@ open class UserAPI { - POST /user - This can only be done by the logged in user. - parameter body: (body) Created user object - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -81,7 +80,6 @@ open class UserAPI { Creates list of users with given input array - POST /user/createWithArray - parameter body: (body) List of user object - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -126,7 +124,6 @@ open class UserAPI { Creates list of users with given input array - POST /user/createWithList - parameter body: (body) List of user object - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -172,7 +169,6 @@ open class UserAPI { - DELETE /user/{username} - This can only be done by the logged in user. - parameter username: (path) The name that needs to be deleted - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -220,7 +216,6 @@ open class UserAPI { Get user by user name - GET /user/{username} - parameter username: (path) The name that needs to be fetched. Use user1 for testing. - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -270,8 +265,7 @@ open class UserAPI { - GET /user/login - responseHeaders: [X-Rate-Limit(Int), X-Expires-After(Date)] - parameter username: (query) The user name for login - - parameter password: (query) The password for login in clear text - + - parameter password: (query) The password for login in clear text - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -318,7 +312,6 @@ open class UserAPI { /** Logs out current logged in user session - GET /user/logout - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ @@ -365,8 +358,7 @@ open class UserAPI { - PUT /user/{username} - This can only be done by the logged in user. - parameter username: (path) name that need to be deleted - - parameter body: (body) Updated user object - + - parameter body: (body) Updated user object - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ diff --git a/samples/client/petstore/swift6/urlsessionLibrary/SwaggerClientTests/SwaggerClient/BearerTokenHandler.swift b/samples/client/petstore/swift6/urlsessionLibrary/SwaggerClientTests/SwaggerClient/BearerTokenHandler.swift index 25d06ebefc33..a05f8a8ca140 100644 --- a/samples/client/petstore/swift6/urlsessionLibrary/SwaggerClientTests/SwaggerClient/BearerTokenHandler.swift +++ b/samples/client/petstore/swift6/urlsessionLibrary/SwaggerClientTests/SwaggerClient/BearerTokenHandler.swift @@ -13,7 +13,7 @@ public class BearerOpenAPIInterceptor: OpenAPIInterceptor { public init() {} public func intercept(urlRequest: URLRequest, urlSession: URLSessionProtocol, openAPIClient: OpenAPIClient, completion: @escaping (Result) -> Void) { - BearerTokenHandler.shared.refreshTokenIfDoesntExist { token in + refreshTokenIfDoesntExist { token in // Change the current url request var newUrlRequest = urlRequest @@ -28,7 +28,7 @@ public class BearerOpenAPIInterceptor: OpenAPIInterceptor { 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 - BearerTokenHandler.shared.refreshTokenIfUnauthorizedRequestResponse( + refreshTokenIfUnauthorizedRequestResponse( data: data, response: response, error: error @@ -46,12 +46,6 @@ public class BearerOpenAPIInterceptor: OpenAPIInterceptor { } } } -} - -class BearerTokenHandler: @unchecked Sendable { - private init() {} - static let shared = BearerTokenHandler() - private var bearerToken: String? = nil diff --git a/samples/client/petstore/swift6/validation/PetstoreClient/Classes/OpenAPIs/APIs/DefaultAPI.swift b/samples/client/petstore/swift6/validation/PetstoreClient/Classes/OpenAPIs/APIs/DefaultAPI.swift index c96e65914c4c..cacf82e53c71 100644 --- a/samples/client/petstore/swift6/validation/PetstoreClient/Classes/OpenAPIs/APIs/DefaultAPI.swift +++ b/samples/client/petstore/swift6/validation/PetstoreClient/Classes/OpenAPIs/APIs/DefaultAPI.swift @@ -21,7 +21,6 @@ open class DefaultAPI { /** - GET / - - parameter openAPIClient: The OpenAPIClient that contains the configuration for the http request. - returns: RequestBuilder */ diff --git a/samples/client/petstore/swift6/validation/README.md b/samples/client/petstore/swift6/validation/README.md index 8f005ad0d749..7836c8cc6e7a 100644 --- a/samples/client/petstore/swift6/validation/README.md +++ b/samples/client/petstore/swift6/validation/README.md @@ -40,6 +40,89 @@ Class | Method | HTTP request | Description Endpoints do not require authorization. +### How do I implement bearer token authentication with URLSession on the Swift 6 API client? + +First you implement the `OpenAPIInterceptor` protocol. +``` +public class BearerOpenAPIInterceptor: OpenAPIInterceptor { + public init() {} + + public func intercept(urlRequest: URLRequest, urlSession: URLSessionProtocol, openAPIClient: OpenAPIClient, completion: @escaping (Result) -> 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 diff --git a/samples/client/petstore/swift6/vaporLibrary/README.md b/samples/client/petstore/swift6/vaporLibrary/README.md index 647f9326704b..ccce3778272a 100644 --- a/samples/client/petstore/swift6/vaporLibrary/README.md +++ b/samples/client/petstore/swift6/vaporLibrary/README.md @@ -147,6 +147,7 @@ Authentication schemes defined for the API: - **Type**: HTTP basic authentication + ## Author