Open VyrCossont opened 5 years ago
Hey @VyrCossont I'm wondering what your status is on this
I've got a feature branch here, implemented as a new folder of Stencil templates called SwiftCombine: https://github.com/VyrCossont/SwagGen/tree/swift-combine
Basics are functional; I've got enough working to support a simple Mastodon client, but development has been on hold for the last few months due to other work and life stuff. Can take a look this weekend at what's missing.
On Mon, Dec 9, 2019 at 12:04 Moritz Sternemann notifications@github.com wrote:
Hey @VyrCossont https://github.com/VyrCossont I'm wondering what your status is on this
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/yonaskolb/SwagGen/issues/190?email_source=notifications&email_token=AGH3MYGWKBXIMVLZTSC5HWLQX2QDLA5CNFSM4ILGPTBKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEGKPVRA#issuecomment-563411652, or unsubscribe https://github.com/notifications/unsubscribe-auth/AGH3MYD3GKID5EDGIW3RCOLQX2QDLANCNFSM4ILGPTBA .
If you need Combine support (or any other asynchronous framework), you should just be able to add an extension on APIClient that wraps the existing completion block
I know that I am a bit late, but I implemented something similar to what @yonaskolb mentioned in the above comment.
(The code bellow has some other components not here specified, but simple to assume)
//
import Combine
import Foundation
import SwaggerAPI
extension APIClient {
func request<T: APIResponseValue>(_ request: APIRequest<T>,
behaviours: [RequestBehaviour] = [],
completionQueue: DispatchQueue = DispatchQueue.main) -> Publishers.DataPublisher<T> {
return Publishers.DataPublisher<T>(apiClient: self,
request: request,
behaviours: behaviours,
completionQueue: completionQueue)
}
}
extension Publishers {
struct DataPublisher<T: APIResponseValue>: Publisher {
typealias Output = T.SuccessType
typealias Failure = NSError
private let apiClient: APIClient
private let request: APIRequest<T>
private let behaviours: [RequestBehaviour]
private let completionQueue: DispatchQueue
init(apiClient: APIClient,
request: APIRequest<T>,
behaviours: [RequestBehaviour],
completionQueue: DispatchQueue) {
self.apiClient = apiClient
self.request = request
self.behaviours = behaviours
self.completionQueue = completionQueue
}
func receive<S: Subscriber>(subscriber: S) where
DataPublisher.Failure == S.Failure, DataPublisher.Output == S.Input {
let subscription = DataSubscription(apiClient: self.apiClient,
request: self.request,
behaviours: self.behaviours,
completionQueue: self.completionQueue,
subscriber: subscriber)
subscriber.receive(subscription: subscription)
}
}
}
private extension Publishers {
class DataSubscription<S: Subscriber, T: APIResponseValue>: Subscription where S.Input == T.SuccessType, S.Failure == NSError {
let apiClient: APIClient
let request: APIRequest<T>
let behaviours: [RequestBehaviour]
let completionQueue: DispatchQueue
private var subscriber: S?
init(apiClient: APIClient,
request: APIRequest<T>,
behaviours: [RequestBehaviour] = [],
completionQueue: DispatchQueue = DispatchQueue.main,
subscriber: S) {
self.apiClient = apiClient
self.request = request
self.behaviours = behaviours
self.completionQueue = completionQueue
self.subscriber = subscriber
}
func request(_ demand: Subscribers.Demand) {
self.sendRequest()
}
func cancel() {
subscriber = nil
}
private func sendRequest() {
self.apiClient.makeRequest(request, completionQueue: completionQueue) { [weak self] response in
guard let subscriber = self?.subscriber else { return }
let result = response.result
switch result {
case .failure(let error):
print(error)
let applicationError = error.toNSError(withPrefix: "")
subscriber.receive(completion: Subscribers.Completion.failure(applicationError))
case .success(let response):
if let successResult = response.success {
_ = subscriber.receive(successResult)
return
}
let result = (response.response as? SGErrorsObject) ?? []
let error = NSError.makeError(withStatusCode: response.statusCode, failures: result)
subscriber.receive(completion: Subscribers.Completion.failure(error))
}
}
}
}
}
I've got a feature branch here, implemented as a new folder of Stencil templates called SwiftCombine: https://github.com/VyrCossont/SwagGen/tree/swift-combine Basics are functional; I've got enough working to support a simple Mastodon client, but development has been on hold for the last few months due to other work and life stuff. Can take a look this weekend at what's missing.
Hey @VyrCossont, I was able to get your feature branch up and running pretty easily, thanks for sharing! Besides the request.service.isUpload
, what do you think is missing?
I've started working on SwagGen support for Apple's new Combine reactive programming library over in the
swift-combine
branch of my fork as an alternate template set, since I want it for a SwiftUI project. Using the closure parameters toAPIClient
andRequestBehaviour
as an adapter to Combine, as suggested in the readme, probably won't help here, since Combine has uniform backpressure and cancellation support, and since I'd also like to get rid ofAlamofire
as a dependency.Still working on file upload support since Apple doesn't seem to have Combine-ized data upload tasks yet, but I'll open a PR once this is a little more complete.