Files
purchases-ios/Sources/Networking/Operations/PostSubscriberAttributesOperation.swift
T
NachoSoto 2504b953b8 Simplified HTTPClient.Completion and refactored response handling implementation (#1426)
For #695.

The biggest change is that this code at the beginning of `HTTPClient.handle` is now gone:
```swift
var statusCode: HTTPStatusCode = .networkConnectTimeoutError
var jsonObject: [String: Any]?
var httpResponse: HTTPResponse? = HTTPResponse(statusCode: statusCode, jsonObject: jsonObject)
var receivedJSONError: Error?
```

It was hard to trace which paths modified these default values. The new implementation has a mostly linear path (part of it abstracted in smaller methods now) and doesn’t have mutable values.

This is the new `handle` implementation:
```swift
func handle(urlResponse: URLResponse?,
            request: Request,
            urlRequest: URLRequest,
            data: Data?,
            error networkError: Error?) {
    let (response, shouldRetry) = self.parse(
        urlResponse: urlResponse,
        request: request,
        urlRequest: urlRequest,
        data: data,
        error: networkError
    )

    if shouldRetry {
        Logger.debug(Strings.network.retrying_request(httpMethod: request.method.httpMethod,
                                                      path: request.path))

        self.state.modify {
            $0.queuedRequests.insert(request.retriedRequest(), at: 0)
        }
    } else {
        request.completionHandler?(response)
    }

    self.beginNextRequest()
}
```

## All Changes:

- `HTTPClient.perform` no longer has a bunch of mutable variables with forking paths that make it hard to follow. Most of the response handling is now in a new `parse` method. This will simplify the task of continuing to refactor response deserialization.
- `HTTPClient`’s completion abstracts response into `HTTPResponse`
- `UserInfoAttributeParser` is now an `enum`
- `ETagManager` no longer takes an `Error`. The only thing it did with it is to return the default response.
- `HTTPResponse.jsonObject` is no longer `Optional`
- Moved `defaultJsonEncoder` / `defaultJsonDecoder` to `JSONDecoder+Extensions`. They used by `HTTPClient` and others soon.
2022-04-01 14:22:29 -07:00

89 lines
2.8 KiB
Swift

//
// Copyright RevenueCat Inc. All Rights Reserved.
//
// Licensed under the MIT License (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://opensource.org/licenses/MIT
//
// PostSubscriberAttributesOperation.swift
//
// Created by Joshua Liebowitz on 11/18/21.
import Foundation
class PostSubscriberAttributesOperation: NetworkOperation {
private let subscriberAttributeHandler: SubscriberAttributeHandler
private let configuration: UserSpecificConfiguration
private let subscriberAttributes: SubscriberAttributeDict
private let responseHandler: SimpleResponseHandler?
init(configuration: UserSpecificConfiguration,
subscriberAttributes: SubscriberAttributeDict,
completion: SimpleResponseHandler?,
subscriberAttributeHandler: SubscriberAttributeHandler = SubscriberAttributeHandler()) {
self.configuration = configuration
self.subscriberAttributes = subscriberAttributes
self.responseHandler = completion
self.subscriberAttributeHandler = subscriberAttributeHandler
super.init(configuration: configuration)
}
override func begin(completion: @escaping () -> Void) {
post(completion: completion)
}
private func post(completion: @escaping () -> Void) {
guard self.subscriberAttributes.count > 0 else {
Logger.warn(Strings.attribution.empty_subscriber_attributes)
self.responseHandler?(ErrorCode.emptySubscriberAttributes)
completion()
return
}
guard let appUserID = try? self.configuration.appUserID.escapedOrError() else {
self.responseHandler?(ErrorUtils.missingAppUserIDError())
completion()
return
}
let request = HTTPRequest(method: .post(Body(self.subscriberAttributes)),
path: .postSubscriberAttributes(appUserID: appUserID))
httpClient.perform(request, authHeaders: self.authHeaders) { response in
defer {
completion()
}
guard let responseHandler = self.responseHandler else {
return
}
self.subscriberAttributeHandler.handleSubscriberAttributesResult(response,
completion: responseHandler)
}
}
}
extension PostSubscriberAttributesOperation {
private struct Body: Encodable {
let attributes: AnyEncodable
init(_ attributes: SubscriberAttributeDict) {
self.attributes = AnyEncodable(
SubscriberAttributesMarshaller.map(subscriberAttributes: attributes)
)
}
}
}