Reputation: 99
I have this ugly construction of returning generic type as solid model, does anyone have ideas on refactoring to be more declarative?
extension NetworkingService {
func login(email: String, password: String) -> AnyPublisher<UserModel, APIError> {
func convertToModel() -> AnyPublisher<ResponseObject<UserResponse>, APIError> {
return request(with: AuthRequests.login(email: email, password: password)).eraseToAnyPublisher()
}
return convertToModel().map { UserModel(with: $0.data!) }.eraseToAnyPublisher()
}
func request<T>(with endpoint: Endpoint) -> AnyPublisher<T, APIError> where T : Decodable {
//... returning any publisher with Decodable
}
}
Upvotes: 0
Views: 69
Reputation: 33979
Your request<T>(with:)
function only uses the T
in the return. Although this is doable, it means that the calling code must call out what T
is which is what is making your calling code "ugly".
The impression I get from what you posted is that the only thing your Endpoint
type does is create a URLRequest. If it also defined the shape of the expected return data, then the entire construct would be cleaner.
I suggesting making your Endpoint
type look like this:
public struct Endpoint<Response> {
public let request: URLRequest
public let response: (Data) throws -> Response
public init(request: URLRequest, response: @escaping (Data) throws -> Response) {
self.request = request
self.response = response
}
}
Then, with suitable updates elsewhere, you could do something like this:
extension NetworkingService {
func login(email: String, password: String) -> AnyPublisher<UserModel, APIError> {
request(with: AuthRequests.login(email: email, password: password))
.map { $0.response.model }
.eraseToAnyPublisher()
}
func request<T>(with endpoint: Endpoint<T>) -> AnyPublisher<T, APIError> where T: Decodable {
//... returning any publisher with Decodable
}
}
Upvotes: 1