Skip to content

Chaining optional JSON GET requests efficiently #1155

Closed

Description

@gsora

Hi,
I'm trying to wrap my head around the promise concept and I'm having some issue when dealing with HTTP GET requests.

I have a function f that calls an HTTP endpoint, decodes some JSON and returns a Swift object after doing some transformations on an intermediate type:

rgp in this case is an object containing an array of objects.

        return firstly {
            URLSession.shared.dataTask(.promise, with: urls.Price(forIDs: gamesIDs, country: nation, lang: nation))
        }.compactMap {
            try self.urls.JSONDataDecoder().decode(RawGamePrice.self, from: $0.data)
        }.compactMap { rgp in
            // does some transformations on rgp and then returns
        }

Now, I need to bolt several other HTTP calls, which should be executed for a subset of rgp components:

                var proms = [Promise<[EuropeGamePrice]>]()

                for (chunk) in idChunks {
                    proms.append(self.prices(list: chunk, nation: "IT"))
                }
            
                when(resolved: proms).done {results in
                    return proms.forEach { dd in
                            dd.value?.forEach { newPrice in
                                g.updateDiscountPrice(gameWith: newPrice.gameID, newPrice: newPrice.salePrice)
                            }
                        }
                } .catch { error in
                    debugPrint("cannot fetch prices, using APIs ones", error)
                }.finally {
                    debugPrint("finished pulling prices")
                }

As far as I understand, compactMap does not permit chaining other promises with then because it doesn't return a Promise itself.

What's the best way to tackle this situation?

I do not know the subset of object to work with before the second compactMap ends.

I tried embedding the when logic in the latter compactMap but since it's all async the wrapping closure returns before the when ends, and to be honest it doesn't look good enough.

Activity

  1. GarthSnyder commented on Jun 22, 2020

    @GarthSnyder
    Collaborator

    As far as I understand, compactMap does not permit chaining other promises with then because it doesn't return a Promise itself.

    Sure it does. All that map and compactMap do is convert Promise<InputType> to Promise<OutputType>. You can continue to extend the chain however you wish.

    I suspect you are confusing the types created as the chain is set up with the types that propagate through the chain itself.

    promise.map { String(describing: $0) }
    

    is the same as

    promise.map(transform: { String(describing: $0) })
    

    The closure is just an argument to map, and map runs as the promise is being set up. But map doesn't run the closure itself; it just saves it to be used later as the chain executes. map itself returns a Promise<String> (in this case).

    then makes this conceptually confusing because both the closure and the then return Promise<X>. But the Promise<X> returned by then is not actually the Promise<X> created by the closure (which hasn't even run yet). It's just a wrapper that will run the closure at the appropriate time and then pass the result of the newly-generated promise on to its own descendants.

  2. Repository owner locked and limited conversation to collaborators on May 24, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions