Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Swift6] better configuration #19732

Merged
merged 22 commits into from
Oct 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 59 additions & 23 deletions modules/openapi-generator/src/main/resources/swift6/APIs.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -10,55 +10,91 @@ import FoundationNetworking
#endif{{#useVapor}}
import Vapor{{/useVapor}}{{#useAlamofire}}
import Alamofire{{/useAlamofire}}
{{#swiftUseApiNamespace}}

{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} enum {{projectName}}API {}
{{/swiftUseApiNamespace}}

{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}open{{/nonPublicApi}} class OpenAPIClient: @unchecked Sendable {
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} var basePath: String{{#useVapor}}
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} var customHeaders: HTTPHeaders
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} var apiClient: Vapor.Client?
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} var apiWrapper: (inout Vapor.ClientRequest) throws -> ()
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} var contentConfiguration{{/useVapor}}{{^useVapor}}
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} var customHeaders: [String: String]
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} var credential: URLCredential?
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} var requestBuilderFactory: RequestBuilderFactory
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} var apiResponseQueue: DispatchQueue
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} var codableHelper: CodableHelper

{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}open{{/nonPublicApi}} class {{projectName}}API: @unchecked Sendable {
private init() {}
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} static let shared = {{projectName}}API()

{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} var basePath = "{{{basePath}}}"{{#useVapor}}
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} var customHeaders: HTTPHeaders = [:]
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} var apiClient: Vapor.Client? = nil
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} var apiWrapper: (inout Vapor.ClientRequest) throws -> () = { _ in }
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} var contentConfiguration = ContentConfiguration.default(){{/useVapor}}{{^useVapor}}{{/useVapor}}{{^useVapor}}
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} var customHeaders: [String: String] = [:]
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} var credential: URLCredential?{{#useAlamofire}}
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} var requestBuilderFactory: RequestBuilderFactory = AlamofireRequestBuilderFactory(){{/useAlamofire}}{{#useURLSession}}
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} var requestBuilderFactory: RequestBuilderFactory = URLSessionRequestBuilderFactory(){{/useURLSession}}
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} var apiResponseQueue: DispatchQueue = .main
/// Configures the range of HTTP status codes that will result in a successful response
///
/// If a HTTP status code is outside of this range the response will be interpreted as failed.
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} var successfulStatusCodeRange: Range = 200..<300{{/useVapor}}{{#useAlamofire}}
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} var successfulStatusCodeRange: Range<Int>{{#useAlamofire}}
/// ResponseSerializer that will be used by the generator for `Data` responses
///
/// If unchanged, Alamofires default `DataResponseSerializer` will be used.
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} var dataResponseSerializer: AnyResponseSerializer<Data> = AnyResponseSerializer(DataResponseSerializer())
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} var dataResponseSerializer: AnyResponseSerializer<Data>
/// ResponseSerializer that will be used by the generator for `String` responses
///
/// If unchanged, Alamofires default `StringResponseSerializer` will be used.
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} var stringResponseSerializer: AnyResponseSerializer<String> = AnyResponseSerializer(StringResponseSerializer()){{/useAlamofire}}
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} var stringResponseSerializer: AnyResponseSerializer<String>{{/useAlamofire}}{{/useVapor}}

{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} init(
basePath: String = "{{{basePath}}}",{{#useVapor}}
customHeaders: HTTPHeaders = [:],
apiClient: Vapor.Client? = nil,
apiWrapper: (inout Vapor.ClientRequest) throws -> () = { _ in },
contentConfiguration = ContentConfiguration.default(){{/useVapor}}{{^useVapor}}
customHeaders: [String: String] = [:],
credential: URLCredential? = nil,
requestBuilderFactory: RequestBuilderFactory = {{#useAlamofire}}AlamofireRequestBuilderFactory(){{/useAlamofire}}{{#useURLSession}}URLSessionRequestBuilderFactory(){{/useURLSession}},
apiResponseQueue: DispatchQueue = .main,
codableHelper: CodableHelper = CodableHelper(),
successfulStatusCodeRange: Range<Int> = 200..<300{{#useAlamofire}},
dataResponseSerializer: AnyResponseSerializer<Data> = AnyResponseSerializer(DataResponseSerializer()),
stringResponseSerializer: AnyResponseSerializer<String> = AnyResponseSerializer(StringResponseSerializer()){{/useAlamofire}}{{/useVapor}}
) {
self.basePath = basePath{{#useVapor}}
customHeaders = customHeaders
apiClient = apiClient
apiWrapper = apiWrapper
contentConfiguration = contentConfiguration{{/useVapor}}{{^useVapor}}
self.customHeaders = customHeaders
self.credential = credential
self.requestBuilderFactory = requestBuilderFactory
self.apiResponseQueue = apiResponseQueue
self.codableHelper = codableHelper
self.successfulStatusCodeRange = successfulStatusCodeRange{{#useAlamofire}}
self.dataResponseSerializer = dataResponseSerializer
self.stringResponseSerializer = stringResponseSerializer{{/useAlamofire}}{{/useVapor}}
}

{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} static let shared = OpenAPIClient()
}{{^useVapor}}

{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}open{{/nonPublicApi}} class RequestBuilder<T>: @unchecked Sendable {
var credential: URLCredential?
var headers: [String: String]
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} var credential: URLCredential?
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} var headers: [String: String]
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} let parameters: [String: Any]?
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} let method: String
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} let URLString: String
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} let requestTask: RequestTask = RequestTask()
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} let requiresAuthentication: Bool
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} let openAPIClient: OpenAPIClient

/// Optional block to obtain a reference to the request's progress instance when available.
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} var onProgressReady: ((Progress) -> Void)?

required {{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} init(method: String, URLString: String, parameters: [String: Any]?, headers: [String: String] = [:], requiresAuthentication: Bool) {
required {{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} init(method: String, URLString: String, parameters: [String: Any]?, headers: [String: String] = [:], requiresAuthentication: Bool, openAPIClient: OpenAPIClient = OpenAPIClient.shared) {
self.method = method
self.URLString = URLString
self.parameters = parameters
self.headers = headers
self.requiresAuthentication = requiresAuthentication
self.openAPIClient = openAPIClient

addHeaders({{projectName}}API.shared.customHeaders)
addHeaders(openAPIClient.customHeaders)
}

{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}open{{/nonPublicApi}} func addHeaders(_ aHeaders: [String: String]) {
Expand All @@ -68,7 +104,7 @@ import Alamofire{{/useAlamofire}}
}

@discardableResult
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}open{{/nonPublicApi}} func execute(_ apiResponseQueue: DispatchQueue = {{projectName}}API.shared.apiResponseQueue, _ completion: @Sendable @escaping (_ result: Swift.Result<Response<T>, ErrorResponse>) -> Void) -> RequestTask {
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}open{{/nonPublicApi}} func execute(completion: @Sendable @escaping (_ result: Swift.Result<Response<T>, ErrorResponse>) -> Void) -> RequestTask {
return requestTask
}

Expand Down Expand Up @@ -117,7 +153,7 @@ import Alamofire{{/useAlamofire}}
}

{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}open{{/nonPublicApi}} func addCredential() -> Self {
credential = {{projectName}}API.shared.credential
credential = openAPIClient.credential
return self
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@
import Foundation

{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}open{{/nonPublicApi}} class CodableHelper: @unchecked Sendable {
private init() {}
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} static let shared = CodableHelper()
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} init() {}

private var customDateFormatter: DateFormatter?
private var defaultDateFormatter: DateFormatter = OpenISO8601DateFormatter()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,97 +15,97 @@ import AnyCodable
import Vapor{{/useVapor}}{{^useVapor}}

extension Bool: JSONEncodable {
func encodeToJSON() -> Any { self }
func encodeToJSON(codableHelper: CodableHelper) -> Any { self }
}

extension Float: JSONEncodable {
func encodeToJSON() -> Any { self }
func encodeToJSON(codableHelper: CodableHelper) -> Any { self }
}

extension Int: JSONEncodable {
func encodeToJSON() -> Any { self }
func encodeToJSON(codableHelper: CodableHelper) -> Any { self }
}

extension Int32: JSONEncodable {
func encodeToJSON() -> Any { self }
func encodeToJSON(codableHelper: CodableHelper) -> Any { self }
}

extension Int64: JSONEncodable {
func encodeToJSON() -> Any { self }
func encodeToJSON(codableHelper: CodableHelper) -> Any { self }
}

extension Double: JSONEncodable {
func encodeToJSON() -> Any { self }
func encodeToJSON(codableHelper: CodableHelper) -> Any { self }
}

extension Decimal: JSONEncodable {
func encodeToJSON() -> Any { self }
func encodeToJSON(codableHelper: CodableHelper) -> Any { self }
}

extension String: JSONEncodable {
func encodeToJSON() -> Any { self }
func encodeToJSON(codableHelper: CodableHelper) -> Any { self }
}

extension URL: JSONEncodable {
func encodeToJSON() -> Any { self }
func encodeToJSON(codableHelper: CodableHelper) -> Any { self }
}

extension UUID: JSONEncodable {
func encodeToJSON() -> Any { self }
func encodeToJSON(codableHelper: CodableHelper) -> Any { self }
}

extension RawRepresentable where RawValue: JSONEncodable {
func encodeToJSON() -> Any { return self.rawValue }
func encodeToJSON(codableHelper: CodableHelper) -> Any { return self.rawValue }
}

private func encodeIfPossible<T>(_ object: T) -> Any {
private func encodeIfPossible<T>(_ object: T, codableHelper: CodableHelper) -> Any {
if let encodableObject = object as? JSONEncodable {
return encodableObject.encodeToJSON()
return encodableObject.encodeToJSON(codableHelper: codableHelper)
} else {
return object
}
}

extension Array: JSONEncodable {
func encodeToJSON() -> Any {
return self.map(encodeIfPossible)
func encodeToJSON(codableHelper: CodableHelper) -> Any {
return self.map { encodeIfPossible($0, codableHelper: codableHelper) }
}
}

extension Set: JSONEncodable {
func encodeToJSON() -> Any {
return Array(self).encodeToJSON()
func encodeToJSON(codableHelper: CodableHelper) -> Any {
return Array(self).encodeToJSON(codableHelper: codableHelper)
}
}

extension Dictionary: JSONEncodable {
func encodeToJSON() -> Any {
func encodeToJSON(codableHelper: CodableHelper) -> Any {
var dictionary = [AnyHashable: Any]()
for (key, value) in self {
dictionary[key] = encodeIfPossible(value)
dictionary[key] = encodeIfPossible(value, codableHelper: codableHelper)
}
return dictionary
}
}

extension Data: JSONEncodable {
func encodeToJSON() -> Any {
func encodeToJSON(codableHelper: CodableHelper) -> Any {
return self.base64EncodedString(options: Data.Base64EncodingOptions())
}
}

extension Date: JSONEncodable {
func encodeToJSON() -> Any {
return CodableHelper.shared.dateFormatter.string(from: self)
func encodeToJSON(codableHelper: CodableHelper) -> Any {
return codableHelper.dateFormatter.string(from: self)
}
}

extension JSONEncodable where Self: Encodable {
func encodeToJSON() -> Any {
guard let data = try? CodableHelper.shared.jsonEncoder.encode(self) else {
func encodeToJSON(codableHelper: CodableHelper) -> Any {
guard let data = try? codableHelper.jsonEncoder.encode(self) else {
fatalError("Could not encode to json: \(self)")
}
return data.encodeToJSON()
return data.encodeToJSON(codableHelper: codableHelper)
}
}{{/useVapor}}{{#generateModelAdditionalProperties}}

Expand Down Expand Up @@ -229,13 +229,7 @@ extension KeyedDecodingContainerProtocol {
return decimalValue
}

}{{/generateModelAdditionalProperties}}{{^useVapor}}

extension HTTPURLResponse {
var isStatusCodeSuccessful: Bool {
return {{projectName}}API.shared.successfulStatusCodeRange.contains(statusCode)
}
}{{/useVapor}}{{#usePromiseKit}}
}{{/generateModelAdditionalProperties}}{{#usePromiseKit}}

extension RequestBuilder {
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} func execute() -> Promise<Response<T>> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ import Foundation

{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}open{{/nonPublicApi}} class JSONEncodingHelper {

{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}open{{/nonPublicApi}} class func encodingParameters<T: Encodable>(forEncodableObject encodableObj: T?) -> [String: Any]? {
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}open{{/nonPublicApi}} class func encodingParameters<T: Encodable>(forEncodableObject encodableObj: T?, codableHelper: CodableHelper) -> [String: Any]? {
var params: [String: Any]?

// Encode the Encodable object
if let encodableObj = encodableObj {
let encodeResult = CodableHelper.shared.encode(encodableObj)
let encodeResult = codableHelper.encode(encodableObj)
do {
let data = try encodeResult.get()
params = JSONDataEncoding.encodingParameters(jsonData: data)
Expand All @@ -26,7 +26,7 @@ import Foundation
return params
}

{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}open{{/nonPublicApi}} class func encodingParameters(forEncodableObject encodableObj: Any?) -> [String: Any]? {
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}open{{/nonPublicApi}} class func encodingParameters(forEncodableObject encodableObj: Any?, codableHelper: CodableHelper) -> [String: Any]? {
var params: [String: Any]?

if let encodableObj = encodableObj {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import FoundationNetworking
import Alamofire{{/useAlamofire}}

protocol JSONEncodable {
func encodeToJSON() -> Any
func encodeToJSON(codableHelper: CodableHelper) -> Any
}

/// An enum where the last case value can be used as a default catch-all.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ import Foundation
}

extension OpenAPIDateWithoutTime: JSONEncodable {
func encodeToJSON() -> Any {
func encodeToJSON(codableHelper: CodableHelper) -> Any {
return OpenISO8601DateFormatter.withoutTime.string(from: self.normalizedWrappedDate())
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1 @@
"{{baseName}}": {{#isQueryParam}}(wrappedValue: {{/isQueryParam}}{{paramName}}{{^required}}?{{/required}}.encodeToJSON(){{#isQueryParam}}, isExplode: {{isExplode}}){{/isQueryParam}}
"{{baseName}}": {{#isQueryParam}}(wrappedValue: {{/isQueryParam}}{{paramName}}{{^required}}?{{/required}}.encodeToJSON(codableHelper: openAPIClient.codableHelper){{#isQueryParam}}, isExplode: {{isExplode}}){{/isQueryParam}}
Loading
Loading