Tuesday, January 30, 2024
HomeiOS Developmentios - Refresh token utilizing Swift Mix

ios – Refresh token utilizing Swift Mix


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.



Supply hyperlink

RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

- Advertisment -
Google search engine

Most Popular

Recent Comments