Godlike
Godlike

Reputation: 1928

Swift Combine return AnyPublisher<Void, Error> with FlatMap (POST Request)

I started using combine and it's really cool but currently I have no idea how to fix it. I want to make a POST Request using combine so I have to decode Data, create my request, send it and after that return an

AnyPublisher<Void, Error>

Currently my code looks like this:

func postData<T>(withURL urlRequest: URLRequest, object: T) -> AnyPublisher<Void, Error> where T: Encodable {

        return Just(object)
        .encode(encoder: JSONEncoder())
        .mapError {
            let error = self.classifyError($0)
            return error
        }
        .map { data -> URLRequest in
            var request = urlRequest
            //BUILD REQUEST
            return request
        }
        .flatMap { request in
            let dataTaskPublisher: AnyPublisher<URLSession.DataTaskPublisher.Output, URLSession.DataTaskPublisher.Failure> = URLSession.DataTaskPublisher(request: request, session: .shared)

            return dataTaskPublisher
            .tryMap { try self.throwErrorOrContinue(data: $0, basedOnResponse: $1) }
            .decode(type: T.self, decoder: JSONDecoder())
            .mapError { return self.handle(error: $0, from: urlRequest, object: T.self) }
        }
        .eraseToAnyPublisher()
    }

And he tells me:

Cannot convert return expression of type 'AnyPublisher<Publishers.FlatMap<_, Publishers.Map<Publishers.MapError<Publishers.Encode<Just<T>, JSONEncoder>, _>, URLRequest>>.Output, Publishers.FlatMap<_, Publishers.Map<Publishers.MapError<Publishers.Encode<Just<T>, JSONEncoder>, _>, URLRequest>>.Failure>' (aka 'AnyPublisher<_.Output, _>') 
to return type 'AnyPublisher<Void, Error>'

I tried some mapping but it didn't work and I have no idea what he wants from me. Maybe one of you knows the problem? Thanks :)

Upvotes: 1

Views: 10807

Answers (1)

Sweeper
Sweeper

Reputation: 271355

You could always map to Void, which is an empty tuple:

return URLSession.DataTaskPublisher(request: request, session: .shared)
    .tryMap { try self.throwErrorOrContinue(data: $0, basedOnResponse: $1) }
    .decode(type: T.self, decoder: JSONDecoder())
    .mapError { return self.handle(error: $0, from: urlRequest, object: T.self) }
    .map { _ in return () }

Also T should be constrained to Decodable.

But really though, I think postData should return AnyPublisher<T, Error>. What to do with the data got from the server should be decided by the caller of postData. Therefore, you should change the return type of postData instead. For example, if the caller wants to ignore the result, it could do:

Publishers.IgnoreOutput(upstream: postData(...))

This creates a Publisher with Never, rather than Void, as its Output. The publisher will only produce errors.

Upvotes: 2

Related Questions