From b01271bfdae7f91ec52e2af3f2a30423c7d4cdb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20Rusi=C5=88=C3=A1k?= <1114245+spigo@users.noreply.github.com> Date: Thu, 8 Oct 2026 13:35:16 +0200 Subject: [PATCH 1/4] [swift6] Fail requests instead of crashing, and don't send a body that failed to encode The alamofire and urlsession request builders called fatalError for an unsupported HTTP method, Content-Type, multipart/octet-stream parameter value or response type, and the alamofire builder force-unwrapped parameters and responses. Fail the request instead with the new RequestBuilderError (status 415, as urlsession already uses for requests that can't be created) or DecodableRequestBuilderError.nilHTTPResponse (-2). JSONEncodingHelper only printed a JSON body encoding error, so the request went out without a body. Hand the error to the request builder, which fails the request with RequestBuilderError.bodyEncodingFailed. Update swift6 samples. --- .../swift6/JSONEncodingHelper.mustache | 4 +- .../src/main/resources/swift6/Models.mustache | 8 ++ .../AlamofireImplementations.mustache | 77 ++++++++++++++++--- .../URLSessionImplementations.mustache | 38 +++++---- .../AlamofireImplementations.swift | 77 ++++++++++++++++--- .../Infrastructure/JSONEncodingHelper.swift | 4 +- .../Infrastructure/Models.swift | 8 ++ .../AlamofireImplementations.swift | 77 ++++++++++++++++--- .../Infrastructure/JSONEncodingHelper.swift | 4 +- .../Infrastructure/Models.swift | 8 ++ .../Infrastructure/JSONEncodingHelper.swift | 4 +- .../Infrastructure/Models.swift | 8 ++ .../URLSessionImplementations.swift | 38 +++++---- .../Infrastructure/JSONEncodingHelper.swift | 4 +- .../OpenAPIs/Infrastructure/Models.swift | 8 ++ .../URLSessionImplementations.swift | 38 +++++---- .../Infrastructure/JSONEncodingHelper.swift | 4 +- .../Infrastructure/Models.swift | 8 ++ .../URLSessionImplementations.swift | 38 +++++---- .../Infrastructure/JSONEncodingHelper.swift | 4 +- .../Infrastructure/Models.swift | 8 ++ .../URLSessionImplementations.swift | 38 +++++---- .../Infrastructure/JSONEncodingHelper.swift | 4 +- .../Infrastructure/Models.swift | 8 ++ .../URLSessionImplementations.swift | 38 +++++---- .../Infrastructure/JSONEncodingHelper.swift | 4 +- .../OpenAPIs/Infrastructure/Models.swift | 8 ++ .../URLSessionImplementations.swift | 38 +++++---- .../Infrastructure/JSONEncodingHelper.swift | 4 +- .../OpenAPIs/Infrastructure/Models.swift | 8 ++ .../URLSessionImplementations.swift | 38 +++++---- .../Infrastructure/JSONEncodingHelper.swift | 4 +- .../OpenAPIs/Infrastructure/Models.swift | 8 ++ .../URLSessionImplementations.swift | 38 +++++---- .../Infrastructure/JSONEncodingHelper.swift | 4 +- .../OpenAPIs/Infrastructure/Models.swift | 8 ++ .../URLSessionImplementations.swift | 38 +++++---- .../Infrastructure/JSONEncodingHelper.swift | 4 +- .../Infrastructure/Models.swift | 8 ++ .../URLSessionImplementations.swift | 38 +++++---- .../Infrastructure/JSONEncodingHelper.swift | 4 +- .../OpenAPIs/Infrastructure/Models.swift | 8 ++ .../URLSessionImplementations.swift | 38 +++++---- 43 files changed, 652 insertions(+), 203 deletions(-) diff --git a/modules/openapi-generator/src/main/resources/swift6/JSONEncodingHelper.mustache b/modules/openapi-generator/src/main/resources/swift6/JSONEncodingHelper.mustache index d6e7308600f6..5c9caa492f3d 100644 --- a/modules/openapi-generator/src/main/resources/swift6/JSONEncodingHelper.mustache +++ b/modules/openapi-generator/src/main/resources/swift6/JSONEncodingHelper.mustache @@ -9,6 +9,8 @@ import Foundation {{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}open{{/nonPublicApi}} class JSONEncodingHelper { + static let encodingErrorParameterKey = "{{projectName}}.RequestBuilderError" + {{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}open{{/nonPublicApi}} class func encodingParameters(forEncodableObject encodableObj: T?, codableHelper: CodableHelper) -> [String: any Sendable]? { var params: [String: any Sendable]? @@ -19,7 +21,7 @@ import Foundation let data = try encodeResult.get() params = JSONDataEncoding.encodingParameters(jsonData: data) } catch { - print(error.localizedDescription) + params = [encodingErrorParameterKey: RequestBuilderError.bodyEncodingFailed(error)] } } diff --git a/modules/openapi-generator/src/main/resources/swift6/Models.mustache b/modules/openapi-generator/src/main/resources/swift6/Models.mustache index a5135bd8f26c..055c5cb38729 100644 --- a/modules/openapi-generator/src/main/resources/swift6/Models.mustache +++ b/modules/openapi-generator/src/main/resources/swift6/Models.mustache @@ -95,6 +95,14 @@ where RawValue: Decodable, AllCases: BidirectionalCollection {} case requestMissingURL } +{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} enum RequestBuilderError: Error, Sendable { + case bodyEncodingFailed(any Error) + case unsupportedHTTPMethod(String) + case unsupportedMediaType(String) + case unsupportedParameterValue(key: String) + case unsupportedResponseType(String) +} + {{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} enum DecodableRequestBuilderError: Error, Sendable { case emptyDataResponse case nilHTTPResponse diff --git a/modules/openapi-generator/src/main/resources/swift6/libraries/alamofire/AlamofireImplementations.mustache b/modules/openapi-generator/src/main/resources/swift6/libraries/alamofire/AlamofireImplementations.mustache index a5c62c80203d..9633f87ad7fc 100644 --- a/modules/openapi-generator/src/main/resources/swift6/libraries/alamofire/AlamofireImplementations.mustache +++ b/modules/openapi-generator/src/main/resources/swift6/libraries/alamofire/AlamofireImplementations.mustache @@ -59,7 +59,7 @@ fileprivate class AlamofireRequestBuilderConfiguration: @unchecked Sendable { encoding = JSONDataEncoding() default: - fatalError("Unsupported HTTPMethod - \(xMethod.rawValue)") + return nil } guard let originalRequest = try? URLRequest(url: URLString, method: xMethod, headers: HTTPHeaders(buildHeaders())) else { return nil } @@ -92,6 +92,10 @@ fileprivate class AlamofireRequestBuilderConfiguration: @unchecked Sendable { let manager = createAlamofireSession() AlamofireRequestBuilderConfiguration.shared.managerStore[managerId] = manager + if let bodyEncodingError = parameters?[JSONEncodingHelper.encodingErrorParameterKey] as? RequestBuilderError { + return failBeforeSending(bodyEncodingError, managerId: managerId, completion: completion) + } + let xMethod = Alamofire.HTTPMethod(rawValue: method) let encoding: ParameterEncoding? @@ -108,8 +112,12 @@ fileprivate class AlamofireRequestBuilderConfiguration: @unchecked Sendable { } else if contentType.hasPrefix("multipart/form-data") { encoding = nil + if let key = Self.firstUnsupportedMultipartKey(in: self.parameters) { + return failBeforeSending(.unsupportedParameterValue(key: key), managerId: managerId, completion: completion) + } + let upload = manager.upload(multipartFormData: { mpForm in - for (k, v) in self.parameters! { + for (k, v) in self.parameters ?? [:] { for v in (v as? Array ?? [v]) { switch v { case let fileURL as URL: @@ -127,7 +135,7 @@ fileprivate class AlamofireRequestBuilderConfiguration: @unchecked Sendable { case let uuid as UUID: mpForm.append(uuid.uuidString.data(using: String.Encoding.utf8)!, withName: k) default: - fatalError("Unprocessable value \(v) with key \(k)") + break } } } @@ -144,11 +152,11 @@ fileprivate class AlamofireRequestBuilderConfiguration: @unchecked Sendable { } else if contentType.hasPrefix("application/x-www-form-urlencoded") { encoding = URLEncoding(destination: .httpBody) } else { - fatalError("Unsupported Media Type - \(contentType)") + return failBeforeSending(.unsupportedMediaType(contentType), managerId: managerId, completion: completion) } default: - fatalError("Unsupported HTTPMethod - \(xMethod.rawValue)") + return failBeforeSending(.unsupportedHTTPMethod(xMethod.rawValue), managerId: managerId, completion: completion) } if let encoding = encoding { @@ -183,15 +191,46 @@ fileprivate class AlamofireRequestBuilderConfiguration: @unchecked Sendable { switch voidResponse.result { case .success: - completion(.success(Response(response: voidResponse.response!, body: () as! T, bodyData: voidResponse.data))) + if let httpResponse = voidResponse.response { + completion(.success(Response(response: httpResponse, body: () as! T, bodyData: voidResponse.data))) + } else { + completion(.failure(ErrorResponse.error(-2, voidResponse.data, nil, DecodableRequestBuilderError.nilHTTPResponse))) + } case let .failure(error): completion(.failure(ErrorResponse.error(voidResponse.response?.statusCode ?? 500, voidResponse.data, voidResponse.response, error))) } }) default: - fatalError("Unsupported Response Body Type - \(String(describing: T.self))") + request.cancel() + cleanupRequest() + let error = RequestBuilderError.unsupportedResponseType(String(describing: T.self)) + apiConfiguration.apiResponseQueue.async { + completion(.failure(ErrorResponse.error(415, nil, nil, error))) + } + } + } + + fileprivate func failBeforeSending(_ error: RequestBuilderError, managerId: String, completion: @Sendable @escaping (_ result: Swift.Result, ErrorResponse>) -> Void) -> RequestTask { + AlamofireRequestBuilderConfiguration.shared.managerStore[managerId] = nil + apiConfiguration.apiResponseQueue.async { + completion(.failure(ErrorResponse.error(415, nil, nil, error))) + } + return requestTask + } + + fileprivate static func firstUnsupportedMultipartKey(in parameters: [String: any Sendable]?) -> String? { + for (key, value) in parameters ?? [:] { + for element in (value as? [Any] ?? [value]) { + switch element { + case is URL, is String, is NSNumber, is Data, is UUID: + continue + default: + return key + } + } } + return nil } {{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}open{{/nonPublicApi}} func buildHeaders() -> [String: String] { @@ -277,7 +316,11 @@ fileprivate class AlamofireRequestBuilderConfiguration: @unchecked Sendable { switch stringResponse.result { case let .success(value): - completion(.success(Response(response: stringResponse.response!, body: value as! T, bodyData: stringResponse.data))) + if let httpResponse = stringResponse.response { + completion(.success(Response(response: httpResponse, body: value as! T, bodyData: stringResponse.data))) + } else { + completion(.failure(ErrorResponse.error(-2, stringResponse.data, nil, DecodableRequestBuilderError.nilHTTPResponse))) + } case let .failure(error): completion(.failure(ErrorResponse.error(stringResponse.response?.statusCode ?? 500, stringResponse.data, stringResponse.response, error))) } @@ -322,7 +365,11 @@ fileprivate class AlamofireRequestBuilderConfiguration: @unchecked Sendable { try fileManager.createDirectory(atPath: directoryPath, withIntermediateDirectories: true, attributes: nil) try data.write(to: filePath, options: .atomic) - completion(.success(Response(response: dataResponse.response!, body: filePath as! T, bodyData: data))) + if let httpResponse = dataResponse.response { + completion(.success(Response(response: httpResponse, body: filePath as! T, bodyData: data))) + } else { + completion(.failure(ErrorResponse.error(-2, dataResponse.data, nil, DecodableRequestBuilderError.nilHTTPResponse))) + } } catch let requestParserError as DownloadException { completion(.failure(ErrorResponse.error(400, dataResponse.data, dataResponse.response, requestParserError))) @@ -339,7 +386,11 @@ fileprivate class AlamofireRequestBuilderConfiguration: @unchecked Sendable { switch voidResponse.result { case .success: - completion(.success(Response(response: voidResponse.response!, body: () as! T, bodyData: voidResponse.data))) + if let httpResponse = voidResponse.response { + completion(.success(Response(response: httpResponse, body: () as! T, bodyData: voidResponse.data))) + } else { + completion(.failure(ErrorResponse.error(-2, voidResponse.data, nil, DecodableRequestBuilderError.nilHTTPResponse))) + } case let .failure(error): completion(.failure(ErrorResponse.error(voidResponse.response?.statusCode ?? 500, voidResponse.data, voidResponse.response, error))) } @@ -353,7 +404,11 @@ fileprivate class AlamofireRequestBuilderConfiguration: @unchecked Sendable { switch dataResponse.result { case .success: - completion(.success(Response(response: dataResponse.response!, body: dataResponse.data as! T, bodyData: dataResponse.data))) + if let httpResponse = dataResponse.response { + completion(.success(Response(response: httpResponse, body: (dataResponse.data ?? Data()) as! T, bodyData: dataResponse.data))) + } else { + completion(.failure(ErrorResponse.error(-2, dataResponse.data, nil, DecodableRequestBuilderError.nilHTTPResponse))) + } case let .failure(error): completion(.failure(ErrorResponse.error(dataResponse.response?.statusCode ?? 500, dataResponse.data, dataResponse.response, error))) } diff --git a/modules/openapi-generator/src/main/resources/swift6/libraries/urlsession/URLSessionImplementations.mustache b/modules/openapi-generator/src/main/resources/swift6/libraries/urlsession/URLSessionImplementations.mustache index 5e82aebd7949..e2f9439ec920 100644 --- a/modules/openapi-generator/src/main/resources/swift6/libraries/urlsession/URLSessionImplementations.mustache +++ b/modules/openapi-generator/src/main/resources/swift6/libraries/urlsession/URLSessionImplementations.mustache @@ -125,7 +125,7 @@ fileprivate class URLSessionRequestBuilderConfiguration: @unchecked Sendable { let urlSession = createURLSession() guard let xMethod = HTTPMethod(rawValue: method) else { - fatalError("Unsupported Http method - \(method)") + return failBeforeSending(RequestBuilderError.unsupportedHTTPMethod(method), urlSession: urlSession, completion: completion) } let encoding: ParameterEncoding @@ -146,11 +146,15 @@ fileprivate class URLSessionRequestBuilderConfiguration: @unchecked Sendable { } else if contentType.hasPrefix("application/octet-stream") || contentType.hasPrefix("image/") { encoding = OctetStreamEncoding() } else { - fatalError("Unsupported Media Type - \(contentType)") + return failBeforeSending(RequestBuilderError.unsupportedMediaType(contentType), urlSession: urlSession, completion: completion) } } do { + if let bodyEncodingError = parameters?[JSONEncodingHelper.encodingErrorParameterKey] as? RequestBuilderError { + throw bodyEncodingError + } + let request = try createURLRequest(urlSession: urlSession, method: xMethod, encoding: encoding, headers: headers) apiConfiguration.interceptor.intercept(urlRequest: request, urlSession: urlSession, requestBuilder: self) { result in @@ -222,16 +226,22 @@ fileprivate class URLSessionRequestBuilderConfiguration: @unchecked Sendable { } } } catch { - // Request creation failed - create a minimal request for error reporting - let failedURL = URL(string: URLString) ?? URL(string: "about:blank")! - var failedRequest = URLRequest(url: failedURL) - failedRequest.httpMethod = method + return failBeforeSending(error, urlSession: urlSession, completion: completion) + } + + return requestTask + } - self.apiConfiguration.interceptor.didComplete(urlRequest: failedRequest, urlSession: urlSession, requestBuilder: self, data: nil, response: nil, result: .failure(error)) + private func failBeforeSending(_ error: Error, urlSession: URLSessionProtocol, completion: @Sendable @escaping (_ result: Swift.Result, ErrorResponse>) -> Void) -> RequestTask { + // Request creation failed - create a minimal request for error reporting + let failedURL = URL(string: URLString) ?? URL(string: "about:blank")! + var failedRequest = URLRequest(url: failedURL) + failedRequest.httpMethod = method - self.apiConfiguration.apiResponseQueue.async { - completion(.failure(ErrorResponse.error(415, nil, nil, error))) - } + self.apiConfiguration.interceptor.didComplete(urlRequest: failedRequest, urlSession: urlSession, requestBuilder: self, data: nil, response: nil, result: .failure(error)) + + self.apiConfiguration.apiResponseQueue.async { + completion(.failure(ErrorResponse.error(415, nil, nil, error))) } return requestTask @@ -267,7 +277,9 @@ fileprivate class URLSessionRequestBuilderConfiguration: @unchecked Sendable { completion(.success(Response(response: httpResponse, body: result, bodyData: data))) default: - fatalError("Unsupported Response Body Type - \(String(describing: T.self))") + let error = RequestBuilderError.unsupportedResponseType(String(describing: T.self)) + apiConfiguration.interceptor.didComplete(urlRequest: urlRequest, urlSession: urlSession, requestBuilder: self, data: data, response: httpResponse, result: .failure(error)) + completion(.failure(ErrorResponse.error(httpResponse.statusCode, data, httpResponse, error))) } } @@ -554,7 +566,7 @@ private class FormDataEncoding: ParameterEncoding { } default: - fatalError("Unprocessable value \(value) with key \(key)") + throw RequestBuilderError.unsupportedParameterValue(key: key) } } } @@ -701,7 +713,7 @@ private class OctetStreamEncoding: ParameterEncoding { case let data as Data: urlRequest.httpBody = data default: - fatalError("Unprocessable body \(body)") + throw RequestBuilderError.unsupportedParameterValue(key: "body") } return urlRequest diff --git a/samples/client/petstore/swift6/alamofireLibrary/Sources/PetstoreClient/Infrastructure/AlamofireImplementations.swift b/samples/client/petstore/swift6/alamofireLibrary/Sources/PetstoreClient/Infrastructure/AlamofireImplementations.swift index 331acf68cb07..bf1456bc4621 100644 --- a/samples/client/petstore/swift6/alamofireLibrary/Sources/PetstoreClient/Infrastructure/AlamofireImplementations.swift +++ b/samples/client/petstore/swift6/alamofireLibrary/Sources/PetstoreClient/Infrastructure/AlamofireImplementations.swift @@ -59,7 +59,7 @@ open class AlamofireRequestBuilder: RequestBuilder, @unchecked S encoding = JSONDataEncoding() default: - fatalError("Unsupported HTTPMethod - \(xMethod.rawValue)") + return nil } guard let originalRequest = try? URLRequest(url: URLString, method: xMethod, headers: HTTPHeaders(buildHeaders())) else { return nil } @@ -92,6 +92,10 @@ open class AlamofireRequestBuilder: RequestBuilder, @unchecked S let manager = createAlamofireSession() AlamofireRequestBuilderConfiguration.shared.managerStore[managerId] = manager + if let bodyEncodingError = parameters?[JSONEncodingHelper.encodingErrorParameterKey] as? RequestBuilderError { + return failBeforeSending(bodyEncodingError, managerId: managerId, completion: completion) + } + let xMethod = Alamofire.HTTPMethod(rawValue: method) let encoding: ParameterEncoding? @@ -108,8 +112,12 @@ open class AlamofireRequestBuilder: RequestBuilder, @unchecked S } else if contentType.hasPrefix("multipart/form-data") { encoding = nil + if let key = Self.firstUnsupportedMultipartKey(in: self.parameters) { + return failBeforeSending(.unsupportedParameterValue(key: key), managerId: managerId, completion: completion) + } + let upload = manager.upload(multipartFormData: { mpForm in - for (k, v) in self.parameters! { + for (k, v) in self.parameters ?? [:] { for v in (v as? Array ?? [v]) { switch v { case let fileURL as URL: @@ -127,7 +135,7 @@ open class AlamofireRequestBuilder: RequestBuilder, @unchecked S case let uuid as UUID: mpForm.append(uuid.uuidString.data(using: String.Encoding.utf8)!, withName: k) default: - fatalError("Unprocessable value \(v) with key \(k)") + break } } } @@ -144,11 +152,11 @@ open class AlamofireRequestBuilder: RequestBuilder, @unchecked S } else if contentType.hasPrefix("application/x-www-form-urlencoded") { encoding = URLEncoding(destination: .httpBody) } else { - fatalError("Unsupported Media Type - \(contentType)") + return failBeforeSending(.unsupportedMediaType(contentType), managerId: managerId, completion: completion) } default: - fatalError("Unsupported HTTPMethod - \(xMethod.rawValue)") + return failBeforeSending(.unsupportedHTTPMethod(xMethod.rawValue), managerId: managerId, completion: completion) } if let encoding = encoding { @@ -183,15 +191,46 @@ open class AlamofireRequestBuilder: RequestBuilder, @unchecked S switch voidResponse.result { case .success: - completion(.success(Response(response: voidResponse.response!, body: () as! T, bodyData: voidResponse.data))) + if let httpResponse = voidResponse.response { + completion(.success(Response(response: httpResponse, body: () as! T, bodyData: voidResponse.data))) + } else { + completion(.failure(ErrorResponse.error(-2, voidResponse.data, nil, DecodableRequestBuilderError.nilHTTPResponse))) + } case let .failure(error): completion(.failure(ErrorResponse.error(voidResponse.response?.statusCode ?? 500, voidResponse.data, voidResponse.response, error))) } }) default: - fatalError("Unsupported Response Body Type - \(String(describing: T.self))") + request.cancel() + cleanupRequest() + let error = RequestBuilderError.unsupportedResponseType(String(describing: T.self)) + apiConfiguration.apiResponseQueue.async { + completion(.failure(ErrorResponse.error(415, nil, nil, error))) + } + } + } + + fileprivate func failBeforeSending(_ error: RequestBuilderError, managerId: String, completion: @Sendable @escaping (_ result: Swift.Result, ErrorResponse>) -> Void) -> RequestTask { + AlamofireRequestBuilderConfiguration.shared.managerStore[managerId] = nil + apiConfiguration.apiResponseQueue.async { + completion(.failure(ErrorResponse.error(415, nil, nil, error))) + } + return requestTask + } + + fileprivate static func firstUnsupportedMultipartKey(in parameters: [String: any Sendable]?) -> String? { + for (key, value) in parameters ?? [:] { + for element in (value as? [Any] ?? [value]) { + switch element { + case is URL, is String, is NSNumber, is Data, is UUID: + continue + default: + return key + } + } } + return nil } open func buildHeaders() -> [String: String] { @@ -277,7 +316,11 @@ open class AlamofireDecodableRequestBuilder: AlamofireR switch stringResponse.result { case let .success(value): - completion(.success(Response(response: stringResponse.response!, body: value as! T, bodyData: stringResponse.data))) + if let httpResponse = stringResponse.response { + completion(.success(Response(response: httpResponse, body: value as! T, bodyData: stringResponse.data))) + } else { + completion(.failure(ErrorResponse.error(-2, stringResponse.data, nil, DecodableRequestBuilderError.nilHTTPResponse))) + } case let .failure(error): completion(.failure(ErrorResponse.error(stringResponse.response?.statusCode ?? 500, stringResponse.data, stringResponse.response, error))) } @@ -322,7 +365,11 @@ open class AlamofireDecodableRequestBuilder: AlamofireR try fileManager.createDirectory(atPath: directoryPath, withIntermediateDirectories: true, attributes: nil) try data.write(to: filePath, options: .atomic) - completion(.success(Response(response: dataResponse.response!, body: filePath as! T, bodyData: data))) + if let httpResponse = dataResponse.response { + completion(.success(Response(response: httpResponse, body: filePath as! T, bodyData: data))) + } else { + completion(.failure(ErrorResponse.error(-2, dataResponse.data, nil, DecodableRequestBuilderError.nilHTTPResponse))) + } } catch let requestParserError as DownloadException { completion(.failure(ErrorResponse.error(400, dataResponse.data, dataResponse.response, requestParserError))) @@ -339,7 +386,11 @@ open class AlamofireDecodableRequestBuilder: AlamofireR switch voidResponse.result { case .success: - completion(.success(Response(response: voidResponse.response!, body: () as! T, bodyData: voidResponse.data))) + if let httpResponse = voidResponse.response { + completion(.success(Response(response: httpResponse, body: () as! T, bodyData: voidResponse.data))) + } else { + completion(.failure(ErrorResponse.error(-2, voidResponse.data, nil, DecodableRequestBuilderError.nilHTTPResponse))) + } case let .failure(error): completion(.failure(ErrorResponse.error(voidResponse.response?.statusCode ?? 500, voidResponse.data, voidResponse.response, error))) } @@ -353,7 +404,11 @@ open class AlamofireDecodableRequestBuilder: AlamofireR switch dataResponse.result { case .success: - completion(.success(Response(response: dataResponse.response!, body: dataResponse.data as! T, bodyData: dataResponse.data))) + if let httpResponse = dataResponse.response { + completion(.success(Response(response: httpResponse, body: (dataResponse.data ?? Data()) as! T, bodyData: dataResponse.data))) + } else { + completion(.failure(ErrorResponse.error(-2, dataResponse.data, nil, DecodableRequestBuilderError.nilHTTPResponse))) + } case let .failure(error): completion(.failure(ErrorResponse.error(dataResponse.response?.statusCode ?? 500, dataResponse.data, dataResponse.response, error))) } diff --git a/samples/client/petstore/swift6/alamofireLibrary/Sources/PetstoreClient/Infrastructure/JSONEncodingHelper.swift b/samples/client/petstore/swift6/alamofireLibrary/Sources/PetstoreClient/Infrastructure/JSONEncodingHelper.swift index 71c8b4e84faf..9d4d8cb2ae4a 100644 --- a/samples/client/petstore/swift6/alamofireLibrary/Sources/PetstoreClient/Infrastructure/JSONEncodingHelper.swift +++ b/samples/client/petstore/swift6/alamofireLibrary/Sources/PetstoreClient/Infrastructure/JSONEncodingHelper.swift @@ -9,6 +9,8 @@ import Foundation open class JSONEncodingHelper { + static let encodingErrorParameterKey = "PetstoreClient.RequestBuilderError" + open class func encodingParameters(forEncodableObject encodableObj: T?, codableHelper: CodableHelper) -> [String: any Sendable]? { var params: [String: any Sendable]? @@ -19,7 +21,7 @@ open class JSONEncodingHelper { let data = try encodeResult.get() params = JSONDataEncoding.encodingParameters(jsonData: data) } catch { - print(error.localizedDescription) + params = [encodingErrorParameterKey: RequestBuilderError.bodyEncodingFailed(error)] } } diff --git a/samples/client/petstore/swift6/alamofireLibrary/Sources/PetstoreClient/Infrastructure/Models.swift b/samples/client/petstore/swift6/alamofireLibrary/Sources/PetstoreClient/Infrastructure/Models.swift index ef2c6e25cf9e..7e84be850fc6 100644 --- a/samples/client/petstore/swift6/alamofireLibrary/Sources/PetstoreClient/Infrastructure/Models.swift +++ b/samples/client/petstore/swift6/alamofireLibrary/Sources/PetstoreClient/Infrastructure/Models.swift @@ -82,6 +82,14 @@ public enum DownloadException: Error, Sendable { case requestMissingURL } +public enum RequestBuilderError: Error, Sendable { + case bodyEncodingFailed(any Error) + case unsupportedHTTPMethod(String) + case unsupportedMediaType(String) + case unsupportedParameterValue(key: String) + case unsupportedResponseType(String) +} + public enum DecodableRequestBuilderError: Error, Sendable { case emptyDataResponse case nilHTTPResponse diff --git a/samples/client/petstore/swift6/apiNonStaticMethod/Sources/PetstoreClient/Infrastructure/AlamofireImplementations.swift b/samples/client/petstore/swift6/apiNonStaticMethod/Sources/PetstoreClient/Infrastructure/AlamofireImplementations.swift index 331acf68cb07..bf1456bc4621 100644 --- a/samples/client/petstore/swift6/apiNonStaticMethod/Sources/PetstoreClient/Infrastructure/AlamofireImplementations.swift +++ b/samples/client/petstore/swift6/apiNonStaticMethod/Sources/PetstoreClient/Infrastructure/AlamofireImplementations.swift @@ -59,7 +59,7 @@ open class AlamofireRequestBuilder: RequestBuilder, @unchecked S encoding = JSONDataEncoding() default: - fatalError("Unsupported HTTPMethod - \(xMethod.rawValue)") + return nil } guard let originalRequest = try? URLRequest(url: URLString, method: xMethod, headers: HTTPHeaders(buildHeaders())) else { return nil } @@ -92,6 +92,10 @@ open class AlamofireRequestBuilder: RequestBuilder, @unchecked S let manager = createAlamofireSession() AlamofireRequestBuilderConfiguration.shared.managerStore[managerId] = manager + if let bodyEncodingError = parameters?[JSONEncodingHelper.encodingErrorParameterKey] as? RequestBuilderError { + return failBeforeSending(bodyEncodingError, managerId: managerId, completion: completion) + } + let xMethod = Alamofire.HTTPMethod(rawValue: method) let encoding: ParameterEncoding? @@ -108,8 +112,12 @@ open class AlamofireRequestBuilder: RequestBuilder, @unchecked S } else if contentType.hasPrefix("multipart/form-data") { encoding = nil + if let key = Self.firstUnsupportedMultipartKey(in: self.parameters) { + return failBeforeSending(.unsupportedParameterValue(key: key), managerId: managerId, completion: completion) + } + let upload = manager.upload(multipartFormData: { mpForm in - for (k, v) in self.parameters! { + for (k, v) in self.parameters ?? [:] { for v in (v as? Array ?? [v]) { switch v { case let fileURL as URL: @@ -127,7 +135,7 @@ open class AlamofireRequestBuilder: RequestBuilder, @unchecked S case let uuid as UUID: mpForm.append(uuid.uuidString.data(using: String.Encoding.utf8)!, withName: k) default: - fatalError("Unprocessable value \(v) with key \(k)") + break } } } @@ -144,11 +152,11 @@ open class AlamofireRequestBuilder: RequestBuilder, @unchecked S } else if contentType.hasPrefix("application/x-www-form-urlencoded") { encoding = URLEncoding(destination: .httpBody) } else { - fatalError("Unsupported Media Type - \(contentType)") + return failBeforeSending(.unsupportedMediaType(contentType), managerId: managerId, completion: completion) } default: - fatalError("Unsupported HTTPMethod - \(xMethod.rawValue)") + return failBeforeSending(.unsupportedHTTPMethod(xMethod.rawValue), managerId: managerId, completion: completion) } if let encoding = encoding { @@ -183,15 +191,46 @@ open class AlamofireRequestBuilder: RequestBuilder, @unchecked S switch voidResponse.result { case .success: - completion(.success(Response(response: voidResponse.response!, body: () as! T, bodyData: voidResponse.data))) + if let httpResponse = voidResponse.response { + completion(.success(Response(response: httpResponse, body: () as! T, bodyData: voidResponse.data))) + } else { + completion(.failure(ErrorResponse.error(-2, voidResponse.data, nil, DecodableRequestBuilderError.nilHTTPResponse))) + } case let .failure(error): completion(.failure(ErrorResponse.error(voidResponse.response?.statusCode ?? 500, voidResponse.data, voidResponse.response, error))) } }) default: - fatalError("Unsupported Response Body Type - \(String(describing: T.self))") + request.cancel() + cleanupRequest() + let error = RequestBuilderError.unsupportedResponseType(String(describing: T.self)) + apiConfiguration.apiResponseQueue.async { + completion(.failure(ErrorResponse.error(415, nil, nil, error))) + } + } + } + + fileprivate func failBeforeSending(_ error: RequestBuilderError, managerId: String, completion: @Sendable @escaping (_ result: Swift.Result, ErrorResponse>) -> Void) -> RequestTask { + AlamofireRequestBuilderConfiguration.shared.managerStore[managerId] = nil + apiConfiguration.apiResponseQueue.async { + completion(.failure(ErrorResponse.error(415, nil, nil, error))) + } + return requestTask + } + + fileprivate static func firstUnsupportedMultipartKey(in parameters: [String: any Sendable]?) -> String? { + for (key, value) in parameters ?? [:] { + for element in (value as? [Any] ?? [value]) { + switch element { + case is URL, is String, is NSNumber, is Data, is UUID: + continue + default: + return key + } + } } + return nil } open func buildHeaders() -> [String: String] { @@ -277,7 +316,11 @@ open class AlamofireDecodableRequestBuilder: AlamofireR switch stringResponse.result { case let .success(value): - completion(.success(Response(response: stringResponse.response!, body: value as! T, bodyData: stringResponse.data))) + if let httpResponse = stringResponse.response { + completion(.success(Response(response: httpResponse, body: value as! T, bodyData: stringResponse.data))) + } else { + completion(.failure(ErrorResponse.error(-2, stringResponse.data, nil, DecodableRequestBuilderError.nilHTTPResponse))) + } case let .failure(error): completion(.failure(ErrorResponse.error(stringResponse.response?.statusCode ?? 500, stringResponse.data, stringResponse.response, error))) } @@ -322,7 +365,11 @@ open class AlamofireDecodableRequestBuilder: AlamofireR try fileManager.createDirectory(atPath: directoryPath, withIntermediateDirectories: true, attributes: nil) try data.write(to: filePath, options: .atomic) - completion(.success(Response(response: dataResponse.response!, body: filePath as! T, bodyData: data))) + if let httpResponse = dataResponse.response { + completion(.success(Response(response: httpResponse, body: filePath as! T, bodyData: data))) + } else { + completion(.failure(ErrorResponse.error(-2, dataResponse.data, nil, DecodableRequestBuilderError.nilHTTPResponse))) + } } catch let requestParserError as DownloadException { completion(.failure(ErrorResponse.error(400, dataResponse.data, dataResponse.response, requestParserError))) @@ -339,7 +386,11 @@ open class AlamofireDecodableRequestBuilder: AlamofireR switch voidResponse.result { case .success: - completion(.success(Response(response: voidResponse.response!, body: () as! T, bodyData: voidResponse.data))) + if let httpResponse = voidResponse.response { + completion(.success(Response(response: httpResponse, body: () as! T, bodyData: voidResponse.data))) + } else { + completion(.failure(ErrorResponse.error(-2, voidResponse.data, nil, DecodableRequestBuilderError.nilHTTPResponse))) + } case let .failure(error): completion(.failure(ErrorResponse.error(voidResponse.response?.statusCode ?? 500, voidResponse.data, voidResponse.response, error))) } @@ -353,7 +404,11 @@ open class AlamofireDecodableRequestBuilder: AlamofireR switch dataResponse.result { case .success: - completion(.success(Response(response: dataResponse.response!, body: dataResponse.data as! T, bodyData: dataResponse.data))) + if let httpResponse = dataResponse.response { + completion(.success(Response(response: httpResponse, body: (dataResponse.data ?? Data()) as! T, bodyData: dataResponse.data))) + } else { + completion(.failure(ErrorResponse.error(-2, dataResponse.data, nil, DecodableRequestBuilderError.nilHTTPResponse))) + } case let .failure(error): completion(.failure(ErrorResponse.error(dataResponse.response?.statusCode ?? 500, dataResponse.data, dataResponse.response, error))) } diff --git a/samples/client/petstore/swift6/apiNonStaticMethod/Sources/PetstoreClient/Infrastructure/JSONEncodingHelper.swift b/samples/client/petstore/swift6/apiNonStaticMethod/Sources/PetstoreClient/Infrastructure/JSONEncodingHelper.swift index 71c8b4e84faf..9d4d8cb2ae4a 100644 --- a/samples/client/petstore/swift6/apiNonStaticMethod/Sources/PetstoreClient/Infrastructure/JSONEncodingHelper.swift +++ b/samples/client/petstore/swift6/apiNonStaticMethod/Sources/PetstoreClient/Infrastructure/JSONEncodingHelper.swift @@ -9,6 +9,8 @@ import Foundation open class JSONEncodingHelper { + static let encodingErrorParameterKey = "PetstoreClient.RequestBuilderError" + open class func encodingParameters(forEncodableObject encodableObj: T?, codableHelper: CodableHelper) -> [String: any Sendable]? { var params: [String: any Sendable]? @@ -19,7 +21,7 @@ open class JSONEncodingHelper { let data = try encodeResult.get() params = JSONDataEncoding.encodingParameters(jsonData: data) } catch { - print(error.localizedDescription) + params = [encodingErrorParameterKey: RequestBuilderError.bodyEncodingFailed(error)] } } diff --git a/samples/client/petstore/swift6/apiNonStaticMethod/Sources/PetstoreClient/Infrastructure/Models.swift b/samples/client/petstore/swift6/apiNonStaticMethod/Sources/PetstoreClient/Infrastructure/Models.swift index ef2c6e25cf9e..7e84be850fc6 100644 --- a/samples/client/petstore/swift6/apiNonStaticMethod/Sources/PetstoreClient/Infrastructure/Models.swift +++ b/samples/client/petstore/swift6/apiNonStaticMethod/Sources/PetstoreClient/Infrastructure/Models.swift @@ -82,6 +82,14 @@ public enum DownloadException: Error, Sendable { case requestMissingURL } +public enum RequestBuilderError: Error, Sendable { + case bodyEncodingFailed(any Error) + case unsupportedHTTPMethod(String) + case unsupportedMediaType(String) + case unsupportedParameterValue(key: String) + case unsupportedResponseType(String) +} + public enum DecodableRequestBuilderError: Error, Sendable { case emptyDataResponse case nilHTTPResponse diff --git a/samples/client/petstore/swift6/asyncAwaitLibrary/Sources/PetstoreClient/Infrastructure/JSONEncodingHelper.swift b/samples/client/petstore/swift6/asyncAwaitLibrary/Sources/PetstoreClient/Infrastructure/JSONEncodingHelper.swift index 71c8b4e84faf..9d4d8cb2ae4a 100644 --- a/samples/client/petstore/swift6/asyncAwaitLibrary/Sources/PetstoreClient/Infrastructure/JSONEncodingHelper.swift +++ b/samples/client/petstore/swift6/asyncAwaitLibrary/Sources/PetstoreClient/Infrastructure/JSONEncodingHelper.swift @@ -9,6 +9,8 @@ import Foundation open class JSONEncodingHelper { + static let encodingErrorParameterKey = "PetstoreClient.RequestBuilderError" + open class func encodingParameters(forEncodableObject encodableObj: T?, codableHelper: CodableHelper) -> [String: any Sendable]? { var params: [String: any Sendable]? @@ -19,7 +21,7 @@ open class JSONEncodingHelper { let data = try encodeResult.get() params = JSONDataEncoding.encodingParameters(jsonData: data) } catch { - print(error.localizedDescription) + params = [encodingErrorParameterKey: RequestBuilderError.bodyEncodingFailed(error)] } } diff --git a/samples/client/petstore/swift6/asyncAwaitLibrary/Sources/PetstoreClient/Infrastructure/Models.swift b/samples/client/petstore/swift6/asyncAwaitLibrary/Sources/PetstoreClient/Infrastructure/Models.swift index e98056ea6658..67ce3d455b21 100644 --- a/samples/client/petstore/swift6/asyncAwaitLibrary/Sources/PetstoreClient/Infrastructure/Models.swift +++ b/samples/client/petstore/swift6/asyncAwaitLibrary/Sources/PetstoreClient/Infrastructure/Models.swift @@ -81,6 +81,14 @@ public enum DownloadException: Error, Sendable { case requestMissingURL } +public enum RequestBuilderError: Error, Sendable { + case bodyEncodingFailed(any Error) + case unsupportedHTTPMethod(String) + case unsupportedMediaType(String) + case unsupportedParameterValue(key: String) + case unsupportedResponseType(String) +} + public enum DecodableRequestBuilderError: Error, Sendable { case emptyDataResponse case nilHTTPResponse diff --git a/samples/client/petstore/swift6/asyncAwaitLibrary/Sources/PetstoreClient/Infrastructure/URLSessionImplementations.swift b/samples/client/petstore/swift6/asyncAwaitLibrary/Sources/PetstoreClient/Infrastructure/URLSessionImplementations.swift index 5b993205718c..361032896a64 100644 --- a/samples/client/petstore/swift6/asyncAwaitLibrary/Sources/PetstoreClient/Infrastructure/URLSessionImplementations.swift +++ b/samples/client/petstore/swift6/asyncAwaitLibrary/Sources/PetstoreClient/Infrastructure/URLSessionImplementations.swift @@ -125,7 +125,7 @@ open class URLSessionRequestBuilder: RequestBuilder, @unchecked let urlSession = createURLSession() guard let xMethod = HTTPMethod(rawValue: method) else { - fatalError("Unsupported Http method - \(method)") + return failBeforeSending(RequestBuilderError.unsupportedHTTPMethod(method), urlSession: urlSession, completion: completion) } let encoding: ParameterEncoding @@ -146,11 +146,15 @@ open class URLSessionRequestBuilder: RequestBuilder, @unchecked } else if contentType.hasPrefix("application/octet-stream") || contentType.hasPrefix("image/") { encoding = OctetStreamEncoding() } else { - fatalError("Unsupported Media Type - \(contentType)") + return failBeforeSending(RequestBuilderError.unsupportedMediaType(contentType), urlSession: urlSession, completion: completion) } } do { + if let bodyEncodingError = parameters?[JSONEncodingHelper.encodingErrorParameterKey] as? RequestBuilderError { + throw bodyEncodingError + } + let request = try createURLRequest(urlSession: urlSession, method: xMethod, encoding: encoding, headers: headers) apiConfiguration.interceptor.intercept(urlRequest: request, urlSession: urlSession, requestBuilder: self) { result in @@ -222,16 +226,22 @@ open class URLSessionRequestBuilder: RequestBuilder, @unchecked } } } catch { - // Request creation failed - create a minimal request for error reporting - let failedURL = URL(string: URLString) ?? URL(string: "about:blank")! - var failedRequest = URLRequest(url: failedURL) - failedRequest.httpMethod = method + return failBeforeSending(error, urlSession: urlSession, completion: completion) + } + + return requestTask + } - self.apiConfiguration.interceptor.didComplete(urlRequest: failedRequest, urlSession: urlSession, requestBuilder: self, data: nil, response: nil, result: .failure(error)) + private func failBeforeSending(_ error: Error, urlSession: URLSessionProtocol, completion: @Sendable @escaping (_ result: Swift.Result, ErrorResponse>) -> Void) -> RequestTask { + // Request creation failed - create a minimal request for error reporting + let failedURL = URL(string: URLString) ?? URL(string: "about:blank")! + var failedRequest = URLRequest(url: failedURL) + failedRequest.httpMethod = method - self.apiConfiguration.apiResponseQueue.async { - completion(.failure(ErrorResponse.error(415, nil, nil, error))) - } + self.apiConfiguration.interceptor.didComplete(urlRequest: failedRequest, urlSession: urlSession, requestBuilder: self, data: nil, response: nil, result: .failure(error)) + + self.apiConfiguration.apiResponseQueue.async { + completion(.failure(ErrorResponse.error(415, nil, nil, error))) } return requestTask @@ -267,7 +277,9 @@ open class URLSessionRequestBuilder: RequestBuilder, @unchecked completion(.success(Response(response: httpResponse, body: result, bodyData: data))) default: - fatalError("Unsupported Response Body Type - \(String(describing: T.self))") + let error = RequestBuilderError.unsupportedResponseType(String(describing: T.self)) + apiConfiguration.interceptor.didComplete(urlRequest: urlRequest, urlSession: urlSession, requestBuilder: self, data: data, response: httpResponse, result: .failure(error)) + completion(.failure(ErrorResponse.error(httpResponse.statusCode, data, httpResponse, error))) } } @@ -554,7 +566,7 @@ private class FormDataEncoding: ParameterEncoding { } default: - fatalError("Unprocessable value \(value) with key \(key)") + throw RequestBuilderError.unsupportedParameterValue(key: key) } } } @@ -701,7 +713,7 @@ private class OctetStreamEncoding: ParameterEncoding { case let data as Data: urlRequest.httpBody = data default: - fatalError("Unprocessable body \(body)") + throw RequestBuilderError.unsupportedParameterValue(key: "body") } return urlRequest diff --git a/samples/client/petstore/swift6/combineDeferredLibrary/PetstoreClient/Classes/OpenAPIs/Infrastructure/JSONEncodingHelper.swift b/samples/client/petstore/swift6/combineDeferredLibrary/PetstoreClient/Classes/OpenAPIs/Infrastructure/JSONEncodingHelper.swift index 71c8b4e84faf..9d4d8cb2ae4a 100644 --- a/samples/client/petstore/swift6/combineDeferredLibrary/PetstoreClient/Classes/OpenAPIs/Infrastructure/JSONEncodingHelper.swift +++ b/samples/client/petstore/swift6/combineDeferredLibrary/PetstoreClient/Classes/OpenAPIs/Infrastructure/JSONEncodingHelper.swift @@ -9,6 +9,8 @@ import Foundation open class JSONEncodingHelper { + static let encodingErrorParameterKey = "PetstoreClient.RequestBuilderError" + open class func encodingParameters(forEncodableObject encodableObj: T?, codableHelper: CodableHelper) -> [String: any Sendable]? { var params: [String: any Sendable]? @@ -19,7 +21,7 @@ open class JSONEncodingHelper { let data = try encodeResult.get() params = JSONDataEncoding.encodingParameters(jsonData: data) } catch { - print(error.localizedDescription) + params = [encodingErrorParameterKey: RequestBuilderError.bodyEncodingFailed(error)] } } diff --git a/samples/client/petstore/swift6/combineDeferredLibrary/PetstoreClient/Classes/OpenAPIs/Infrastructure/Models.swift b/samples/client/petstore/swift6/combineDeferredLibrary/PetstoreClient/Classes/OpenAPIs/Infrastructure/Models.swift index e98056ea6658..67ce3d455b21 100644 --- a/samples/client/petstore/swift6/combineDeferredLibrary/PetstoreClient/Classes/OpenAPIs/Infrastructure/Models.swift +++ b/samples/client/petstore/swift6/combineDeferredLibrary/PetstoreClient/Classes/OpenAPIs/Infrastructure/Models.swift @@ -81,6 +81,14 @@ public enum DownloadException: Error, Sendable { case requestMissingURL } +public enum RequestBuilderError: Error, Sendable { + case bodyEncodingFailed(any Error) + case unsupportedHTTPMethod(String) + case unsupportedMediaType(String) + case unsupportedParameterValue(key: String) + case unsupportedResponseType(String) +} + public enum DecodableRequestBuilderError: Error, Sendable { case emptyDataResponse case nilHTTPResponse diff --git a/samples/client/petstore/swift6/combineDeferredLibrary/PetstoreClient/Classes/OpenAPIs/Infrastructure/URLSessionImplementations.swift b/samples/client/petstore/swift6/combineDeferredLibrary/PetstoreClient/Classes/OpenAPIs/Infrastructure/URLSessionImplementations.swift index 5b993205718c..361032896a64 100644 --- a/samples/client/petstore/swift6/combineDeferredLibrary/PetstoreClient/Classes/OpenAPIs/Infrastructure/URLSessionImplementations.swift +++ b/samples/client/petstore/swift6/combineDeferredLibrary/PetstoreClient/Classes/OpenAPIs/Infrastructure/URLSessionImplementations.swift @@ -125,7 +125,7 @@ open class URLSessionRequestBuilder: RequestBuilder, @unchecked let urlSession = createURLSession() guard let xMethod = HTTPMethod(rawValue: method) else { - fatalError("Unsupported Http method - \(method)") + return failBeforeSending(RequestBuilderError.unsupportedHTTPMethod(method), urlSession: urlSession, completion: completion) } let encoding: ParameterEncoding @@ -146,11 +146,15 @@ open class URLSessionRequestBuilder: RequestBuilder, @unchecked } else if contentType.hasPrefix("application/octet-stream") || contentType.hasPrefix("image/") { encoding = OctetStreamEncoding() } else { - fatalError("Unsupported Media Type - \(contentType)") + return failBeforeSending(RequestBuilderError.unsupportedMediaType(contentType), urlSession: urlSession, completion: completion) } } do { + if let bodyEncodingError = parameters?[JSONEncodingHelper.encodingErrorParameterKey] as? RequestBuilderError { + throw bodyEncodingError + } + let request = try createURLRequest(urlSession: urlSession, method: xMethod, encoding: encoding, headers: headers) apiConfiguration.interceptor.intercept(urlRequest: request, urlSession: urlSession, requestBuilder: self) { result in @@ -222,16 +226,22 @@ open class URLSessionRequestBuilder: RequestBuilder, @unchecked } } } catch { - // Request creation failed - create a minimal request for error reporting - let failedURL = URL(string: URLString) ?? URL(string: "about:blank")! - var failedRequest = URLRequest(url: failedURL) - failedRequest.httpMethod = method + return failBeforeSending(error, urlSession: urlSession, completion: completion) + } + + return requestTask + } - self.apiConfiguration.interceptor.didComplete(urlRequest: failedRequest, urlSession: urlSession, requestBuilder: self, data: nil, response: nil, result: .failure(error)) + private func failBeforeSending(_ error: Error, urlSession: URLSessionProtocol, completion: @Sendable @escaping (_ result: Swift.Result, ErrorResponse>) -> Void) -> RequestTask { + // Request creation failed - create a minimal request for error reporting + let failedURL = URL(string: URLString) ?? URL(string: "about:blank")! + var failedRequest = URLRequest(url: failedURL) + failedRequest.httpMethod = method - self.apiConfiguration.apiResponseQueue.async { - completion(.failure(ErrorResponse.error(415, nil, nil, error))) - } + self.apiConfiguration.interceptor.didComplete(urlRequest: failedRequest, urlSession: urlSession, requestBuilder: self, data: nil, response: nil, result: .failure(error)) + + self.apiConfiguration.apiResponseQueue.async { + completion(.failure(ErrorResponse.error(415, nil, nil, error))) } return requestTask @@ -267,7 +277,9 @@ open class URLSessionRequestBuilder: RequestBuilder, @unchecked completion(.success(Response(response: httpResponse, body: result, bodyData: data))) default: - fatalError("Unsupported Response Body Type - \(String(describing: T.self))") + let error = RequestBuilderError.unsupportedResponseType(String(describing: T.self)) + apiConfiguration.interceptor.didComplete(urlRequest: urlRequest, urlSession: urlSession, requestBuilder: self, data: data, response: httpResponse, result: .failure(error)) + completion(.failure(ErrorResponse.error(httpResponse.statusCode, data, httpResponse, error))) } } @@ -554,7 +566,7 @@ private class FormDataEncoding: ParameterEncoding { } default: - fatalError("Unprocessable value \(value) with key \(key)") + throw RequestBuilderError.unsupportedParameterValue(key: key) } } } @@ -701,7 +713,7 @@ private class OctetStreamEncoding: ParameterEncoding { case let data as Data: urlRequest.httpBody = data default: - fatalError("Unprocessable body \(body)") + throw RequestBuilderError.unsupportedParameterValue(key: "body") } return urlRequest diff --git a/samples/client/petstore/swift6/combineLibrary/Sources/CombineLibrary/Infrastructure/JSONEncodingHelper.swift b/samples/client/petstore/swift6/combineLibrary/Sources/CombineLibrary/Infrastructure/JSONEncodingHelper.swift index 71c8b4e84faf..9d4d8cb2ae4a 100644 --- a/samples/client/petstore/swift6/combineLibrary/Sources/CombineLibrary/Infrastructure/JSONEncodingHelper.swift +++ b/samples/client/petstore/swift6/combineLibrary/Sources/CombineLibrary/Infrastructure/JSONEncodingHelper.swift @@ -9,6 +9,8 @@ import Foundation open class JSONEncodingHelper { + static let encodingErrorParameterKey = "PetstoreClient.RequestBuilderError" + open class func encodingParameters(forEncodableObject encodableObj: T?, codableHelper: CodableHelper) -> [String: any Sendable]? { var params: [String: any Sendable]? @@ -19,7 +21,7 @@ open class JSONEncodingHelper { let data = try encodeResult.get() params = JSONDataEncoding.encodingParameters(jsonData: data) } catch { - print(error.localizedDescription) + params = [encodingErrorParameterKey: RequestBuilderError.bodyEncodingFailed(error)] } } diff --git a/samples/client/petstore/swift6/combineLibrary/Sources/CombineLibrary/Infrastructure/Models.swift b/samples/client/petstore/swift6/combineLibrary/Sources/CombineLibrary/Infrastructure/Models.swift index e98056ea6658..67ce3d455b21 100644 --- a/samples/client/petstore/swift6/combineLibrary/Sources/CombineLibrary/Infrastructure/Models.swift +++ b/samples/client/petstore/swift6/combineLibrary/Sources/CombineLibrary/Infrastructure/Models.swift @@ -81,6 +81,14 @@ public enum DownloadException: Error, Sendable { case requestMissingURL } +public enum RequestBuilderError: Error, Sendable { + case bodyEncodingFailed(any Error) + case unsupportedHTTPMethod(String) + case unsupportedMediaType(String) + case unsupportedParameterValue(key: String) + case unsupportedResponseType(String) +} + public enum DecodableRequestBuilderError: Error, Sendable { case emptyDataResponse case nilHTTPResponse diff --git a/samples/client/petstore/swift6/combineLibrary/Sources/CombineLibrary/Infrastructure/URLSessionImplementations.swift b/samples/client/petstore/swift6/combineLibrary/Sources/CombineLibrary/Infrastructure/URLSessionImplementations.swift index 5b993205718c..361032896a64 100644 --- a/samples/client/petstore/swift6/combineLibrary/Sources/CombineLibrary/Infrastructure/URLSessionImplementations.swift +++ b/samples/client/petstore/swift6/combineLibrary/Sources/CombineLibrary/Infrastructure/URLSessionImplementations.swift @@ -125,7 +125,7 @@ open class URLSessionRequestBuilder: RequestBuilder, @unchecked let urlSession = createURLSession() guard let xMethod = HTTPMethod(rawValue: method) else { - fatalError("Unsupported Http method - \(method)") + return failBeforeSending(RequestBuilderError.unsupportedHTTPMethod(method), urlSession: urlSession, completion: completion) } let encoding: ParameterEncoding @@ -146,11 +146,15 @@ open class URLSessionRequestBuilder: RequestBuilder, @unchecked } else if contentType.hasPrefix("application/octet-stream") || contentType.hasPrefix("image/") { encoding = OctetStreamEncoding() } else { - fatalError("Unsupported Media Type - \(contentType)") + return failBeforeSending(RequestBuilderError.unsupportedMediaType(contentType), urlSession: urlSession, completion: completion) } } do { + if let bodyEncodingError = parameters?[JSONEncodingHelper.encodingErrorParameterKey] as? RequestBuilderError { + throw bodyEncodingError + } + let request = try createURLRequest(urlSession: urlSession, method: xMethod, encoding: encoding, headers: headers) apiConfiguration.interceptor.intercept(urlRequest: request, urlSession: urlSession, requestBuilder: self) { result in @@ -222,16 +226,22 @@ open class URLSessionRequestBuilder: RequestBuilder, @unchecked } } } catch { - // Request creation failed - create a minimal request for error reporting - let failedURL = URL(string: URLString) ?? URL(string: "about:blank")! - var failedRequest = URLRequest(url: failedURL) - failedRequest.httpMethod = method + return failBeforeSending(error, urlSession: urlSession, completion: completion) + } + + return requestTask + } - self.apiConfiguration.interceptor.didComplete(urlRequest: failedRequest, urlSession: urlSession, requestBuilder: self, data: nil, response: nil, result: .failure(error)) + private func failBeforeSending(_ error: Error, urlSession: URLSessionProtocol, completion: @Sendable @escaping (_ result: Swift.Result, ErrorResponse>) -> Void) -> RequestTask { + // Request creation failed - create a minimal request for error reporting + let failedURL = URL(string: URLString) ?? URL(string: "about:blank")! + var failedRequest = URLRequest(url: failedURL) + failedRequest.httpMethod = method - self.apiConfiguration.apiResponseQueue.async { - completion(.failure(ErrorResponse.error(415, nil, nil, error))) - } + self.apiConfiguration.interceptor.didComplete(urlRequest: failedRequest, urlSession: urlSession, requestBuilder: self, data: nil, response: nil, result: .failure(error)) + + self.apiConfiguration.apiResponseQueue.async { + completion(.failure(ErrorResponse.error(415, nil, nil, error))) } return requestTask @@ -267,7 +277,9 @@ open class URLSessionRequestBuilder: RequestBuilder, @unchecked completion(.success(Response(response: httpResponse, body: result, bodyData: data))) default: - fatalError("Unsupported Response Body Type - \(String(describing: T.self))") + let error = RequestBuilderError.unsupportedResponseType(String(describing: T.self)) + apiConfiguration.interceptor.didComplete(urlRequest: urlRequest, urlSession: urlSession, requestBuilder: self, data: data, response: httpResponse, result: .failure(error)) + completion(.failure(ErrorResponse.error(httpResponse.statusCode, data, httpResponse, error))) } } @@ -554,7 +566,7 @@ private class FormDataEncoding: ParameterEncoding { } default: - fatalError("Unprocessable value \(value) with key \(key)") + throw RequestBuilderError.unsupportedParameterValue(key: key) } } } @@ -701,7 +713,7 @@ private class OctetStreamEncoding: ParameterEncoding { case let data as Data: urlRequest.httpBody = data default: - fatalError("Unprocessable body \(body)") + throw RequestBuilderError.unsupportedParameterValue(key: "body") } return urlRequest diff --git a/samples/client/petstore/swift6/default/Sources/PetstoreClient/Infrastructure/JSONEncodingHelper.swift b/samples/client/petstore/swift6/default/Sources/PetstoreClient/Infrastructure/JSONEncodingHelper.swift index 71c8b4e84faf..9d4d8cb2ae4a 100644 --- a/samples/client/petstore/swift6/default/Sources/PetstoreClient/Infrastructure/JSONEncodingHelper.swift +++ b/samples/client/petstore/swift6/default/Sources/PetstoreClient/Infrastructure/JSONEncodingHelper.swift @@ -9,6 +9,8 @@ import Foundation open class JSONEncodingHelper { + static let encodingErrorParameterKey = "PetstoreClient.RequestBuilderError" + open class func encodingParameters(forEncodableObject encodableObj: T?, codableHelper: CodableHelper) -> [String: any Sendable]? { var params: [String: any Sendable]? @@ -19,7 +21,7 @@ open class JSONEncodingHelper { let data = try encodeResult.get() params = JSONDataEncoding.encodingParameters(jsonData: data) } catch { - print(error.localizedDescription) + params = [encodingErrorParameterKey: RequestBuilderError.bodyEncodingFailed(error)] } } diff --git a/samples/client/petstore/swift6/default/Sources/PetstoreClient/Infrastructure/Models.swift b/samples/client/petstore/swift6/default/Sources/PetstoreClient/Infrastructure/Models.swift index e98056ea6658..67ce3d455b21 100644 --- a/samples/client/petstore/swift6/default/Sources/PetstoreClient/Infrastructure/Models.swift +++ b/samples/client/petstore/swift6/default/Sources/PetstoreClient/Infrastructure/Models.swift @@ -81,6 +81,14 @@ public enum DownloadException: Error, Sendable { case requestMissingURL } +public enum RequestBuilderError: Error, Sendable { + case bodyEncodingFailed(any Error) + case unsupportedHTTPMethod(String) + case unsupportedMediaType(String) + case unsupportedParameterValue(key: String) + case unsupportedResponseType(String) +} + public enum DecodableRequestBuilderError: Error, Sendable { case emptyDataResponse case nilHTTPResponse diff --git a/samples/client/petstore/swift6/default/Sources/PetstoreClient/Infrastructure/URLSessionImplementations.swift b/samples/client/petstore/swift6/default/Sources/PetstoreClient/Infrastructure/URLSessionImplementations.swift index 5b993205718c..361032896a64 100644 --- a/samples/client/petstore/swift6/default/Sources/PetstoreClient/Infrastructure/URLSessionImplementations.swift +++ b/samples/client/petstore/swift6/default/Sources/PetstoreClient/Infrastructure/URLSessionImplementations.swift @@ -125,7 +125,7 @@ open class URLSessionRequestBuilder: RequestBuilder, @unchecked let urlSession = createURLSession() guard let xMethod = HTTPMethod(rawValue: method) else { - fatalError("Unsupported Http method - \(method)") + return failBeforeSending(RequestBuilderError.unsupportedHTTPMethod(method), urlSession: urlSession, completion: completion) } let encoding: ParameterEncoding @@ -146,11 +146,15 @@ open class URLSessionRequestBuilder: RequestBuilder, @unchecked } else if contentType.hasPrefix("application/octet-stream") || contentType.hasPrefix("image/") { encoding = OctetStreamEncoding() } else { - fatalError("Unsupported Media Type - \(contentType)") + return failBeforeSending(RequestBuilderError.unsupportedMediaType(contentType), urlSession: urlSession, completion: completion) } } do { + if let bodyEncodingError = parameters?[JSONEncodingHelper.encodingErrorParameterKey] as? RequestBuilderError { + throw bodyEncodingError + } + let request = try createURLRequest(urlSession: urlSession, method: xMethod, encoding: encoding, headers: headers) apiConfiguration.interceptor.intercept(urlRequest: request, urlSession: urlSession, requestBuilder: self) { result in @@ -222,16 +226,22 @@ open class URLSessionRequestBuilder: RequestBuilder, @unchecked } } } catch { - // Request creation failed - create a minimal request for error reporting - let failedURL = URL(string: URLString) ?? URL(string: "about:blank")! - var failedRequest = URLRequest(url: failedURL) - failedRequest.httpMethod = method + return failBeforeSending(error, urlSession: urlSession, completion: completion) + } + + return requestTask + } - self.apiConfiguration.interceptor.didComplete(urlRequest: failedRequest, urlSession: urlSession, requestBuilder: self, data: nil, response: nil, result: .failure(error)) + private func failBeforeSending(_ error: Error, urlSession: URLSessionProtocol, completion: @Sendable @escaping (_ result: Swift.Result, ErrorResponse>) -> Void) -> RequestTask { + // Request creation failed - create a minimal request for error reporting + let failedURL = URL(string: URLString) ?? URL(string: "about:blank")! + var failedRequest = URLRequest(url: failedURL) + failedRequest.httpMethod = method - self.apiConfiguration.apiResponseQueue.async { - completion(.failure(ErrorResponse.error(415, nil, nil, error))) - } + self.apiConfiguration.interceptor.didComplete(urlRequest: failedRequest, urlSession: urlSession, requestBuilder: self, data: nil, response: nil, result: .failure(error)) + + self.apiConfiguration.apiResponseQueue.async { + completion(.failure(ErrorResponse.error(415, nil, nil, error))) } return requestTask @@ -267,7 +277,9 @@ open class URLSessionRequestBuilder: RequestBuilder, @unchecked completion(.success(Response(response: httpResponse, body: result, bodyData: data))) default: - fatalError("Unsupported Response Body Type - \(String(describing: T.self))") + let error = RequestBuilderError.unsupportedResponseType(String(describing: T.self)) + apiConfiguration.interceptor.didComplete(urlRequest: urlRequest, urlSession: urlSession, requestBuilder: self, data: data, response: httpResponse, result: .failure(error)) + completion(.failure(ErrorResponse.error(httpResponse.statusCode, data, httpResponse, error))) } } @@ -554,7 +566,7 @@ private class FormDataEncoding: ParameterEncoding { } default: - fatalError("Unprocessable value \(value) with key \(key)") + throw RequestBuilderError.unsupportedParameterValue(key: key) } } } @@ -701,7 +713,7 @@ private class OctetStreamEncoding: ParameterEncoding { case let data as Data: urlRequest.httpBody = data default: - fatalError("Unprocessable body \(body)") + throw RequestBuilderError.unsupportedParameterValue(key: "body") } return urlRequest diff --git a/samples/client/petstore/swift6/objcCompatible/Sources/PetstoreClient/Infrastructure/JSONEncodingHelper.swift b/samples/client/petstore/swift6/objcCompatible/Sources/PetstoreClient/Infrastructure/JSONEncodingHelper.swift index 71c8b4e84faf..9d4d8cb2ae4a 100644 --- a/samples/client/petstore/swift6/objcCompatible/Sources/PetstoreClient/Infrastructure/JSONEncodingHelper.swift +++ b/samples/client/petstore/swift6/objcCompatible/Sources/PetstoreClient/Infrastructure/JSONEncodingHelper.swift @@ -9,6 +9,8 @@ import Foundation open class JSONEncodingHelper { + static let encodingErrorParameterKey = "PetstoreClient.RequestBuilderError" + open class func encodingParameters(forEncodableObject encodableObj: T?, codableHelper: CodableHelper) -> [String: any Sendable]? { var params: [String: any Sendable]? @@ -19,7 +21,7 @@ open class JSONEncodingHelper { let data = try encodeResult.get() params = JSONDataEncoding.encodingParameters(jsonData: data) } catch { - print(error.localizedDescription) + params = [encodingErrorParameterKey: RequestBuilderError.bodyEncodingFailed(error)] } } diff --git a/samples/client/petstore/swift6/objcCompatible/Sources/PetstoreClient/Infrastructure/Models.swift b/samples/client/petstore/swift6/objcCompatible/Sources/PetstoreClient/Infrastructure/Models.swift index e98056ea6658..67ce3d455b21 100644 --- a/samples/client/petstore/swift6/objcCompatible/Sources/PetstoreClient/Infrastructure/Models.swift +++ b/samples/client/petstore/swift6/objcCompatible/Sources/PetstoreClient/Infrastructure/Models.swift @@ -81,6 +81,14 @@ public enum DownloadException: Error, Sendable { case requestMissingURL } +public enum RequestBuilderError: Error, Sendable { + case bodyEncodingFailed(any Error) + case unsupportedHTTPMethod(String) + case unsupportedMediaType(String) + case unsupportedParameterValue(key: String) + case unsupportedResponseType(String) +} + public enum DecodableRequestBuilderError: Error, Sendable { case emptyDataResponse case nilHTTPResponse diff --git a/samples/client/petstore/swift6/objcCompatible/Sources/PetstoreClient/Infrastructure/URLSessionImplementations.swift b/samples/client/petstore/swift6/objcCompatible/Sources/PetstoreClient/Infrastructure/URLSessionImplementations.swift index 5b993205718c..361032896a64 100644 --- a/samples/client/petstore/swift6/objcCompatible/Sources/PetstoreClient/Infrastructure/URLSessionImplementations.swift +++ b/samples/client/petstore/swift6/objcCompatible/Sources/PetstoreClient/Infrastructure/URLSessionImplementations.swift @@ -125,7 +125,7 @@ open class URLSessionRequestBuilder: RequestBuilder, @unchecked let urlSession = createURLSession() guard let xMethod = HTTPMethod(rawValue: method) else { - fatalError("Unsupported Http method - \(method)") + return failBeforeSending(RequestBuilderError.unsupportedHTTPMethod(method), urlSession: urlSession, completion: completion) } let encoding: ParameterEncoding @@ -146,11 +146,15 @@ open class URLSessionRequestBuilder: RequestBuilder, @unchecked } else if contentType.hasPrefix("application/octet-stream") || contentType.hasPrefix("image/") { encoding = OctetStreamEncoding() } else { - fatalError("Unsupported Media Type - \(contentType)") + return failBeforeSending(RequestBuilderError.unsupportedMediaType(contentType), urlSession: urlSession, completion: completion) } } do { + if let bodyEncodingError = parameters?[JSONEncodingHelper.encodingErrorParameterKey] as? RequestBuilderError { + throw bodyEncodingError + } + let request = try createURLRequest(urlSession: urlSession, method: xMethod, encoding: encoding, headers: headers) apiConfiguration.interceptor.intercept(urlRequest: request, urlSession: urlSession, requestBuilder: self) { result in @@ -222,16 +226,22 @@ open class URLSessionRequestBuilder: RequestBuilder, @unchecked } } } catch { - // Request creation failed - create a minimal request for error reporting - let failedURL = URL(string: URLString) ?? URL(string: "about:blank")! - var failedRequest = URLRequest(url: failedURL) - failedRequest.httpMethod = method + return failBeforeSending(error, urlSession: urlSession, completion: completion) + } + + return requestTask + } - self.apiConfiguration.interceptor.didComplete(urlRequest: failedRequest, urlSession: urlSession, requestBuilder: self, data: nil, response: nil, result: .failure(error)) + private func failBeforeSending(_ error: Error, urlSession: URLSessionProtocol, completion: @Sendable @escaping (_ result: Swift.Result, ErrorResponse>) -> Void) -> RequestTask { + // Request creation failed - create a minimal request for error reporting + let failedURL = URL(string: URLString) ?? URL(string: "about:blank")! + var failedRequest = URLRequest(url: failedURL) + failedRequest.httpMethod = method - self.apiConfiguration.apiResponseQueue.async { - completion(.failure(ErrorResponse.error(415, nil, nil, error))) - } + self.apiConfiguration.interceptor.didComplete(urlRequest: failedRequest, urlSession: urlSession, requestBuilder: self, data: nil, response: nil, result: .failure(error)) + + self.apiConfiguration.apiResponseQueue.async { + completion(.failure(ErrorResponse.error(415, nil, nil, error))) } return requestTask @@ -267,7 +277,9 @@ open class URLSessionRequestBuilder: RequestBuilder, @unchecked completion(.success(Response(response: httpResponse, body: result, bodyData: data))) default: - fatalError("Unsupported Response Body Type - \(String(describing: T.self))") + let error = RequestBuilderError.unsupportedResponseType(String(describing: T.self)) + apiConfiguration.interceptor.didComplete(urlRequest: urlRequest, urlSession: urlSession, requestBuilder: self, data: data, response: httpResponse, result: .failure(error)) + completion(.failure(ErrorResponse.error(httpResponse.statusCode, data, httpResponse, error))) } } @@ -554,7 +566,7 @@ private class FormDataEncoding: ParameterEncoding { } default: - fatalError("Unprocessable value \(value) with key \(key)") + throw RequestBuilderError.unsupportedParameterValue(key: key) } } } @@ -701,7 +713,7 @@ private class OctetStreamEncoding: ParameterEncoding { case let data as Data: urlRequest.httpBody = data default: - fatalError("Unprocessable body \(body)") + throw RequestBuilderError.unsupportedParameterValue(key: "body") } return urlRequest diff --git a/samples/client/petstore/swift6/oneOf/PetstoreClient/Classes/OpenAPIs/Infrastructure/JSONEncodingHelper.swift b/samples/client/petstore/swift6/oneOf/PetstoreClient/Classes/OpenAPIs/Infrastructure/JSONEncodingHelper.swift index 71c8b4e84faf..9d4d8cb2ae4a 100644 --- a/samples/client/petstore/swift6/oneOf/PetstoreClient/Classes/OpenAPIs/Infrastructure/JSONEncodingHelper.swift +++ b/samples/client/petstore/swift6/oneOf/PetstoreClient/Classes/OpenAPIs/Infrastructure/JSONEncodingHelper.swift @@ -9,6 +9,8 @@ import Foundation open class JSONEncodingHelper { + static let encodingErrorParameterKey = "PetstoreClient.RequestBuilderError" + open class func encodingParameters(forEncodableObject encodableObj: T?, codableHelper: CodableHelper) -> [String: any Sendable]? { var params: [String: any Sendable]? @@ -19,7 +21,7 @@ open class JSONEncodingHelper { let data = try encodeResult.get() params = JSONDataEncoding.encodingParameters(jsonData: data) } catch { - print(error.localizedDescription) + params = [encodingErrorParameterKey: RequestBuilderError.bodyEncodingFailed(error)] } } diff --git a/samples/client/petstore/swift6/oneOf/PetstoreClient/Classes/OpenAPIs/Infrastructure/Models.swift b/samples/client/petstore/swift6/oneOf/PetstoreClient/Classes/OpenAPIs/Infrastructure/Models.swift index e98056ea6658..67ce3d455b21 100644 --- a/samples/client/petstore/swift6/oneOf/PetstoreClient/Classes/OpenAPIs/Infrastructure/Models.swift +++ b/samples/client/petstore/swift6/oneOf/PetstoreClient/Classes/OpenAPIs/Infrastructure/Models.swift @@ -81,6 +81,14 @@ public enum DownloadException: Error, Sendable { case requestMissingURL } +public enum RequestBuilderError: Error, Sendable { + case bodyEncodingFailed(any Error) + case unsupportedHTTPMethod(String) + case unsupportedMediaType(String) + case unsupportedParameterValue(key: String) + case unsupportedResponseType(String) +} + public enum DecodableRequestBuilderError: Error, Sendable { case emptyDataResponse case nilHTTPResponse diff --git a/samples/client/petstore/swift6/oneOf/PetstoreClient/Classes/OpenAPIs/Infrastructure/URLSessionImplementations.swift b/samples/client/petstore/swift6/oneOf/PetstoreClient/Classes/OpenAPIs/Infrastructure/URLSessionImplementations.swift index 5b993205718c..361032896a64 100644 --- a/samples/client/petstore/swift6/oneOf/PetstoreClient/Classes/OpenAPIs/Infrastructure/URLSessionImplementations.swift +++ b/samples/client/petstore/swift6/oneOf/PetstoreClient/Classes/OpenAPIs/Infrastructure/URLSessionImplementations.swift @@ -125,7 +125,7 @@ open class URLSessionRequestBuilder: RequestBuilder, @unchecked let urlSession = createURLSession() guard let xMethod = HTTPMethod(rawValue: method) else { - fatalError("Unsupported Http method - \(method)") + return failBeforeSending(RequestBuilderError.unsupportedHTTPMethod(method), urlSession: urlSession, completion: completion) } let encoding: ParameterEncoding @@ -146,11 +146,15 @@ open class URLSessionRequestBuilder: RequestBuilder, @unchecked } else if contentType.hasPrefix("application/octet-stream") || contentType.hasPrefix("image/") { encoding = OctetStreamEncoding() } else { - fatalError("Unsupported Media Type - \(contentType)") + return failBeforeSending(RequestBuilderError.unsupportedMediaType(contentType), urlSession: urlSession, completion: completion) } } do { + if let bodyEncodingError = parameters?[JSONEncodingHelper.encodingErrorParameterKey] as? RequestBuilderError { + throw bodyEncodingError + } + let request = try createURLRequest(urlSession: urlSession, method: xMethod, encoding: encoding, headers: headers) apiConfiguration.interceptor.intercept(urlRequest: request, urlSession: urlSession, requestBuilder: self) { result in @@ -222,16 +226,22 @@ open class URLSessionRequestBuilder: RequestBuilder, @unchecked } } } catch { - // Request creation failed - create a minimal request for error reporting - let failedURL = URL(string: URLString) ?? URL(string: "about:blank")! - var failedRequest = URLRequest(url: failedURL) - failedRequest.httpMethod = method + return failBeforeSending(error, urlSession: urlSession, completion: completion) + } + + return requestTask + } - self.apiConfiguration.interceptor.didComplete(urlRequest: failedRequest, urlSession: urlSession, requestBuilder: self, data: nil, response: nil, result: .failure(error)) + private func failBeforeSending(_ error: Error, urlSession: URLSessionProtocol, completion: @Sendable @escaping (_ result: Swift.Result, ErrorResponse>) -> Void) -> RequestTask { + // Request creation failed - create a minimal request for error reporting + let failedURL = URL(string: URLString) ?? URL(string: "about:blank")! + var failedRequest = URLRequest(url: failedURL) + failedRequest.httpMethod = method - self.apiConfiguration.apiResponseQueue.async { - completion(.failure(ErrorResponse.error(415, nil, nil, error))) - } + self.apiConfiguration.interceptor.didComplete(urlRequest: failedRequest, urlSession: urlSession, requestBuilder: self, data: nil, response: nil, result: .failure(error)) + + self.apiConfiguration.apiResponseQueue.async { + completion(.failure(ErrorResponse.error(415, nil, nil, error))) } return requestTask @@ -267,7 +277,9 @@ open class URLSessionRequestBuilder: RequestBuilder, @unchecked completion(.success(Response(response: httpResponse, body: result, bodyData: data))) default: - fatalError("Unsupported Response Body Type - \(String(describing: T.self))") + let error = RequestBuilderError.unsupportedResponseType(String(describing: T.self)) + apiConfiguration.interceptor.didComplete(urlRequest: urlRequest, urlSession: urlSession, requestBuilder: self, data: data, response: httpResponse, result: .failure(error)) + completion(.failure(ErrorResponse.error(httpResponse.statusCode, data, httpResponse, error))) } } @@ -554,7 +566,7 @@ private class FormDataEncoding: ParameterEncoding { } default: - fatalError("Unprocessable value \(value) with key \(key)") + throw RequestBuilderError.unsupportedParameterValue(key: key) } } } @@ -701,7 +713,7 @@ private class OctetStreamEncoding: ParameterEncoding { case let data as Data: urlRequest.httpBody = data default: - fatalError("Unprocessable body \(body)") + throw RequestBuilderError.unsupportedParameterValue(key: "body") } return urlRequest diff --git a/samples/client/petstore/swift6/promisekitLibrary/PetstoreClient/Classes/OpenAPIs/Infrastructure/JSONEncodingHelper.swift b/samples/client/petstore/swift6/promisekitLibrary/PetstoreClient/Classes/OpenAPIs/Infrastructure/JSONEncodingHelper.swift index 71c8b4e84faf..9d4d8cb2ae4a 100644 --- a/samples/client/petstore/swift6/promisekitLibrary/PetstoreClient/Classes/OpenAPIs/Infrastructure/JSONEncodingHelper.swift +++ b/samples/client/petstore/swift6/promisekitLibrary/PetstoreClient/Classes/OpenAPIs/Infrastructure/JSONEncodingHelper.swift @@ -9,6 +9,8 @@ import Foundation open class JSONEncodingHelper { + static let encodingErrorParameterKey = "PetstoreClient.RequestBuilderError" + open class func encodingParameters(forEncodableObject encodableObj: T?, codableHelper: CodableHelper) -> [String: any Sendable]? { var params: [String: any Sendable]? @@ -19,7 +21,7 @@ open class JSONEncodingHelper { let data = try encodeResult.get() params = JSONDataEncoding.encodingParameters(jsonData: data) } catch { - print(error.localizedDescription) + params = [encodingErrorParameterKey: RequestBuilderError.bodyEncodingFailed(error)] } } diff --git a/samples/client/petstore/swift6/promisekitLibrary/PetstoreClient/Classes/OpenAPIs/Infrastructure/Models.swift b/samples/client/petstore/swift6/promisekitLibrary/PetstoreClient/Classes/OpenAPIs/Infrastructure/Models.swift index e98056ea6658..67ce3d455b21 100644 --- a/samples/client/petstore/swift6/promisekitLibrary/PetstoreClient/Classes/OpenAPIs/Infrastructure/Models.swift +++ b/samples/client/petstore/swift6/promisekitLibrary/PetstoreClient/Classes/OpenAPIs/Infrastructure/Models.swift @@ -81,6 +81,14 @@ public enum DownloadException: Error, Sendable { case requestMissingURL } +public enum RequestBuilderError: Error, Sendable { + case bodyEncodingFailed(any Error) + case unsupportedHTTPMethod(String) + case unsupportedMediaType(String) + case unsupportedParameterValue(key: String) + case unsupportedResponseType(String) +} + public enum DecodableRequestBuilderError: Error, Sendable { case emptyDataResponse case nilHTTPResponse diff --git a/samples/client/petstore/swift6/promisekitLibrary/PetstoreClient/Classes/OpenAPIs/Infrastructure/URLSessionImplementations.swift b/samples/client/petstore/swift6/promisekitLibrary/PetstoreClient/Classes/OpenAPIs/Infrastructure/URLSessionImplementations.swift index 5b993205718c..361032896a64 100644 --- a/samples/client/petstore/swift6/promisekitLibrary/PetstoreClient/Classes/OpenAPIs/Infrastructure/URLSessionImplementations.swift +++ b/samples/client/petstore/swift6/promisekitLibrary/PetstoreClient/Classes/OpenAPIs/Infrastructure/URLSessionImplementations.swift @@ -125,7 +125,7 @@ open class URLSessionRequestBuilder: RequestBuilder, @unchecked let urlSession = createURLSession() guard let xMethod = HTTPMethod(rawValue: method) else { - fatalError("Unsupported Http method - \(method)") + return failBeforeSending(RequestBuilderError.unsupportedHTTPMethod(method), urlSession: urlSession, completion: completion) } let encoding: ParameterEncoding @@ -146,11 +146,15 @@ open class URLSessionRequestBuilder: RequestBuilder, @unchecked } else if contentType.hasPrefix("application/octet-stream") || contentType.hasPrefix("image/") { encoding = OctetStreamEncoding() } else { - fatalError("Unsupported Media Type - \(contentType)") + return failBeforeSending(RequestBuilderError.unsupportedMediaType(contentType), urlSession: urlSession, completion: completion) } } do { + if let bodyEncodingError = parameters?[JSONEncodingHelper.encodingErrorParameterKey] as? RequestBuilderError { + throw bodyEncodingError + } + let request = try createURLRequest(urlSession: urlSession, method: xMethod, encoding: encoding, headers: headers) apiConfiguration.interceptor.intercept(urlRequest: request, urlSession: urlSession, requestBuilder: self) { result in @@ -222,16 +226,22 @@ open class URLSessionRequestBuilder: RequestBuilder, @unchecked } } } catch { - // Request creation failed - create a minimal request for error reporting - let failedURL = URL(string: URLString) ?? URL(string: "about:blank")! - var failedRequest = URLRequest(url: failedURL) - failedRequest.httpMethod = method + return failBeforeSending(error, urlSession: urlSession, completion: completion) + } + + return requestTask + } - self.apiConfiguration.interceptor.didComplete(urlRequest: failedRequest, urlSession: urlSession, requestBuilder: self, data: nil, response: nil, result: .failure(error)) + private func failBeforeSending(_ error: Error, urlSession: URLSessionProtocol, completion: @Sendable @escaping (_ result: Swift.Result, ErrorResponse>) -> Void) -> RequestTask { + // Request creation failed - create a minimal request for error reporting + let failedURL = URL(string: URLString) ?? URL(string: "about:blank")! + var failedRequest = URLRequest(url: failedURL) + failedRequest.httpMethod = method - self.apiConfiguration.apiResponseQueue.async { - completion(.failure(ErrorResponse.error(415, nil, nil, error))) - } + self.apiConfiguration.interceptor.didComplete(urlRequest: failedRequest, urlSession: urlSession, requestBuilder: self, data: nil, response: nil, result: .failure(error)) + + self.apiConfiguration.apiResponseQueue.async { + completion(.failure(ErrorResponse.error(415, nil, nil, error))) } return requestTask @@ -267,7 +277,9 @@ open class URLSessionRequestBuilder: RequestBuilder, @unchecked completion(.success(Response(response: httpResponse, body: result, bodyData: data))) default: - fatalError("Unsupported Response Body Type - \(String(describing: T.self))") + let error = RequestBuilderError.unsupportedResponseType(String(describing: T.self)) + apiConfiguration.interceptor.didComplete(urlRequest: urlRequest, urlSession: urlSession, requestBuilder: self, data: data, response: httpResponse, result: .failure(error)) + completion(.failure(ErrorResponse.error(httpResponse.statusCode, data, httpResponse, error))) } } @@ -554,7 +566,7 @@ private class FormDataEncoding: ParameterEncoding { } default: - fatalError("Unprocessable value \(value) with key \(key)") + throw RequestBuilderError.unsupportedParameterValue(key: key) } } } @@ -701,7 +713,7 @@ private class OctetStreamEncoding: ParameterEncoding { case let data as Data: urlRequest.httpBody = data default: - fatalError("Unprocessable body \(body)") + throw RequestBuilderError.unsupportedParameterValue(key: "body") } return urlRequest diff --git a/samples/client/petstore/swift6/resultLibrary/PetstoreClient/Classes/OpenAPIs/Infrastructure/JSONEncodingHelper.swift b/samples/client/petstore/swift6/resultLibrary/PetstoreClient/Classes/OpenAPIs/Infrastructure/JSONEncodingHelper.swift index 7d61b0e77569..e404b1885446 100644 --- a/samples/client/petstore/swift6/resultLibrary/PetstoreClient/Classes/OpenAPIs/Infrastructure/JSONEncodingHelper.swift +++ b/samples/client/petstore/swift6/resultLibrary/PetstoreClient/Classes/OpenAPIs/Infrastructure/JSONEncodingHelper.swift @@ -9,6 +9,8 @@ import Foundation internal class JSONEncodingHelper { + static let encodingErrorParameterKey = "PetstoreClient.RequestBuilderError" + internal class func encodingParameters(forEncodableObject encodableObj: T?, codableHelper: CodableHelper) -> [String: any Sendable]? { var params: [String: any Sendable]? @@ -19,7 +21,7 @@ internal class JSONEncodingHelper { let data = try encodeResult.get() params = JSONDataEncoding.encodingParameters(jsonData: data) } catch { - print(error.localizedDescription) + params = [encodingErrorParameterKey: RequestBuilderError.bodyEncodingFailed(error)] } } diff --git a/samples/client/petstore/swift6/resultLibrary/PetstoreClient/Classes/OpenAPIs/Infrastructure/Models.swift b/samples/client/petstore/swift6/resultLibrary/PetstoreClient/Classes/OpenAPIs/Infrastructure/Models.swift index 684e7891f0bc..94a3794a3458 100644 --- a/samples/client/petstore/swift6/resultLibrary/PetstoreClient/Classes/OpenAPIs/Infrastructure/Models.swift +++ b/samples/client/petstore/swift6/resultLibrary/PetstoreClient/Classes/OpenAPIs/Infrastructure/Models.swift @@ -92,6 +92,14 @@ internal enum DownloadException: Error, Sendable { case requestMissingURL } +internal enum RequestBuilderError: Error, Sendable { + case bodyEncodingFailed(any Error) + case unsupportedHTTPMethod(String) + case unsupportedMediaType(String) + case unsupportedParameterValue(key: String) + case unsupportedResponseType(String) +} + internal enum DecodableRequestBuilderError: Error, Sendable { case emptyDataResponse case nilHTTPResponse diff --git a/samples/client/petstore/swift6/resultLibrary/PetstoreClient/Classes/OpenAPIs/Infrastructure/URLSessionImplementations.swift b/samples/client/petstore/swift6/resultLibrary/PetstoreClient/Classes/OpenAPIs/Infrastructure/URLSessionImplementations.swift index 8109567dcc10..f2989a0593ee 100644 --- a/samples/client/petstore/swift6/resultLibrary/PetstoreClient/Classes/OpenAPIs/Infrastructure/URLSessionImplementations.swift +++ b/samples/client/petstore/swift6/resultLibrary/PetstoreClient/Classes/OpenAPIs/Infrastructure/URLSessionImplementations.swift @@ -125,7 +125,7 @@ internal class URLSessionRequestBuilder: RequestBuilder, @unchec let urlSession = createURLSession() guard let xMethod = HTTPMethod(rawValue: method) else { - fatalError("Unsupported Http method - \(method)") + return failBeforeSending(RequestBuilderError.unsupportedHTTPMethod(method), urlSession: urlSession, completion: completion) } let encoding: ParameterEncoding @@ -146,11 +146,15 @@ internal class URLSessionRequestBuilder: RequestBuilder, @unchec } else if contentType.hasPrefix("application/octet-stream") || contentType.hasPrefix("image/") { encoding = OctetStreamEncoding() } else { - fatalError("Unsupported Media Type - \(contentType)") + return failBeforeSending(RequestBuilderError.unsupportedMediaType(contentType), urlSession: urlSession, completion: completion) } } do { + if let bodyEncodingError = parameters?[JSONEncodingHelper.encodingErrorParameterKey] as? RequestBuilderError { + throw bodyEncodingError + } + let request = try createURLRequest(urlSession: urlSession, method: xMethod, encoding: encoding, headers: headers) apiConfiguration.interceptor.intercept(urlRequest: request, urlSession: urlSession, requestBuilder: self) { result in @@ -222,16 +226,22 @@ internal class URLSessionRequestBuilder: RequestBuilder, @unchec } } } catch { - // Request creation failed - create a minimal request for error reporting - let failedURL = URL(string: URLString) ?? URL(string: "about:blank")! - var failedRequest = URLRequest(url: failedURL) - failedRequest.httpMethod = method + return failBeforeSending(error, urlSession: urlSession, completion: completion) + } + + return requestTask + } - self.apiConfiguration.interceptor.didComplete(urlRequest: failedRequest, urlSession: urlSession, requestBuilder: self, data: nil, response: nil, result: .failure(error)) + private func failBeforeSending(_ error: Error, urlSession: URLSessionProtocol, completion: @Sendable @escaping (_ result: Swift.Result, ErrorResponse>) -> Void) -> RequestTask { + // Request creation failed - create a minimal request for error reporting + let failedURL = URL(string: URLString) ?? URL(string: "about:blank")! + var failedRequest = URLRequest(url: failedURL) + failedRequest.httpMethod = method - self.apiConfiguration.apiResponseQueue.async { - completion(.failure(ErrorResponse.error(415, nil, nil, error))) - } + self.apiConfiguration.interceptor.didComplete(urlRequest: failedRequest, urlSession: urlSession, requestBuilder: self, data: nil, response: nil, result: .failure(error)) + + self.apiConfiguration.apiResponseQueue.async { + completion(.failure(ErrorResponse.error(415, nil, nil, error))) } return requestTask @@ -267,7 +277,9 @@ internal class URLSessionRequestBuilder: RequestBuilder, @unchec completion(.success(Response(response: httpResponse, body: result, bodyData: data))) default: - fatalError("Unsupported Response Body Type - \(String(describing: T.self))") + let error = RequestBuilderError.unsupportedResponseType(String(describing: T.self)) + apiConfiguration.interceptor.didComplete(urlRequest: urlRequest, urlSession: urlSession, requestBuilder: self, data: data, response: httpResponse, result: .failure(error)) + completion(.failure(ErrorResponse.error(httpResponse.statusCode, data, httpResponse, error))) } } @@ -554,7 +566,7 @@ private class FormDataEncoding: ParameterEncoding { } default: - fatalError("Unprocessable value \(value) with key \(key)") + throw RequestBuilderError.unsupportedParameterValue(key: key) } } } @@ -701,7 +713,7 @@ private class OctetStreamEncoding: ParameterEncoding { case let data as Data: urlRequest.httpBody = data default: - fatalError("Unprocessable body \(body)") + throw RequestBuilderError.unsupportedParameterValue(key: "body") } return urlRequest diff --git a/samples/client/petstore/swift6/rxswiftLibrary/PetstoreClient/Classes/OpenAPIs/Infrastructure/JSONEncodingHelper.swift b/samples/client/petstore/swift6/rxswiftLibrary/PetstoreClient/Classes/OpenAPIs/Infrastructure/JSONEncodingHelper.swift index 71c8b4e84faf..9d4d8cb2ae4a 100644 --- a/samples/client/petstore/swift6/rxswiftLibrary/PetstoreClient/Classes/OpenAPIs/Infrastructure/JSONEncodingHelper.swift +++ b/samples/client/petstore/swift6/rxswiftLibrary/PetstoreClient/Classes/OpenAPIs/Infrastructure/JSONEncodingHelper.swift @@ -9,6 +9,8 @@ import Foundation open class JSONEncodingHelper { + static let encodingErrorParameterKey = "PetstoreClient.RequestBuilderError" + open class func encodingParameters(forEncodableObject encodableObj: T?, codableHelper: CodableHelper) -> [String: any Sendable]? { var params: [String: any Sendable]? @@ -19,7 +21,7 @@ open class JSONEncodingHelper { let data = try encodeResult.get() params = JSONDataEncoding.encodingParameters(jsonData: data) } catch { - print(error.localizedDescription) + params = [encodingErrorParameterKey: RequestBuilderError.bodyEncodingFailed(error)] } } diff --git a/samples/client/petstore/swift6/rxswiftLibrary/PetstoreClient/Classes/OpenAPIs/Infrastructure/Models.swift b/samples/client/petstore/swift6/rxswiftLibrary/PetstoreClient/Classes/OpenAPIs/Infrastructure/Models.swift index e98056ea6658..67ce3d455b21 100644 --- a/samples/client/petstore/swift6/rxswiftLibrary/PetstoreClient/Classes/OpenAPIs/Infrastructure/Models.swift +++ b/samples/client/petstore/swift6/rxswiftLibrary/PetstoreClient/Classes/OpenAPIs/Infrastructure/Models.swift @@ -81,6 +81,14 @@ public enum DownloadException: Error, Sendable { case requestMissingURL } +public enum RequestBuilderError: Error, Sendable { + case bodyEncodingFailed(any Error) + case unsupportedHTTPMethod(String) + case unsupportedMediaType(String) + case unsupportedParameterValue(key: String) + case unsupportedResponseType(String) +} + public enum DecodableRequestBuilderError: Error, Sendable { case emptyDataResponse case nilHTTPResponse diff --git a/samples/client/petstore/swift6/rxswiftLibrary/PetstoreClient/Classes/OpenAPIs/Infrastructure/URLSessionImplementations.swift b/samples/client/petstore/swift6/rxswiftLibrary/PetstoreClient/Classes/OpenAPIs/Infrastructure/URLSessionImplementations.swift index 5b993205718c..361032896a64 100644 --- a/samples/client/petstore/swift6/rxswiftLibrary/PetstoreClient/Classes/OpenAPIs/Infrastructure/URLSessionImplementations.swift +++ b/samples/client/petstore/swift6/rxswiftLibrary/PetstoreClient/Classes/OpenAPIs/Infrastructure/URLSessionImplementations.swift @@ -125,7 +125,7 @@ open class URLSessionRequestBuilder: RequestBuilder, @unchecked let urlSession = createURLSession() guard let xMethod = HTTPMethod(rawValue: method) else { - fatalError("Unsupported Http method - \(method)") + return failBeforeSending(RequestBuilderError.unsupportedHTTPMethod(method), urlSession: urlSession, completion: completion) } let encoding: ParameterEncoding @@ -146,11 +146,15 @@ open class URLSessionRequestBuilder: RequestBuilder, @unchecked } else if contentType.hasPrefix("application/octet-stream") || contentType.hasPrefix("image/") { encoding = OctetStreamEncoding() } else { - fatalError("Unsupported Media Type - \(contentType)") + return failBeforeSending(RequestBuilderError.unsupportedMediaType(contentType), urlSession: urlSession, completion: completion) } } do { + if let bodyEncodingError = parameters?[JSONEncodingHelper.encodingErrorParameterKey] as? RequestBuilderError { + throw bodyEncodingError + } + let request = try createURLRequest(urlSession: urlSession, method: xMethod, encoding: encoding, headers: headers) apiConfiguration.interceptor.intercept(urlRequest: request, urlSession: urlSession, requestBuilder: self) { result in @@ -222,16 +226,22 @@ open class URLSessionRequestBuilder: RequestBuilder, @unchecked } } } catch { - // Request creation failed - create a minimal request for error reporting - let failedURL = URL(string: URLString) ?? URL(string: "about:blank")! - var failedRequest = URLRequest(url: failedURL) - failedRequest.httpMethod = method + return failBeforeSending(error, urlSession: urlSession, completion: completion) + } + + return requestTask + } - self.apiConfiguration.interceptor.didComplete(urlRequest: failedRequest, urlSession: urlSession, requestBuilder: self, data: nil, response: nil, result: .failure(error)) + private func failBeforeSending(_ error: Error, urlSession: URLSessionProtocol, completion: @Sendable @escaping (_ result: Swift.Result, ErrorResponse>) -> Void) -> RequestTask { + // Request creation failed - create a minimal request for error reporting + let failedURL = URL(string: URLString) ?? URL(string: "about:blank")! + var failedRequest = URLRequest(url: failedURL) + failedRequest.httpMethod = method - self.apiConfiguration.apiResponseQueue.async { - completion(.failure(ErrorResponse.error(415, nil, nil, error))) - } + self.apiConfiguration.interceptor.didComplete(urlRequest: failedRequest, urlSession: urlSession, requestBuilder: self, data: nil, response: nil, result: .failure(error)) + + self.apiConfiguration.apiResponseQueue.async { + completion(.failure(ErrorResponse.error(415, nil, nil, error))) } return requestTask @@ -267,7 +277,9 @@ open class URLSessionRequestBuilder: RequestBuilder, @unchecked completion(.success(Response(response: httpResponse, body: result, bodyData: data))) default: - fatalError("Unsupported Response Body Type - \(String(describing: T.self))") + let error = RequestBuilderError.unsupportedResponseType(String(describing: T.self)) + apiConfiguration.interceptor.didComplete(urlRequest: urlRequest, urlSession: urlSession, requestBuilder: self, data: data, response: httpResponse, result: .failure(error)) + completion(.failure(ErrorResponse.error(httpResponse.statusCode, data, httpResponse, error))) } } @@ -554,7 +566,7 @@ private class FormDataEncoding: ParameterEncoding { } default: - fatalError("Unprocessable value \(value) with key \(key)") + throw RequestBuilderError.unsupportedParameterValue(key: key) } } } @@ -701,7 +713,7 @@ private class OctetStreamEncoding: ParameterEncoding { case let data as Data: urlRequest.httpBody = data default: - fatalError("Unprocessable body \(body)") + throw RequestBuilderError.unsupportedParameterValue(key: "body") } return urlRequest diff --git a/samples/client/petstore/swift6/urlsessionLibrary/Sources/PetstoreClient/Infrastructure/JSONEncodingHelper.swift b/samples/client/petstore/swift6/urlsessionLibrary/Sources/PetstoreClient/Infrastructure/JSONEncodingHelper.swift index 71c8b4e84faf..9d4d8cb2ae4a 100644 --- a/samples/client/petstore/swift6/urlsessionLibrary/Sources/PetstoreClient/Infrastructure/JSONEncodingHelper.swift +++ b/samples/client/petstore/swift6/urlsessionLibrary/Sources/PetstoreClient/Infrastructure/JSONEncodingHelper.swift @@ -9,6 +9,8 @@ import Foundation open class JSONEncodingHelper { + static let encodingErrorParameterKey = "PetstoreClient.RequestBuilderError" + open class func encodingParameters(forEncodableObject encodableObj: T?, codableHelper: CodableHelper) -> [String: any Sendable]? { var params: [String: any Sendable]? @@ -19,7 +21,7 @@ open class JSONEncodingHelper { let data = try encodeResult.get() params = JSONDataEncoding.encodingParameters(jsonData: data) } catch { - print(error.localizedDescription) + params = [encodingErrorParameterKey: RequestBuilderError.bodyEncodingFailed(error)] } } diff --git a/samples/client/petstore/swift6/urlsessionLibrary/Sources/PetstoreClient/Infrastructure/Models.swift b/samples/client/petstore/swift6/urlsessionLibrary/Sources/PetstoreClient/Infrastructure/Models.swift index e98056ea6658..67ce3d455b21 100644 --- a/samples/client/petstore/swift6/urlsessionLibrary/Sources/PetstoreClient/Infrastructure/Models.swift +++ b/samples/client/petstore/swift6/urlsessionLibrary/Sources/PetstoreClient/Infrastructure/Models.swift @@ -81,6 +81,14 @@ public enum DownloadException: Error, Sendable { case requestMissingURL } +public enum RequestBuilderError: Error, Sendable { + case bodyEncodingFailed(any Error) + case unsupportedHTTPMethod(String) + case unsupportedMediaType(String) + case unsupportedParameterValue(key: String) + case unsupportedResponseType(String) +} + public enum DecodableRequestBuilderError: Error, Sendable { case emptyDataResponse case nilHTTPResponse diff --git a/samples/client/petstore/swift6/urlsessionLibrary/Sources/PetstoreClient/Infrastructure/URLSessionImplementations.swift b/samples/client/petstore/swift6/urlsessionLibrary/Sources/PetstoreClient/Infrastructure/URLSessionImplementations.swift index 5b993205718c..361032896a64 100644 --- a/samples/client/petstore/swift6/urlsessionLibrary/Sources/PetstoreClient/Infrastructure/URLSessionImplementations.swift +++ b/samples/client/petstore/swift6/urlsessionLibrary/Sources/PetstoreClient/Infrastructure/URLSessionImplementations.swift @@ -125,7 +125,7 @@ open class URLSessionRequestBuilder: RequestBuilder, @unchecked let urlSession = createURLSession() guard let xMethod = HTTPMethod(rawValue: method) else { - fatalError("Unsupported Http method - \(method)") + return failBeforeSending(RequestBuilderError.unsupportedHTTPMethod(method), urlSession: urlSession, completion: completion) } let encoding: ParameterEncoding @@ -146,11 +146,15 @@ open class URLSessionRequestBuilder: RequestBuilder, @unchecked } else if contentType.hasPrefix("application/octet-stream") || contentType.hasPrefix("image/") { encoding = OctetStreamEncoding() } else { - fatalError("Unsupported Media Type - \(contentType)") + return failBeforeSending(RequestBuilderError.unsupportedMediaType(contentType), urlSession: urlSession, completion: completion) } } do { + if let bodyEncodingError = parameters?[JSONEncodingHelper.encodingErrorParameterKey] as? RequestBuilderError { + throw bodyEncodingError + } + let request = try createURLRequest(urlSession: urlSession, method: xMethod, encoding: encoding, headers: headers) apiConfiguration.interceptor.intercept(urlRequest: request, urlSession: urlSession, requestBuilder: self) { result in @@ -222,16 +226,22 @@ open class URLSessionRequestBuilder: RequestBuilder, @unchecked } } } catch { - // Request creation failed - create a minimal request for error reporting - let failedURL = URL(string: URLString) ?? URL(string: "about:blank")! - var failedRequest = URLRequest(url: failedURL) - failedRequest.httpMethod = method + return failBeforeSending(error, urlSession: urlSession, completion: completion) + } + + return requestTask + } - self.apiConfiguration.interceptor.didComplete(urlRequest: failedRequest, urlSession: urlSession, requestBuilder: self, data: nil, response: nil, result: .failure(error)) + private func failBeforeSending(_ error: Error, urlSession: URLSessionProtocol, completion: @Sendable @escaping (_ result: Swift.Result, ErrorResponse>) -> Void) -> RequestTask { + // Request creation failed - create a minimal request for error reporting + let failedURL = URL(string: URLString) ?? URL(string: "about:blank")! + var failedRequest = URLRequest(url: failedURL) + failedRequest.httpMethod = method - self.apiConfiguration.apiResponseQueue.async { - completion(.failure(ErrorResponse.error(415, nil, nil, error))) - } + self.apiConfiguration.interceptor.didComplete(urlRequest: failedRequest, urlSession: urlSession, requestBuilder: self, data: nil, response: nil, result: .failure(error)) + + self.apiConfiguration.apiResponseQueue.async { + completion(.failure(ErrorResponse.error(415, nil, nil, error))) } return requestTask @@ -267,7 +277,9 @@ open class URLSessionRequestBuilder: RequestBuilder, @unchecked completion(.success(Response(response: httpResponse, body: result, bodyData: data))) default: - fatalError("Unsupported Response Body Type - \(String(describing: T.self))") + let error = RequestBuilderError.unsupportedResponseType(String(describing: T.self)) + apiConfiguration.interceptor.didComplete(urlRequest: urlRequest, urlSession: urlSession, requestBuilder: self, data: data, response: httpResponse, result: .failure(error)) + completion(.failure(ErrorResponse.error(httpResponse.statusCode, data, httpResponse, error))) } } @@ -554,7 +566,7 @@ private class FormDataEncoding: ParameterEncoding { } default: - fatalError("Unprocessable value \(value) with key \(key)") + throw RequestBuilderError.unsupportedParameterValue(key: key) } } } @@ -701,7 +713,7 @@ private class OctetStreamEncoding: ParameterEncoding { case let data as Data: urlRequest.httpBody = data default: - fatalError("Unprocessable body \(body)") + throw RequestBuilderError.unsupportedParameterValue(key: "body") } return urlRequest diff --git a/samples/client/petstore/swift6/validation/PetstoreClient/Classes/OpenAPIs/Infrastructure/JSONEncodingHelper.swift b/samples/client/petstore/swift6/validation/PetstoreClient/Classes/OpenAPIs/Infrastructure/JSONEncodingHelper.swift index 71c8b4e84faf..9d4d8cb2ae4a 100644 --- a/samples/client/petstore/swift6/validation/PetstoreClient/Classes/OpenAPIs/Infrastructure/JSONEncodingHelper.swift +++ b/samples/client/petstore/swift6/validation/PetstoreClient/Classes/OpenAPIs/Infrastructure/JSONEncodingHelper.swift @@ -9,6 +9,8 @@ import Foundation open class JSONEncodingHelper { + static let encodingErrorParameterKey = "PetstoreClient.RequestBuilderError" + open class func encodingParameters(forEncodableObject encodableObj: T?, codableHelper: CodableHelper) -> [String: any Sendable]? { var params: [String: any Sendable]? @@ -19,7 +21,7 @@ open class JSONEncodingHelper { let data = try encodeResult.get() params = JSONDataEncoding.encodingParameters(jsonData: data) } catch { - print(error.localizedDescription) + params = [encodingErrorParameterKey: RequestBuilderError.bodyEncodingFailed(error)] } } diff --git a/samples/client/petstore/swift6/validation/PetstoreClient/Classes/OpenAPIs/Infrastructure/Models.swift b/samples/client/petstore/swift6/validation/PetstoreClient/Classes/OpenAPIs/Infrastructure/Models.swift index 143346e8a061..a3f59079bc6f 100644 --- a/samples/client/petstore/swift6/validation/PetstoreClient/Classes/OpenAPIs/Infrastructure/Models.swift +++ b/samples/client/petstore/swift6/validation/PetstoreClient/Classes/OpenAPIs/Infrastructure/Models.swift @@ -81,6 +81,14 @@ public enum DownloadException: Error, Sendable { case requestMissingURL } +public enum RequestBuilderError: Error, Sendable { + case bodyEncodingFailed(any Error) + case unsupportedHTTPMethod(String) + case unsupportedMediaType(String) + case unsupportedParameterValue(key: String) + case unsupportedResponseType(String) +} + public enum DecodableRequestBuilderError: Error, Sendable { case emptyDataResponse case nilHTTPResponse diff --git a/samples/client/petstore/swift6/validation/PetstoreClient/Classes/OpenAPIs/Infrastructure/URLSessionImplementations.swift b/samples/client/petstore/swift6/validation/PetstoreClient/Classes/OpenAPIs/Infrastructure/URLSessionImplementations.swift index 5b993205718c..361032896a64 100644 --- a/samples/client/petstore/swift6/validation/PetstoreClient/Classes/OpenAPIs/Infrastructure/URLSessionImplementations.swift +++ b/samples/client/petstore/swift6/validation/PetstoreClient/Classes/OpenAPIs/Infrastructure/URLSessionImplementations.swift @@ -125,7 +125,7 @@ open class URLSessionRequestBuilder: RequestBuilder, @unchecked let urlSession = createURLSession() guard let xMethod = HTTPMethod(rawValue: method) else { - fatalError("Unsupported Http method - \(method)") + return failBeforeSending(RequestBuilderError.unsupportedHTTPMethod(method), urlSession: urlSession, completion: completion) } let encoding: ParameterEncoding @@ -146,11 +146,15 @@ open class URLSessionRequestBuilder: RequestBuilder, @unchecked } else if contentType.hasPrefix("application/octet-stream") || contentType.hasPrefix("image/") { encoding = OctetStreamEncoding() } else { - fatalError("Unsupported Media Type - \(contentType)") + return failBeforeSending(RequestBuilderError.unsupportedMediaType(contentType), urlSession: urlSession, completion: completion) } } do { + if let bodyEncodingError = parameters?[JSONEncodingHelper.encodingErrorParameterKey] as? RequestBuilderError { + throw bodyEncodingError + } + let request = try createURLRequest(urlSession: urlSession, method: xMethod, encoding: encoding, headers: headers) apiConfiguration.interceptor.intercept(urlRequest: request, urlSession: urlSession, requestBuilder: self) { result in @@ -222,16 +226,22 @@ open class URLSessionRequestBuilder: RequestBuilder, @unchecked } } } catch { - // Request creation failed - create a minimal request for error reporting - let failedURL = URL(string: URLString) ?? URL(string: "about:blank")! - var failedRequest = URLRequest(url: failedURL) - failedRequest.httpMethod = method + return failBeforeSending(error, urlSession: urlSession, completion: completion) + } + + return requestTask + } - self.apiConfiguration.interceptor.didComplete(urlRequest: failedRequest, urlSession: urlSession, requestBuilder: self, data: nil, response: nil, result: .failure(error)) + private func failBeforeSending(_ error: Error, urlSession: URLSessionProtocol, completion: @Sendable @escaping (_ result: Swift.Result, ErrorResponse>) -> Void) -> RequestTask { + // Request creation failed - create a minimal request for error reporting + let failedURL = URL(string: URLString) ?? URL(string: "about:blank")! + var failedRequest = URLRequest(url: failedURL) + failedRequest.httpMethod = method - self.apiConfiguration.apiResponseQueue.async { - completion(.failure(ErrorResponse.error(415, nil, nil, error))) - } + self.apiConfiguration.interceptor.didComplete(urlRequest: failedRequest, urlSession: urlSession, requestBuilder: self, data: nil, response: nil, result: .failure(error)) + + self.apiConfiguration.apiResponseQueue.async { + completion(.failure(ErrorResponse.error(415, nil, nil, error))) } return requestTask @@ -267,7 +277,9 @@ open class URLSessionRequestBuilder: RequestBuilder, @unchecked completion(.success(Response(response: httpResponse, body: result, bodyData: data))) default: - fatalError("Unsupported Response Body Type - \(String(describing: T.self))") + let error = RequestBuilderError.unsupportedResponseType(String(describing: T.self)) + apiConfiguration.interceptor.didComplete(urlRequest: urlRequest, urlSession: urlSession, requestBuilder: self, data: data, response: httpResponse, result: .failure(error)) + completion(.failure(ErrorResponse.error(httpResponse.statusCode, data, httpResponse, error))) } } @@ -554,7 +566,7 @@ private class FormDataEncoding: ParameterEncoding { } default: - fatalError("Unprocessable value \(value) with key \(key)") + throw RequestBuilderError.unsupportedParameterValue(key: key) } } } @@ -701,7 +713,7 @@ private class OctetStreamEncoding: ParameterEncoding { case let data as Data: urlRequest.httpBody = data default: - fatalError("Unprocessable body \(body)") + throw RequestBuilderError.unsupportedParameterValue(key: "body") } return urlRequest From 1f5c654c26af1ce28bb74091428b40b36c739af4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20Rusi=C5=88=C3=A1k?= <1114245+spigo@users.noreply.github.com> Date: Thu, 8 Oct 2026 15:29:03 +0200 Subject: [PATCH 2/4] [swift6][alamofire] Check the response before writing a downloaded file Fail with nilHTTPResponse before writing the file, so a download without an HTTP response no longer leaves an unreturned file in the caches directory. --- .../alamofire/AlamofireImplementations.mustache | 13 +++++++------ .../Infrastructure/AlamofireImplementations.swift | 13 +++++++------ .../Infrastructure/AlamofireImplementations.swift | 13 +++++++------ 3 files changed, 21 insertions(+), 18 deletions(-) diff --git a/modules/openapi-generator/src/main/resources/swift6/libraries/alamofire/AlamofireImplementations.mustache b/modules/openapi-generator/src/main/resources/swift6/libraries/alamofire/AlamofireImplementations.mustache index 9633f87ad7fc..660d2336b6a5 100644 --- a/modules/openapi-generator/src/main/resources/swift6/libraries/alamofire/AlamofireImplementations.mustache +++ b/modules/openapi-generator/src/main/resources/swift6/libraries/alamofire/AlamofireImplementations.mustache @@ -342,6 +342,11 @@ fileprivate class AlamofireRequestBuilderConfiguration: @unchecked Sendable { throw DownloadException.responseDataMissing } + guard let httpResponse = dataResponse.response else { + completion(.failure(ErrorResponse.error(-2, dataResponse.data, nil, DecodableRequestBuilderError.nilHTTPResponse))) + return + } + guard let request = request.request else { throw DownloadException.requestMissing } @@ -353,7 +358,7 @@ fileprivate class AlamofireRequestBuilderConfiguration: @unchecked Sendable { var requestPath = try self.getPath(from: requestURL) - if let headerFileName = self.getFileName(fromContentDisposition: dataResponse.response?.allHeaderFields["Content-Disposition"] as? String) { + if let headerFileName = self.getFileName(fromContentDisposition: httpResponse.allHeaderFields["Content-Disposition"] as? String) { requestPath = requestPath.appending("/\(headerFileName)") } else { requestPath = requestPath.appending("/tmp.{{projectName}}.\(UUID().uuidString)") @@ -365,11 +370,7 @@ fileprivate class AlamofireRequestBuilderConfiguration: @unchecked Sendable { try fileManager.createDirectory(atPath: directoryPath, withIntermediateDirectories: true, attributes: nil) try data.write(to: filePath, options: .atomic) - if let httpResponse = dataResponse.response { - completion(.success(Response(response: httpResponse, body: filePath as! T, bodyData: data))) - } else { - completion(.failure(ErrorResponse.error(-2, dataResponse.data, nil, DecodableRequestBuilderError.nilHTTPResponse))) - } + completion(.success(Response(response: httpResponse, body: filePath as! T, bodyData: data))) } catch let requestParserError as DownloadException { completion(.failure(ErrorResponse.error(400, dataResponse.data, dataResponse.response, requestParserError))) diff --git a/samples/client/petstore/swift6/alamofireLibrary/Sources/PetstoreClient/Infrastructure/AlamofireImplementations.swift b/samples/client/petstore/swift6/alamofireLibrary/Sources/PetstoreClient/Infrastructure/AlamofireImplementations.swift index bf1456bc4621..745b4af956d1 100644 --- a/samples/client/petstore/swift6/alamofireLibrary/Sources/PetstoreClient/Infrastructure/AlamofireImplementations.swift +++ b/samples/client/petstore/swift6/alamofireLibrary/Sources/PetstoreClient/Infrastructure/AlamofireImplementations.swift @@ -342,6 +342,11 @@ open class AlamofireDecodableRequestBuilder: AlamofireR throw DownloadException.responseDataMissing } + guard let httpResponse = dataResponse.response else { + completion(.failure(ErrorResponse.error(-2, dataResponse.data, nil, DecodableRequestBuilderError.nilHTTPResponse))) + return + } + guard let request = request.request else { throw DownloadException.requestMissing } @@ -353,7 +358,7 @@ open class AlamofireDecodableRequestBuilder: AlamofireR var requestPath = try self.getPath(from: requestURL) - if let headerFileName = self.getFileName(fromContentDisposition: dataResponse.response?.allHeaderFields["Content-Disposition"] as? String) { + if let headerFileName = self.getFileName(fromContentDisposition: httpResponse.allHeaderFields["Content-Disposition"] as? String) { requestPath = requestPath.appending("/\(headerFileName)") } else { requestPath = requestPath.appending("/tmp.PetstoreClient.\(UUID().uuidString)") @@ -365,11 +370,7 @@ open class AlamofireDecodableRequestBuilder: AlamofireR try fileManager.createDirectory(atPath: directoryPath, withIntermediateDirectories: true, attributes: nil) try data.write(to: filePath, options: .atomic) - if let httpResponse = dataResponse.response { - completion(.success(Response(response: httpResponse, body: filePath as! T, bodyData: data))) - } else { - completion(.failure(ErrorResponse.error(-2, dataResponse.data, nil, DecodableRequestBuilderError.nilHTTPResponse))) - } + completion(.success(Response(response: httpResponse, body: filePath as! T, bodyData: data))) } catch let requestParserError as DownloadException { completion(.failure(ErrorResponse.error(400, dataResponse.data, dataResponse.response, requestParserError))) diff --git a/samples/client/petstore/swift6/apiNonStaticMethod/Sources/PetstoreClient/Infrastructure/AlamofireImplementations.swift b/samples/client/petstore/swift6/apiNonStaticMethod/Sources/PetstoreClient/Infrastructure/AlamofireImplementations.swift index bf1456bc4621..745b4af956d1 100644 --- a/samples/client/petstore/swift6/apiNonStaticMethod/Sources/PetstoreClient/Infrastructure/AlamofireImplementations.swift +++ b/samples/client/petstore/swift6/apiNonStaticMethod/Sources/PetstoreClient/Infrastructure/AlamofireImplementations.swift @@ -342,6 +342,11 @@ open class AlamofireDecodableRequestBuilder: AlamofireR throw DownloadException.responseDataMissing } + guard let httpResponse = dataResponse.response else { + completion(.failure(ErrorResponse.error(-2, dataResponse.data, nil, DecodableRequestBuilderError.nilHTTPResponse))) + return + } + guard let request = request.request else { throw DownloadException.requestMissing } @@ -353,7 +358,7 @@ open class AlamofireDecodableRequestBuilder: AlamofireR var requestPath = try self.getPath(from: requestURL) - if let headerFileName = self.getFileName(fromContentDisposition: dataResponse.response?.allHeaderFields["Content-Disposition"] as? String) { + if let headerFileName = self.getFileName(fromContentDisposition: httpResponse.allHeaderFields["Content-Disposition"] as? String) { requestPath = requestPath.appending("/\(headerFileName)") } else { requestPath = requestPath.appending("/tmp.PetstoreClient.\(UUID().uuidString)") @@ -365,11 +370,7 @@ open class AlamofireDecodableRequestBuilder: AlamofireR try fileManager.createDirectory(atPath: directoryPath, withIntermediateDirectories: true, attributes: nil) try data.write(to: filePath, options: .atomic) - if let httpResponse = dataResponse.response { - completion(.success(Response(response: httpResponse, body: filePath as! T, bodyData: data))) - } else { - completion(.failure(ErrorResponse.error(-2, dataResponse.data, nil, DecodableRequestBuilderError.nilHTTPResponse))) - } + completion(.success(Response(response: httpResponse, body: filePath as! T, bodyData: data))) } catch let requestParserError as DownloadException { completion(.failure(ErrorResponse.error(400, dataResponse.data, dataResponse.response, requestParserError))) From 8e1892c579682baaaaf2b81553000bf1d62fdd60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20Rusi=C5=88=C3=A1k?= <1114245+spigo@users.noreply.github.com> Date: Thu, 8 Oct 2026 15:32:19 +0200 Subject: [PATCH 3/4] [swift6][alamofire] Check the download response before its data A download without an HTTP response now reports nilHTTPResponse (-2) instead of responseDataMissing (400). --- .../libraries/alamofire/AlamofireImplementations.mustache | 8 ++++---- .../Infrastructure/AlamofireImplementations.swift | 8 ++++---- .../Infrastructure/AlamofireImplementations.swift | 8 ++++---- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/modules/openapi-generator/src/main/resources/swift6/libraries/alamofire/AlamofireImplementations.mustache b/modules/openapi-generator/src/main/resources/swift6/libraries/alamofire/AlamofireImplementations.mustache index 660d2336b6a5..804adc3fcb87 100644 --- a/modules/openapi-generator/src/main/resources/swift6/libraries/alamofire/AlamofireImplementations.mustache +++ b/modules/openapi-generator/src/main/resources/swift6/libraries/alamofire/AlamofireImplementations.mustache @@ -338,15 +338,15 @@ fileprivate class AlamofireRequestBuilderConfiguration: @unchecked Sendable { throw DownloadException.responseFailed } - guard let data = dataResponse.data else { - throw DownloadException.responseDataMissing - } - guard let httpResponse = dataResponse.response else { completion(.failure(ErrorResponse.error(-2, dataResponse.data, nil, DecodableRequestBuilderError.nilHTTPResponse))) return } + guard let data = dataResponse.data else { + throw DownloadException.responseDataMissing + } + guard let request = request.request else { throw DownloadException.requestMissing } diff --git a/samples/client/petstore/swift6/alamofireLibrary/Sources/PetstoreClient/Infrastructure/AlamofireImplementations.swift b/samples/client/petstore/swift6/alamofireLibrary/Sources/PetstoreClient/Infrastructure/AlamofireImplementations.swift index 745b4af956d1..e5808af67fc4 100644 --- a/samples/client/petstore/swift6/alamofireLibrary/Sources/PetstoreClient/Infrastructure/AlamofireImplementations.swift +++ b/samples/client/petstore/swift6/alamofireLibrary/Sources/PetstoreClient/Infrastructure/AlamofireImplementations.swift @@ -338,15 +338,15 @@ open class AlamofireDecodableRequestBuilder: AlamofireR throw DownloadException.responseFailed } - guard let data = dataResponse.data else { - throw DownloadException.responseDataMissing - } - guard let httpResponse = dataResponse.response else { completion(.failure(ErrorResponse.error(-2, dataResponse.data, nil, DecodableRequestBuilderError.nilHTTPResponse))) return } + guard let data = dataResponse.data else { + throw DownloadException.responseDataMissing + } + guard let request = request.request else { throw DownloadException.requestMissing } diff --git a/samples/client/petstore/swift6/apiNonStaticMethod/Sources/PetstoreClient/Infrastructure/AlamofireImplementations.swift b/samples/client/petstore/swift6/apiNonStaticMethod/Sources/PetstoreClient/Infrastructure/AlamofireImplementations.swift index 745b4af956d1..e5808af67fc4 100644 --- a/samples/client/petstore/swift6/apiNonStaticMethod/Sources/PetstoreClient/Infrastructure/AlamofireImplementations.swift +++ b/samples/client/petstore/swift6/apiNonStaticMethod/Sources/PetstoreClient/Infrastructure/AlamofireImplementations.swift @@ -338,15 +338,15 @@ open class AlamofireDecodableRequestBuilder: AlamofireR throw DownloadException.responseFailed } - guard let data = dataResponse.data else { - throw DownloadException.responseDataMissing - } - guard let httpResponse = dataResponse.response else { completion(.failure(ErrorResponse.error(-2, dataResponse.data, nil, DecodableRequestBuilderError.nilHTTPResponse))) return } + guard let data = dataResponse.data else { + throw DownloadException.responseDataMissing + } + guard let request = request.request else { throw DownloadException.requestMissing } From 59126b63e36df6ede83a468db717dd8e502e5cf7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20Rusi=C5=88=C3=A1k?= <1114245+spigo@users.noreply.github.com> Date: Fri, 9 Oct 2026 11:46:22 +0200 Subject: [PATCH 4/4] [swift6][alamofire] Fail on unsupported multipart values while building the form Build the MultipartFormData up front instead of in Alamofire's non-throwing closure, so an unsupported value fails the request right where it is found (RequestBuilderError.unsupportedParameterValue), as the urlsession library's encoder does, instead of being skipped by a default case. This replaces the separate pre-check. --- .../AlamofireImplementations.mustache | 61 +++++++------------ .../AlamofireImplementations.swift | 61 +++++++------------ .../AlamofireImplementations.swift | 61 +++++++------------ 3 files changed, 66 insertions(+), 117 deletions(-) diff --git a/modules/openapi-generator/src/main/resources/swift6/libraries/alamofire/AlamofireImplementations.mustache b/modules/openapi-generator/src/main/resources/swift6/libraries/alamofire/AlamofireImplementations.mustache index ffcaa4ccfba8..22ee41208af5 100644 --- a/modules/openapi-generator/src/main/resources/swift6/libraries/alamofire/AlamofireImplementations.mustache +++ b/modules/openapi-generator/src/main/resources/swift6/libraries/alamofire/AlamofireImplementations.mustache @@ -112,34 +112,31 @@ fileprivate class AlamofireRequestBuilderConfiguration: @unchecked Sendable { } else if contentType.hasPrefix("multipart/form-data") { encoding = nil - if let key = Self.firstUnsupportedMultipartKey(in: self.parameters) { - return failBeforeSending(.unsupportedParameterValue(key: key), managerId: managerId, completion: completion) - } - - let upload = manager.upload(multipartFormData: { mpForm in - for (k, v) in self.parameters ?? [:] { - for v in (v as? Array ?? [v]) { - switch v { - case let fileURL as URL: - if let mimeType = self.contentTypeForFormPart(fileURL: fileURL) { - mpForm.append(fileURL, withName: k, fileName: fileURL.lastPathComponent, mimeType: mimeType) - } else { - mpForm.append(fileURL, withName: k) - } - case let string as String: - mpForm.append(string.data(using: String.Encoding.utf8)!, withName: k) - case let number as NSNumber: - mpForm.append(number.stringValue.data(using: String.Encoding.utf8)!, withName: k) - case let data as Data: - mpForm.append(data, withName: k, fileName: k, mimeType: "application/octet-stream") - case let uuid as UUID: - mpForm.append(uuid.uuidString.data(using: String.Encoding.utf8)!, withName: k) - default: - break + let mpForm = MultipartFormData() + for (k, v) in self.parameters ?? [:] { + for v in (v as? Array ?? [v]) { + switch v { + case let fileURL as URL: + if let mimeType = self.contentTypeForFormPart(fileURL: fileURL) { + mpForm.append(fileURL, withName: k, fileName: fileURL.lastPathComponent, mimeType: mimeType) + } else { + mpForm.append(fileURL, withName: k) } + case let string as String: + mpForm.append(string.data(using: String.Encoding.utf8)!, withName: k) + case let number as NSNumber: + mpForm.append(number.stringValue.data(using: String.Encoding.utf8)!, withName: k) + case let data as Data: + mpForm.append(data, withName: k, fileName: k, mimeType: "application/octet-stream") + case let uuid as UUID: + mpForm.append(uuid.uuidString.data(using: String.Encoding.utf8)!, withName: k) + default: + return failBeforeSending(.unsupportedParameterValue(key: k), managerId: managerId, completion: completion) } } - }, to: URLString, method: xMethod, headers: nil) + } + + let upload = manager.upload(multipartFormData: mpForm, to: URLString, method: xMethod, headers: nil) .uploadProgress { progress in if let onProgressReady = self.onProgressReady { onProgressReady(progress) @@ -219,20 +216,6 @@ fileprivate class AlamofireRequestBuilderConfiguration: @unchecked Sendable { return requestTask } - fileprivate static func firstUnsupportedMultipartKey(in parameters: [String: any Sendable]?) -> String? { - for (key, value) in parameters ?? [:] { - for element in (value as? [Any] ?? [value]) { - switch element { - case is URL, is String, is NSNumber, is Data, is UUID: - continue - default: - return key - } - } - } - return nil - } - {{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}open{{/nonPublicApi}} func buildHeaders() -> [String: String] { var httpHeaders = Alamofire.HTTPHeaders.default.dictionary for (key, value) in headers { diff --git a/samples/client/petstore/swift6/alamofireLibrary/Sources/PetstoreClient/Infrastructure/AlamofireImplementations.swift b/samples/client/petstore/swift6/alamofireLibrary/Sources/PetstoreClient/Infrastructure/AlamofireImplementations.swift index 14ee07c591c8..6ab87a820ddd 100644 --- a/samples/client/petstore/swift6/alamofireLibrary/Sources/PetstoreClient/Infrastructure/AlamofireImplementations.swift +++ b/samples/client/petstore/swift6/alamofireLibrary/Sources/PetstoreClient/Infrastructure/AlamofireImplementations.swift @@ -112,34 +112,31 @@ open class AlamofireRequestBuilder: RequestBuilder, @unchecked S } else if contentType.hasPrefix("multipart/form-data") { encoding = nil - if let key = Self.firstUnsupportedMultipartKey(in: self.parameters) { - return failBeforeSending(.unsupportedParameterValue(key: key), managerId: managerId, completion: completion) - } - - let upload = manager.upload(multipartFormData: { mpForm in - for (k, v) in self.parameters ?? [:] { - for v in (v as? Array ?? [v]) { - switch v { - case let fileURL as URL: - if let mimeType = self.contentTypeForFormPart(fileURL: fileURL) { - mpForm.append(fileURL, withName: k, fileName: fileURL.lastPathComponent, mimeType: mimeType) - } else { - mpForm.append(fileURL, withName: k) - } - case let string as String: - mpForm.append(string.data(using: String.Encoding.utf8)!, withName: k) - case let number as NSNumber: - mpForm.append(number.stringValue.data(using: String.Encoding.utf8)!, withName: k) - case let data as Data: - mpForm.append(data, withName: k, fileName: k, mimeType: "application/octet-stream") - case let uuid as UUID: - mpForm.append(uuid.uuidString.data(using: String.Encoding.utf8)!, withName: k) - default: - break + let mpForm = MultipartFormData() + for (k, v) in self.parameters ?? [:] { + for v in (v as? Array ?? [v]) { + switch v { + case let fileURL as URL: + if let mimeType = self.contentTypeForFormPart(fileURL: fileURL) { + mpForm.append(fileURL, withName: k, fileName: fileURL.lastPathComponent, mimeType: mimeType) + } else { + mpForm.append(fileURL, withName: k) } + case let string as String: + mpForm.append(string.data(using: String.Encoding.utf8)!, withName: k) + case let number as NSNumber: + mpForm.append(number.stringValue.data(using: String.Encoding.utf8)!, withName: k) + case let data as Data: + mpForm.append(data, withName: k, fileName: k, mimeType: "application/octet-stream") + case let uuid as UUID: + mpForm.append(uuid.uuidString.data(using: String.Encoding.utf8)!, withName: k) + default: + return failBeforeSending(.unsupportedParameterValue(key: k), managerId: managerId, completion: completion) } } - }, to: URLString, method: xMethod, headers: nil) + } + + let upload = manager.upload(multipartFormData: mpForm, to: URLString, method: xMethod, headers: nil) .uploadProgress { progress in if let onProgressReady = self.onProgressReady { onProgressReady(progress) @@ -219,20 +216,6 @@ open class AlamofireRequestBuilder: RequestBuilder, @unchecked S return requestTask } - fileprivate static func firstUnsupportedMultipartKey(in parameters: [String: any Sendable]?) -> String? { - for (key, value) in parameters ?? [:] { - for element in (value as? [Any] ?? [value]) { - switch element { - case is URL, is String, is NSNumber, is Data, is UUID: - continue - default: - return key - } - } - } - return nil - } - open func buildHeaders() -> [String: String] { var httpHeaders = Alamofire.HTTPHeaders.default.dictionary for (key, value) in headers { diff --git a/samples/client/petstore/swift6/apiNonStaticMethod/Sources/PetstoreClient/Infrastructure/AlamofireImplementations.swift b/samples/client/petstore/swift6/apiNonStaticMethod/Sources/PetstoreClient/Infrastructure/AlamofireImplementations.swift index 14ee07c591c8..6ab87a820ddd 100644 --- a/samples/client/petstore/swift6/apiNonStaticMethod/Sources/PetstoreClient/Infrastructure/AlamofireImplementations.swift +++ b/samples/client/petstore/swift6/apiNonStaticMethod/Sources/PetstoreClient/Infrastructure/AlamofireImplementations.swift @@ -112,34 +112,31 @@ open class AlamofireRequestBuilder: RequestBuilder, @unchecked S } else if contentType.hasPrefix("multipart/form-data") { encoding = nil - if let key = Self.firstUnsupportedMultipartKey(in: self.parameters) { - return failBeforeSending(.unsupportedParameterValue(key: key), managerId: managerId, completion: completion) - } - - let upload = manager.upload(multipartFormData: { mpForm in - for (k, v) in self.parameters ?? [:] { - for v in (v as? Array ?? [v]) { - switch v { - case let fileURL as URL: - if let mimeType = self.contentTypeForFormPart(fileURL: fileURL) { - mpForm.append(fileURL, withName: k, fileName: fileURL.lastPathComponent, mimeType: mimeType) - } else { - mpForm.append(fileURL, withName: k) - } - case let string as String: - mpForm.append(string.data(using: String.Encoding.utf8)!, withName: k) - case let number as NSNumber: - mpForm.append(number.stringValue.data(using: String.Encoding.utf8)!, withName: k) - case let data as Data: - mpForm.append(data, withName: k, fileName: k, mimeType: "application/octet-stream") - case let uuid as UUID: - mpForm.append(uuid.uuidString.data(using: String.Encoding.utf8)!, withName: k) - default: - break + let mpForm = MultipartFormData() + for (k, v) in self.parameters ?? [:] { + for v in (v as? Array ?? [v]) { + switch v { + case let fileURL as URL: + if let mimeType = self.contentTypeForFormPart(fileURL: fileURL) { + mpForm.append(fileURL, withName: k, fileName: fileURL.lastPathComponent, mimeType: mimeType) + } else { + mpForm.append(fileURL, withName: k) } + case let string as String: + mpForm.append(string.data(using: String.Encoding.utf8)!, withName: k) + case let number as NSNumber: + mpForm.append(number.stringValue.data(using: String.Encoding.utf8)!, withName: k) + case let data as Data: + mpForm.append(data, withName: k, fileName: k, mimeType: "application/octet-stream") + case let uuid as UUID: + mpForm.append(uuid.uuidString.data(using: String.Encoding.utf8)!, withName: k) + default: + return failBeforeSending(.unsupportedParameterValue(key: k), managerId: managerId, completion: completion) } } - }, to: URLString, method: xMethod, headers: nil) + } + + let upload = manager.upload(multipartFormData: mpForm, to: URLString, method: xMethod, headers: nil) .uploadProgress { progress in if let onProgressReady = self.onProgressReady { onProgressReady(progress) @@ -219,20 +216,6 @@ open class AlamofireRequestBuilder: RequestBuilder, @unchecked S return requestTask } - fileprivate static func firstUnsupportedMultipartKey(in parameters: [String: any Sendable]?) -> String? { - for (key, value) in parameters ?? [:] { - for element in (value as? [Any] ?? [value]) { - switch element { - case is URL, is String, is NSNumber, is Data, is UUID: - continue - default: - return key - } - } - } - return nil - } - open func buildHeaders() -> [String: String] { var httpHeaders = Alamofire.HTTPHeaders.default.dictionary for (key, value) in headers {