Как добавить заголовок в Apollo GraphQL: iOS

Привет, я работаю над проектом с методом Apollo GraphQL, и он работает нормально. Но теперь клиенту требуется добавить дополнительный заголовок с API-интерфейсом Apollo. Но после добавления заголовка ответ API возвращается как неавторизованный.

Я добавляю заголовок как,

    let apolloAuth: ApolloClient = {
        let configuration = URLSessionConfiguration.default

        // Add additional headers as needed
        configuration.httpAdditionalHeaders = ["Authorization" : self.singleTonInstance.token]
        configuration.httpAdditionalHeaders = ["channel" : "mobile"]

        let url = URL(string: "http://xxx/graphql")!

        return ApolloClient(networkTransport: HTTPNetworkTransport(url: url, configuration: configuration))

    }()

Кто-нибудь, пожалуйста, помогите мне узнать, как добавлять заголовки с помощью Apollo GraphQL.

Вы пытались установить заголовок «Bearer <token>» вместо «<token>»? Какой метод авторизации использует ваш сервер? У вас есть рабочий оператор cURL для сервера, который использует токен авторизации?

marktani 01.04.2019 15:49

вы нашли какое-нибудь решение?

Arash Etemad 29.04.2019 14:01

Пожалуйста, обратитесь к моему ответу.

Angel F Syrus 29.04.2019 14:08
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
13
3
6 467
7
Перейти к ответу Данный вопрос помечен как решенный

Ответы 7

Ответ принят как подходящий

Наконец я нашел ответ. Добавьте заголовок следующим образом:

 let apolloAuth: ApolloClient = {
        let configuration = URLSessionConfiguration.default

        let token = UserDefaults.standard.value(forKey: "token")
        // Add additional headers as needed
        configuration.httpAdditionalHeaders = ["authorization":"\(token!)", "channel":"mobile"]
        let url = URL(string: "http://xxxx/graphql")!

        return ApolloClient(networkTransport: HTTPNetworkTransport(url: url, configuration: configuration))

    }()

Надеюсь, это поможет кому-то.

он перестает работать с версии 0.34, больше нет HTTPNetworkTransport

QuangLoc 10.11.2020 10:46

Принятое решение теперь устарело, поскольку HTTPNetworkTransport больше не принимает аргумент конфигурации, вместо этого принимает URLSession напрямую, а не URLSessionConfiguration

Вот пример того, как отправлять заголовок авторизации при каждом запросе к клиенту Apollo, извлекая его, если он найден, из UserDefaults в version 0.21.0 клиента Apollo (iOS).

import Foundation
import Apollo

class Network {
    static let shared = Network()

    private(set) lazy var apollo: ApolloClient = {
        let token = UserDefaults.standard.string(forKey: "accessToken") ?? ""
        let url = URL(string: "http://localhost:4000/graphql")!

        let configuration = URLSessionConfiguration.default

        configuration.httpAdditionalHeaders = ["authorization": "Bearer \(token)"]

        return ApolloClient(
            networkTransport: HTTPNetworkTransport(url: url, session: URLSession(configuration: configuration))
        )
    }()
}

ОБНОВЛЕНИЕ: это решение устарело после «Apollo Client v0.34.0».

Предыдущие ответы устарели, теперь это делается через делегата:

"This protocol allows pre-flight validation of requests, the ability to bail out before modifying the request, and the ability to modify the URLRequest with things like additional headers."

import Foundation
import Apollo

    final class Network {
        static let shared = Network()
        private lazy var networkTransport: HTTPNetworkTransport = {        

        let transport = HTTPNetworkTransport(url: URL(string: "https://example.com/graphql")!)
        transport.delegate = self

        return transport
    }()

    private(set) lazy var apollo = ApolloClient(networkTransport: self.networkTransport)
}

extension Network: HTTPNetworkTransportPreflightDelegate {
    func networkTransport(_ networkTransport: HTTPNetworkTransport, shouldSend request: URLRequest) -> Bool {
        return true
    }

    func networkTransport(_ networkTransport: HTTPNetworkTransport, willSend request: inout URLRequest) {
        var headers = request.allHTTPHeaderFields ?? [String: String]()
        headers["Authorization"] = "Bearer \(YOUR_TOKEN)"

        request.allHTTPHeaderFields = headers
    }
}

Вот ссылка на документацию для более подробной информации:

https://www.apollographql.com/docs/ios/initialization/

Я получаю эти ошибки Cannot find type 'HTTPNetworkTransport' in scope и Cannot find type 'HTTPNetworkTransportPreflightDelegate' in scope любую помощь? Я использую Appoloclient v0.34.1.

G B 10.10.2020 03:59

@GB Я проверил документы по ссылке выше, и они устарели от HTPPNetworkTransport. Это все еще можно сделать с помощью «LegacyInterceptorProvider», или вы можете изучить новый протокол: NetworkTransport.

jsonkuan 12.10.2020 11:18

Я предоставил решение, которое вы можете посмотреть на него.

G B 12.10.2020 16:33

Начиная с Apollo Client v0.34.0 и выше, код, предоставленный ранее, не будет работать, так как они переписали, как он работал раньше. Вот что у меня сработало... Для получения дополнительной информации рассмотрите эту документацию по ссылке здесь.

class Network {
  static let shared = Network()
  
    private(set) lazy var apollo: ApolloClient = {
        let client = URLSessionClient()
        let cache = InMemoryNormalizedCache()
        let store = ApolloStore(cache: cache)
        let provider = NetworkInterceptorProvider(client: client, store: store)
        let url = URL(string: "https://www.graphqlapi.com/")!
        let transport = RequestChainNetworkTransport(interceptorProvider: provider,
                                                     endpointURL: url)
        return ApolloClient(networkTransport: transport)
    }()
}

class NetworkInterceptorProvider: LegacyInterceptorProvider {
    override func interceptors<Operation: GraphQLOperation>(for operation: Operation) -> [ApolloInterceptor] {
        var interceptors = super.interceptors(for: operation)
        interceptors.insert(CustomInterceptor(), at: 0)
        return interceptors
    }
}

class CustomInterceptor: ApolloInterceptor {
    // Find a better way to store your token this is just an example
    let token = "YOUR TOKEN"
    
