MOB-20804 - updateProposition api with a callback to handle timeout#110
Conversation
…Error will never succeed
…dk-optimize-ios into fix/updateProposition
| @@ -1,68 +0,0 @@ | |||
| PODS: | |||
There was a problem hiding this comment.
Does this need to be deleted? 🤔
There was a problem hiding this comment.
Restored old podfile.lock from base branch.
| /// - Parameter data: Additional free-form data to be sent in the personalization request. | ||
| @objc(updatePropositions:withXdm:andData:) | ||
| static func updatePropositions(for decisionScopes: [DecisionScope], withXdm xdm: [String: Any]?, andData data: [String: Any]? = nil) { | ||
| /// - Parameter completion: An optional callback to be used by consumer |
There was a problem hiding this comment.
can you add what is returned in the callback?
- Parameter completion: Optional completion handler invoked with errors, if any
| static func updatePropositions(for decisionScopes: [DecisionScope], withXdm xdm: [String: Any]?, andData data: [String: Any]? = nil) { | ||
| /// - Parameter completion: An optional callback to be used by consumer | ||
| @objc(updatePropositions:withXdm:andData:completion:) | ||
| static func updatePropositions(for decisionScopes: [DecisionScope], withXdm xdm: [String: Any]?, andData data: [String: Any]? = nil, _ completion: ((Bool, Error?) -> Void)? = nil) { |
There was a problem hiding this comment.
Wondering if we can do away with the boolean value and simplify the completion handler to just _ completion: ((Error?) -> Void)?. If there's no error, we can return null. The boolean field seems a bit superfluous. Thoughts?
There was a problem hiding this comment.
We have changed this to keep list of successful decision scopes and AEPOptimize error as of now
There was a problem hiding this comment.
Update - we are now returning ([DecisionScope: OptimizeProposition]?, AEPOptimizeError?) in completion
Sources/AEPOptimize/Optimize.swift
Outdated
| type: EventType.optimize, | ||
| source: EventSource.responseContent, | ||
| data: [ | ||
| OptimizeConstants.EventDataKeys.COMPLETED_UPDATE_EVENT_ID: requestEventId |
There was a problem hiding this comment.
This value isn't being read or used in the public API response callback. Can we omit it? The public API does not need to aware of this edge request event id
There was a problem hiding this comment.
Yes, from here we are sending list of successful decision scopes.
There was a problem hiding this comment.
Update - now we are sending propositionsInProgress: [DecisionScope: OptimizeProposition] from here
| completion?(false, AEPError.callbackTimeout) | ||
| return | ||
| } | ||
| if let error = responseEvent.data?[OptimizeConstants.EventDataKeys.RESPONSE_ERROR] as? AEPError { |
There was a problem hiding this comment.
nit: Can you check if you can use getTypedData here instead of casting?
let error: AEPError = responseEvent.getTypedData(for: OptimizeConstants.EventDataKeys.RESPONSE_ERROR)
There was a problem hiding this comment.
- Please fix code formatting.
- Make changes to existing tests if needed and ensure all of them pass.
- In
OptimizePublicAPITests, please add a test which has a completion handler passed inupdatePropositionsAPI call and verify its called in case of timeout. - In
OptimizeIntegrationTests, please add a testtestUpdatePropositions_timeoutErrorwith a completion handler passed in and simulating a network request timeout case.
…ecision scopes and AEPOptimizeError
|
Hi @spoorthipujariadobe, I have made few changes based on your comments and added test cases as you suggested. Please review. |
…changed default value of aepError to unexpected
| source: EventSource.responseContent, | ||
| data: [ | ||
| OptimizeConstants.EventDataKeys.RESPONSE_ERROR: error.rawValue | ||
| OptimizeConstants.EventDataKeys.RESPONSE_ERROR: error |
There was a problem hiding this comment.
nit: If createErrorResponseEvent(_ error: AEPError) isn't being used anymore, can we remove it?
There was a problem hiding this comment.
since we return AEPError in getProposition api, we are using this function. If we return AEPOptimizeError instead, we can remove this function.
There was a problem hiding this comment.
Discussed offline to return AEPOptimizeError in getPropositions as well for API consistency
| static func updatePropositions(for decisionScopes: [DecisionScope], withXdm xdm: [String: Any]?, andData data: [String: Any]? = nil) { | ||
| /// - Parameter completion: Optional completion handler invoked with list of successful decision scopes and errors, if any | ||
| @objc(updatePropositions:withXdm:andData:completion:) | ||
| static func updatePropositions(for decisionScopes: [DecisionScope], withXdm xdm: [String: Any]?, andData data: [String: Any]? = nil, _ completion: (([DecisionScope]?, AEPOptimizeError?) -> Void)? = nil) { |
There was a problem hiding this comment.
I thought we're sending back the propositions that were successfully fetched in the completion handler. Should this be
_ completion: (([DecisionScope: OptimizeProposition]?, AEPOptimizeError?) -> Void)? =nil
There was a problem hiding this comment.
As discussed offline, we are now sending ([DecisionScope: OptimizeProposition]?, AEPOptimizeError?) in completion
Sources/AEPOptimize/Optimize.swift
Outdated
| type: EventType.optimize, | ||
| source: EventSource.responseContent, | ||
| data: [ | ||
| OptimizeConstants.EventDataKeys.DECISION_SCOPES: Array(self.propositionsInProgress.keys) |
There was a problem hiding this comment.
Same question here. Should we also be returning the propositionsInProgress.values which have the actual OptimizeProposition?
There was a problem hiding this comment.
Yes, we are now sending propositionInProgress in event data.
| public let status: Int? | ||
| public let title: String? | ||
| public let detail: String? | ||
| public var aepError = AEPError.unexpected |
There was a problem hiding this comment.
Wondering why we added AEPError here? Could you please share how customers are going to use this?
There was a problem hiding this comment.
In get proposition api, today we return ([DecisionScope: OptimizeProposition]?, Error?), where Error is of type AEPError. Considering the possibility customer has kept some check or performed any logic on their side on basis of AEPErrors we added this variable. We can discuss on sending back AEPOptimizeError in getProposition api as well instead of AEPError to improve on parity between api callback.
| wait(for: [expectation], timeout: 12) | ||
| XCTAssertEqual(mockRuntime.dispatchedEvents.count, 2) | ||
|
|
||
| let dispatchedEvent = mockRuntime.dispatchedEvents.first |
There was a problem hiding this comment.
can you add assertions for the first event as well to verify the type, source and maybe the propositions that are returned in that event in case of success?
There was a problem hiding this comment.
Same comment for all following tests
spoorthipujariadobe
left a comment
There was a problem hiding this comment.
Great job with the changes and test coverage! I just have a few small questions
| status: 408, | ||
| title: "Request Timeout", | ||
| detail: "Update proposition request resulted in a timeout.", |
There was a problem hiding this comment.
Can we add these values in OptimizeConstants?
Sources/AEPOptimize/Optimize.swift
Outdated
| status: 408, | ||
| title: "Request Timeout", | ||
| detail: "Update proposition request resulted in a timeout.", |
There was a problem hiding this comment.
Same comment here. Please add in OptimizeConstants and reuse wherever needed
| } | ||
|
|
||
| // response event to provide success callback to updateProposition public api | ||
| let responseEventToSend = event.createResponseEvent( |
There was a problem hiding this comment.
Considering we're also using this same event type and source in processGetPropositions do you think it makes sense to move this also to Event+Optimize.swift, similar to createErrorResponseEvent?
There was a problem hiding this comment.
Yes, since now we are returning ([DecisionScope: OptimizeProposition]?, AEPOptimizeError?) in update proposition's api, we can create a common util function in Event+Optimize.swift. However, in update proposition callback we can have scenario where we have successful [DecisionScope: OptimizeProposition] and AEPOptimizeError both if one upstream gives error and other succeed. So I tried creating a common function which is like this -
createCallbackResponseEvent(_ data: [DecisionScope: OptimizeProposition], _ error: AEPOptimizeError?) -> Event and in case of get proposition i tried sending error as nil which failed some of the test cases. I am debugging that and once I am clear on that I will push it or will include this in next PR which will cover other edge error handling apart from timeout.
| // update propositions | ||
| Optimize.updatePropositions(for: [decisionScope], withXdm: nil) | ||
| Optimize.updatePropositions(for: [decisionScope], withXdm: nil){ (scope,error) in | ||
| XCTAssertNotNil(scope) |
There was a problem hiding this comment.
nit: Can you also add XCTAssertNil(error) for success case?
…sition]? instead of [DecisionScope]? in callback and code review changes
…ve AEPOptimizeError as argument and minor changes
sbenedicadb
left a comment
There was a problem hiding this comment.
looks ok other than it's not clear to me what the purpose is of the type property in OptimizeError.
let's either make it more clear what that property is for, or remove it if it's not in use.
| @objc(AEPOptimizeError) | ||
| public class AEPOptimizeError: NSObject, Error { | ||
| typealias HTTPResponseCodes = OptimizeConstants.HTTPResponseCodes | ||
| public let type: String? |
There was a problem hiding this comment.
is this type property being used?
There was a problem hiding this comment.
type property is received in edge error response content and we have kept it for that purpose. For timeout or any other invalid request case on optimize SDK side this will be nil.
|
thanks a lot for reviewing @sbenedicadb, answering for purpose of keeping type field -
As discussed with team, we have currently decided to send the type field in the error object and thus we have kept it in OptimizeError class." |
|
Thanks @akhiljain1907 - this is super helpful information. it would be good to include this detail in the code itself so anyone maintaining it could get this context as well. |
Description
This PR supports update proposition public api call with an optional completion handler invoked with list of successful decision scopes and errors received by edge (if any). In order to provide error details back we have also created a public class AEPOptimizeError and kept an additional field of AEPError in it which is mapped on the basis of error status received.
Related Issue
Motivation and Context
How Has This Been Tested?
Screenshots (if appropriate):
Types of changes
Checklist: