Im making an attempt to refresh token utilizing Mix in Swift. I put refresh half within the tryCatch half inside URLSession.shared.dataTaskPublisher however for some cause .sink returns as error even when this half in tryCatch is working and new token is fetched.
That is what I’ve in ViewModel:
personal func testApi() {
useCase.getSomeData
.obtain(on: DispatchQueue.most important)
.sink { completion in
swap completion {
case .failure(_):
//That is the place Im getting error code!
case .completed: break
}
} receiveValue: { [weak self] response in
print(response
}
.retailer(in: &cancellables)
}
And this func’s are in my Community class:
public func request<T>(_ req: NetworkRequest) -> AnyPublisher<T, NetworkError> the place T: Decodable, T: Encodable {
guard let url = URL(string: req.url) else {
return AnyPublisher(
Fail<T, NetworkError>(error: NetworkError.badURL("Invalid Url"))
)
}
let urlRequest = req.buildURLRequest(with: url)
return URLSession
.shared
.dataTaskPublisher(for: urlRequest)
.tryMap { output in
let code = (output.response as? HTTPURLResponse)?.statusCode ?? 200
let httpStatusCode = HTTPStatusCode(rawValue: code) ?? .noResponse
let outputData = output.information
let message = self.responseErrorMessage(outputData)
guard output.response is HTTPURLResponse else {
throw NetworkError.serverError(code: code, error: message)
}
swap httpStatusCode {
case .okay, .created, .accepted:
return output.information
case .badRequest, .notFound:
throw NetworkError.badRequest(code: code, error: message)
case .battle:
throw NetworkError.unknown(code: code, error: message)
case .tokenExpired:
throw NetworkError.unknown(code: code, error: message)
case .unauthorised:
throw NetworkError.unauthorised(code: code, error: message)
case .paymentRequired, .forbidden, .methodNotAllowed, .requestTimeout, .unsupportedMediaType, .tooManyRequests:
throw NetworkError.unknown(code: code, error: message)
case .noResponse:
throw NetworkError.noResponse(message)
case .internalServerError, .serviceUnavailable:
throw NetworkError.serverError(code: code, error: message)
}
}
.tryCatch { [weak self] error -> AnyPublisher<Information, NetworkError> in
guard let self = self else { throw error }
if error as? NetworkError == .unauthorised(code: 401, error: "Unauthorized") {
return refreshToken
.flatMap { _ -> AnyPublisher<Information, NetworkError> in
self.request(self.updateRequest(req))
}
.eraseToAnyPublisher()
}
throw error
}
.decode(kind: T.self, decoder: jsonDecoder)
.mapError { error in
if let error = error as? NetworkError {
return error
}
return NetworkError.invalidJSON(String(describing: error))
}
.eraseToAnyPublisher()
}
That is refresh half:
personal var refreshToken: AnyPublisher<Void, NetworkError> {
URLSession
.shared
.dataTaskPublisher(for: buildRefreshRequest())
.map(.information)
.decode(kind: LoginResponseData.self, decoder: jsonDecoder)
.map { response in
let token = response.accessToken
UserDefaults.token = token
}
.mapError { error in
if let error = error as? NetworkError {
return error
}
return NetworkError.invalidJSON(String(describing: error))
}
.eraseToAnyPublisher()
}
So in brief, once I name useCase.getSomeData, I simulate token expire in debug mode by deleting token from headers, after that Im getting 401 in tryMap and in tryCatch catches that error and calling refreshToken and ‘self.request(self.updateRequest(req))’ is known as after new token is fetched however Im not getting code in ‘receiveValue: { [weak self] response ‘ in viewModel, as a substitute it completes in ‘.sink ‘ as a failure.
Im recent in Mix and making an attempt to implement this 401/refreshToken half however I couldn’t determine what Im lacking right here.