    func interceptAsync<Operation: GraphQLOperation>(
        chain: RequestChain,
        request: HTTPRequest<Operation>,
        response: HTTPResponse<Operation>?,
        completion: @escaping (Result<GraphQLResult<Operation.Data>, Error>) -> Void) {
        
        request.addHeader(name: "authorization", value: "Bearer: \(token)")

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

ОБНОВЛЕНИЕ: Решение для «Apollo Client v0.41.0» и «Swift 5»

У меня была такая же проблема с Apollo Client v0.41.0 и Swift 5.0, но ни одно из вышеперечисленных решений не сработало. Наконец удалось найти решение после нескольких часов испытаний. Приведенное ниже решение протестировано с помощью Apollo Client v0.41.0 и Swift 5.

import Foundation
import Apollo

class Network {
    static let shared = Network()
    
    private(set) lazy var apollo: ApolloClient = {

        let cache = InMemoryNormalizedCache()
        let store1 = ApolloStore(cache: cache)
        let authPayloads = ["Authorization": "Bearer <<TOKEN>>"]
        let configuration = URLSessionConfiguration.default
        configuration.httpAdditionalHeaders = authPayloads
        
        let client1 = URLSessionClient(sessionConfiguration: configuration, callbackQueue: nil)
        let provider = NetworkInterceptorProvider(client: client1, shouldInvalidateClientOnDeinit: true, store: store1)
        
        let url = URL(string: "https://<HOST NAME>/graphql")!
        
        let requestChainTransport = RequestChainNetworkTransport(interceptorProvider: provider,
                                                                 endpointURL: url)
        
        return ApolloClient(networkTransport: requestChainTransport,
                            store: store1)
    }()
}
class NetworkInterceptorProvider: DefaultInterceptorProvider {
    override func interceptors<Operation: GraphQLOperation>(for operation: Operation) -> [ApolloInterceptor] {
        var interceptors = super.interceptors(for: operation)
        interceptors.insert(CustomInterceptor(), at: 0)
        return interceptors
    }
}

class CustomInterceptor: ApolloInterceptor {
    
    func interceptAsync<Operation: GraphQLOperation>(
        chain: RequestChain,
        request: HTTPRequest<Operation>,
        response: HTTPResponse<Operation>?,
        completion: @escaping (Swift.Result<GraphQLResult<Operation.Data>, Error>) -> Void) {
        request.addHeader(name: "Authorization", value: "Bearer <<TOKEN>>")
        
        print("request :\(request)")
        print("response :\(String(describing: response))")
        
        chain.proceedAsync(request: request,
                           response: response,
                           completion: completion)
    }
}

Спасибо! Это единственное решение, которое работает с Apollo 0.42.0.

Jochen Holzer 22.04.2021 17:16

@Camath Jeevan Я попробовал это решение с версией Apollo 0.43.0, и оно выдает ошибку сбоя reposne как сбой(Apollo.LegacyParsingInterceptor.LegacyParsingError.c‌​ouldNotParseToLegacy‌​JSON (данные: 1839 байтов)), пожалуйста, предложите мне, что я могу сделать дальше

Princess 29.04.2021 13:01

@JochenHolzer Я тоже пробовал тот же синтаксис кода, но запрос дает мне HTML в блоке сбоя. Не могли бы вы помочь мне решить эту проблему Заголовок Apollo GraphQL всегда дает сбой в iOS Swift

Princess 03.05.2021 08:08

@Princess Возможно, в ответе HTML есть сообщение об ошибке. На вашем месте я бы спросил команду разработчиков конечной точки, какая информация о вашем неудачном запросе содержится в файлах журнала сервера.

Jochen Holzer 03.05.2021 14:26

@JochenHolzer Я использую Shopify GraphQL Admin API для получения информации о заказе клиента из магазина Shopify. Тот же URL-запрос работает с клиентом Android Apollo.

Princess 04.05.2021 06:41

Это решение сработало для меня. Спасибо @ChamathJeevan

GMHSJ 28.06.2021 07:00

Импортируйте эти два элемента

import UIKit
import Apollo

Создайте класс Network и вставьте ниже исходный код

    struct Network {
    static var request = Network()
    private(set) lazy var apollo: ApolloClient = {

        let cache = InMemoryNormalizedCache()
        let store1 = ApolloStore(cache: cache)
        let authPayloads = ["Authorization": "Bearer <TOKEN>"]
        let configuration = URLSessionConfiguration.default
        configuration.httpAdditionalHeaders = authPayloads
        
        let client1 = URLSessionClient(sessionConfiguration: configuration, callbackQueue: nil)
        let provider = NetworkInterceptorProvider(client: client1, shouldInvalidateClientOnDeinit: true, store: store1)
        
        let url = URL(string: "http://xxx/graphql")!
        
        let requestChainTransport = RequestChainNetworkTransport(interceptorProvider: provider,
                                                                 endpointURL: url)
        
        return ApolloClient(networkTransport: requestChainTransport,
                            store: store1)
    }()
}

добавить NetworkInterceptorProvider в сетевой класс

class NetworkInterceptorProvider: LegacyInterceptorProvider {
override func interceptors<Operation: GraphQLOperation>(for operation: Operation) -> [ApolloInterceptor] {
    var interceptors = super.interceptors(for: operation)
    interceptors.insert(CustomInterceptor(), at: 0)
    return interceptors
}

}

добавить CustomInterceptor также в сетевой класс

class CustomInterceptor: ApolloInterceptor {

func interceptAsync<Operation: GraphQLOperation>(
    chain: RequestChain,
    request: HTTPRequest<Operation>,
    response: HTTPResponse<Operation>?,
    completion: @escaping (Swift.Result<GraphQLResult<Operation.Data>, Error>) -> Void) {
    request.addHeader(name: "Authorization", value: "Bearer <TOKEN>")
    
    print("request :\(request)")
    print("response :\(String(describing: response))")
    
    chain.proceedAsync(request: request,
                       response: response,
                       completion: completion)
}

}

наконец, вызовите этот метод из ViewController

func todoQueryCloud(){
    Network.request.apollo.fetch(query: ProgressionsQuery()){result in
        // 3
        switch result {
        case .success(let graphQLResult):
            guard let data = try? result.get().data else { return }
            if graphQLResult.data != nil {
                // 4
                print("Loaded data \(String(describing: data.progressions))")
                self.collectionView.reloadData()
            }
            
        case .failure(let error):
            // 5
            print("Error loading data \(error)")
        }
    }
}

У меня это не работает. Я задал новый вопрос Заголовок Apollo GraphQL всегда дает сбой в iOS Swift, пожалуйста, проверьте это.

Princess 03.05.2021 08:05

NetworkInterceptorProvider: LegacyInterceptorProvider изменен на «DefaultInterceptorProvider».

class NetworkInterceptorProvider: DefaultInterceptorProvider {
override func interceptors<Operation: GraphQLOperation>(for operation: Operation) -> [ApolloInterceptor] {
    var interceptors = super.interceptors(for: operation)
    interceptors.insert(CustomInterceptor(), at: 0)
    return interceptors
}

}

Другие вопросы по теме