I'm new to the Combine
game and am trying to figure out how to generalize a HTTP POST
request.
I created the following APIService
class to extend individual resource services from:
import Foundation
import Combine
class APIService {
let decoder: JSONDecoder
let session: URLSession
init(session: URLSession = URLSession.shared, decoder: JSONDecoder = JSONDecoder()) {
self.decoder = decoder
self.session = session
}
}
// MARK: JSON API
extension APIService {
struct Response<T> {
let response: HTTPURLResponse
let value: T
}
func post<T: Codable>(
payload: T,
url: URL
) -> AnyPublisher<Response<T>, APIError> {
return Just(payload)
.setFailureType(to: APIError.self) // <<< THIS WAS MISSING!
.encode(encoder: JSONEncoder())
.flatMap({ [weak self] payload -> AnyPublisher<Data, Error> in
guard let self = self else {
return Fail(error: .default("Failing to establish self.")).eraseToAnyPublisher()
}
var request = URLRequest(url: url)
request.httpMethod = Methods.post
request.setValue(
Mimetypes.json,
forHTTPHeaderField: Headers.contentType
)
request.httpBody = payload
return self.session
.dataTaskPublisher(
for: request
)
.tryMap { response -> Response<T> in
let value = try self.decoder.decode(T.self, from: response.data)
return Response(
value: value,
response: response.response
)
}
.mapError { error in
return APIError.default(error.localizedDescription)
}
.receive(on: DispatchQueue.main)
.eraseToAnyPublisher()
})
.eraseToAnyPublisher()
}
}
However, this class won't compile with the following error at the post
function.
Type of expression is ambiguous without more context
Being new to Swift in general and Combine in particular, I am unfortunately out of ideas on how to proceed.
Any help is greatly appreciated!
Figured it out myself: Solution
Add a Failure
type to the Just
, so input and output Failure
types to flatMap
are equal. Or put differently: flatMap
cannot convert the Never
failing Just
to a Publisher
with Failure
.
The missing line in my case:
Just(payload)
.setFailureType(to: APIError.self)