0

I want to use Alamofire to query my backend, encode the response using Alamofire's built-in Codable parsing and then publish an extract from the resulting Struct to be consumed by the caller of my API class. Say I have some JSON data from my backend (simplified, but shows the structure):

{
    "total": 123,
    "results": [
        {"foo" : "bar"},
        {"foo" : "baz"}
    ]
}

and the associated Codable Structs

struct MyServerData: Codable {
    let total: Int
    let results: [Result]
}

struct Result: Codable {
    let foo: String
}

I can get, parse, publish, and subscribe all fine with the following:

func myAPI() -> DataResponsePublisher<MyServerData> {
    return AF.request("https://backend/path")
        .validate()
        .publishDecodable(type: MyServerData.self)
}

myAPI()
    .sink { response in /* Do stuff, e.g. update @State */ }

What I'd like to do is to publish just the [Result] array. What's the correct approach to this? Should I use .responseDecodable() and create a new publisher (somehow - .map()?) that returns a [Result].publisher?

While I think I understand the reactive/stream based principles my Combine-fu is still weak and I don't have a clear handle on the transformation of one publisher into another (I'm guessing?)

Thanks in advance!

Robin Macharg
  • 1,468
  • 14
  • 22

1 Answers1

1

In addition to using Combine API like map, Alamofire offers two publishers on DataResponsePublisher itself.

.result() extracts the Result from the DataResponse and creates an AnyPublisher<Result<Value, AFError>, Never>.

.value() extracts the Value from the DataResponse and creates a failable publisher, AnyPublisher<Value, AFError>.

So depending on what kind of error handling you want, this could be as simple as:

...
  .publishDecodable(...)
  .value()
  .map(\.results)
Jon Shier
  • 12,200
  • 3
  • 35
  • 37
  • I'd so nearly got there; you helped me over the line, thanks! Having had a bit more of a play the difference between `value()` and `result()` seems to be that `.result()` allows you to handle errors at either end of the pub-sub while `value()` leans heavily towards handling them as part of the pub chain. Might be wrong, but I've managed to climb over the current hurdle with the help of the above, a success/failure switch and a trailing `.eraseToAnyPublisher()`. – Robin Macharg May 26 '22 at 18:49
  • Yeah, it just depends on which style you like. I usually go for `Result`s as I don't like handling errors in streams. – Jon Shier May 26 '22 at 21:37