Emre Önder
Emre Önder

Reputation: 2537

Get first response object in PromiseKit then done block

I'm calling three services in a row. When I'm calling third service, I need to use variable from first service response which is userModel. I can get second service response from which is initModel but can't reach first model userModel. My Question is that how can I use userModel in done block by returning it then blocks?

P.S: I tried to return -> Promise<(UserModel,InstallationModel)> in first call but because UserModel is already an object not a promise, I need to convert it to promise to return it. This looks like me a bad way to do it.

As you can see I'm storing it with self.userModel = userModel which I don't wanna do.

func callService(completionHandler: @escaping (Result<UserModel>) -> Void) {
    SandboxService.createsandboxUser().then { userModel -> Promise<InstallationModel> in
        self.userModel = userModel
        return SandboxService.initializeClient(publicKey: self.keyPairs.publicKey)
    }.then { initModel -> Promise<DeviceServerResponseModel> in
        self.initModel = initModel
        if let unwrappedUserModel = self.userModel {
            return SandboxService.deviceServerServiceCaller(authKey: initModel.token.token,apiKey:unwrappedUserModel.apiKey,privaKey: self.keyPairs.privateKey)
        }
        throw ServiceError.handleParseError()
    }.then { serverResponseModel -> Promise<UserModel> in
        if let unwrappedInitModel = self.initModel, let unwrappedUserModel = self.userModel {
            return SandboxService.sessionServiceCaller(authKey: unwrappedInitModel.token.token, apiKey: unwrappedUserModel.apiKey, privaKey: self.keyPairs.privateKey)
        }
        throw ServiceError.handleParseError()
    }.done { userModel in
        completionHandler(Result.success(userModel))
    }.catch { error in
        completionHandler(Result.error(error))
    }
}

Upvotes: 3

Views: 1288

Answers (2)

Emre &#214;nder
Emre &#214;nder

Reputation: 2537

I had also opened issue at PromiseKit page @Github. I'm sharing answer of Mxcl from Github to here also.

func callService(completionHandler: @escaping (Result<UserModel>) -> Void) {
    SandboxService.createsandboxUser().then { userModel in
        firstly {
            SandboxService.initializeClient(publicKey: self.keyPairs.publicKey)
        }.then { initModel in
            SandboxService.deviceServerServiceCaller(authKey: initModel.token.token, apiKey: userModel.apiKey,privaKey: self.keyPairs.privateKey).map{ ($0, initiModel) }
        }.then { serverResponseModel, initModel in
            SandboxService.sessionServiceCaller(authKey: initModel.token.token, apiKey: userModel.apiKey, privaKey: self.keyPairs.privateKey)
        }
    }.pipe(to: completionHandler)
}

Upvotes: 4

emrepun
emrepun

Reputation: 2666

I'm not familiar with PromiseKit but since it is a framework, you cannot really edit the methods in a way that you could include userModel in callback of .done method. So what I would do is, have an optional value declared in the class where this code block is executed with the type of userModel, and then set it to received value from first call, then set it back to nil after using it in second one. Like following:

Lets assume type of userModel is UserModel.

final class SampleFetcher {
    let userModel: UserModel?

    func fetch() {
        SandboxService.createsandboxUser().then { userModel in
            SandboxService.initializeClient()
            // save userModel here.
            userModel = userModel
            }.done { initModel in
                // Use it here
                guard let userModel = userModel else {
                    return
                }
                SandboxService.deviceServerServiceCaller(secretID: "")
                // after you are done, set it to nil
                userModel = nil
            }.catch { error in
        }
    }
}

If it wasn't a framework, you could write functions in a way that you could include userModel in second callback as well.

Upvotes: 1

Related Questions