apollographql / apollo-ios

📱  A strongly-typed, caching GraphQL client for iOS, written in Swift.
https://www.apollographql.com/docs/ios/
MIT License
3.89k stars 730 forks source link

Problems with interceptor #3468

Closed Jensileus closed 3 weeks ago

Jensileus commented 3 weeks ago

Question

I have some problems with my Network.swift that is the apollo clent and handler, //Network.swift import Foundation import Apollo import FixiAPI

enum NetworkError: Error { case userNotFound case networkFailure case missingToken }

class Network { static let shared = Network() private let authManager = AuthenticationManager()

private(set) lazy var apollo: ApolloClient = {
    let url = URL(string: "https://api.gg.gg/graphql")!
    let store = ApolloStore()
    let interceptorProvider = DefaultInterceptorProvider(store: store)

    // Correct way to add interceptors:
    TokenInterCeption.interceptors = { [authManager] operation in
        return [TokenInterCeption(authManager: authManager)]
    }

    let transport = RequestChainNetworkTransport(interceptorProvider: interceptorProvider, endpointURL: url)
    return ApolloClient(networkTransport: transport, store: store)
}()

private init() {}

func fetchUserContext(completion: @escaping (Result<UserContextQuery.Data, Error>) -> Void) {
    apollo.fetch(query: UserContextQuery()) { result in
        switch result {
        case .success(let graphQLResult):
            if let userContext = graphQLResult.data {
                completion(.success(userContext))
            } else {
                completion(.failure(NetworkError.userNotFound))
            }
        case .failure(let error):
            completion(.failure(error))
        }
    }
}

} import Foundation import Apollo

class Tokeninterceptor: ApolloInterceptor { private let authManager: AuthenticationManager

init(authManager: AuthenticationManager) {
    self.authManager = authManager
}

func interceptAsync<Operation: GraphQLOperation>(
    chain: RequestChain,
    request: HTTPRequest<Operation>,
    response: HTTPResponse<Operation>?,
    completion: @escaping (Result<GraphQLResult<Operation.Data>, Error>) -> Void) {

    if let token = authManager.getAccessToken() {
        request.addHeader(name: "Link", value: token)
    }

    chain.proceedAsync(request: request, response: response, interceptor: self, completion: completion)
}

} this was a mix but the main problem is this: Type 'Tokeninterceptor' does not conform to protocol 'ApolloInterceptor' <- why?

Jensileus commented 3 weeks ago

We try again: // Network.swift import Foundation import Apollo import FixiAPI

enum NetworkError: Error { case userNotFound case networkFailure case missingToken }

class Network { static let shared = Network() private let authManager = AuthenticationManager()

private(set) lazy var apollo: ApolloClient = {
    let url = URL(string: "https://xx.xxx.one/graphql")!
    let store = ApolloStore()

    let userManagerInterceptor = UserManagementInterceptor(authManager: authManager) // Create interceptor instance

    let interceptorProvider = DefaultInterceptorProvider(store: store, interceptors: [userManagerInterceptor]) // Add to provider

    let transport = RequestChainNetworkTransport(interceptorProvider: interceptorProvider, endpointURL: url)
    return ApolloClient(networkTransport:

transport, store: store) }()

private init() {}

func fetchUserContext(completion: @escaping (Result<UserContextQuery.Data, Error>) -> Void) {
    apollo.fetch(query: UserContextQuery()) { result in
        switch result {
        case .success(let graphQLResult):
            if let userContext = graphQLResult.data {
                completion(.success(userContext))
            } else {
                completion(.failure(NetworkError.userNotFound))
            }
        case .failure(let error):
            completion(.failure(error))
        }
    }
}

} // UserManagementInterceptor.swift (updated) import Foundation import Apollo

class UserManagementInterceptor: ApolloInterceptor { private let authManager: AuthenticationManager

init(authManager: AuthenticationManager) {
    self.authManager = authManager
}

func interceptAsync<Operation: GraphQLOperation>(
    chain: RequestChain,
    request: HTTPRequest<Operation>,
    response: HTTPResponse<Operation>?,
    completion: @escaping (Result<GraphQLResult<Operation.Data>, Error>) -> Void

) {
    // Access token from AuthenticationManager
    guard let token = authManager.getAccessToken() else {
        chain.handleErrorAsync(NetworkError.missingToken,
                               request: request,
                               response: response,
                               completion: completion)
        return
    }

    request.addHeader(name: "Authorization", value: "Bearer \(token)")
    chain.proceedAsync(request: request,
                      response: response,

                      interceptor: self,
                      completion: completion)

}

} so i made a own? But is this built in?

calvincestari commented 3 weeks ago

this was a mix but the main problem is this: Type 'Tokeninterceptor' does not conform to protocol 'ApolloInterceptor' <- why?

@Jensileus, Xcode is able to add the stubs to your code for ApolloInterceptor conformance, I suggest you use that.

But is this built in?

I don't understand the question - is what built in?

github-actions[bot] commented 3 weeks ago

Do you have any feedback for the maintainers? Please tell us by taking a one-minute survey. Your responses will help us understand Apollo iOS usage and allow us to serve you better.