Hy I am working in a project with Apollo GraphQL
method and its working fine. But now the client required for adding additional header with Apollo API’s. But after adding the header the API’s response return as unAuthorized.
I am adding the header as,
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: "https://xxx/graphql")!
return ApolloClient(networkTransport: HTTPNetworkTransport(url: url, configuration: configuration))
}()
Anyone please help me to find out how to add headers with Apollo GraphQL.
3
8 Answers
UPDATE: Solution for "Apollo Client v0.41.0" and "Swift 5"
I had the same issue with Apollo Client v0.41.0 and Swift 5.0 but none of the above solutions worked. Finally able to find a solution after the hours of try-out. The below solution is tested with Apollo Client v0.41.0 And 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)
}
}
7
-
Thanks! This is the only solution that works with Apollo 0.42.0
– Jochen HolzerApr 22, 2021 at 15:16
-
@Chamath Jeevan I have tried this solution with Apollo 0.43.0 version and it gives me failure reposne error as failure(Apollo.LegacyParsingInterceptor.LegacyParsingError.couldNotParseToLegacyJSON(data: 1839 bytes)) please suggest me what can I do further
– PrincessApr 29, 2021 at 11:01
-
@JochenHolzer I too have tried the same code syntax but the request gives me HTML in failure block. Could you please help me to solve this issue Apollo GraphQL header always gives failure in iOS Swift
– PrincessMay 3, 2021 at 6:08
-
1
@Princess Perhaps there is an error message in the HTML response. If I were you, I would ask the endpoint development team what information about your failed request is in the server log files.
– Jochen HolzerMay 3, 2021 at 12:26
-
@JochenHolzer I am using a Shopify GraphQL Admin API to fetch customer's order details from the Shopify store. The same URL request working with Android Apollo Client.
– PrincessMay 4, 2021 at 4:41
As of Apollo Client v0.34.0 and above the code provided earlier won’t work since they rewrote how it used to work. Here is what worked for me… For more information consider going through this documentation in the link here.
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)
}
}
1
-
1
What a nightmare API!
NetworkInterceptorProvider: LegacyInterceptorProvider
!– SmileBotMar 1, 2022 at 20:50
Finally I found the answer. Add the header in the following way,
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: "https://xxxx/graphql")!
return ApolloClient(networkTransport: HTTPNetworkTransport(url: url, configuration: configuration))
}()
Hope it will help someone.
1
-
5
it stops working from version 0.34, there is no HTTPNetworkTransport anymore
– QuangLocNov 10, 2020 at 9:46
The accepted solution is now outdated as the HTTPNetworkTransport no longer takes in a configuration argument, instead accepting a URLSession
directly rather than a URLSessionConfiguration
Here’s an example how to send an authorization header on every request to Apollo Client, retrieving it, if found, from UserDefaults in version 0.21.0
of Apollo Client(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: "https://localhost:4000/graphql")!
let configuration = URLSessionConfiguration.default
configuration.httpAdditionalHeaders = ["authorization": "Bearer (token)"]
return ApolloClient(
networkTransport: HTTPNetworkTransport(url: url, session: URLSession(configuration: configuration))
)
}()
}
0
UPDATE: This solution is deprecated after "Apollo Client v0.34.0"
The previous answers are old, this is now done through a delegate:
"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
}
}
Here’s a link to the documentation for more details:
3
-
Am getting this errors
Cannot find type 'HTTPNetworkTransport' in scope
andCannot find type 'HTTPNetworkTransportPreflightDelegate' in scope
any help? Am using Appoloclient v0.34.1.– G BOct 10, 2020 at 1:59
-
@GB I checked out the docs in the link above, and they have deprecated HTPPNetworkTransport. This can still be done using "LegacyInterceptorProvider", or you could look into the new protocol: NetworkTransport".
– jsonkuanOct 12, 2020 at 9:18
-
I provided a solution you can have a look at it.
– G BOct 12, 2020 at 14:33
Import these two elements
import UIKit
import Apollo
Create a class Network and paste below source code
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: "https://xxx/graphql")!
let requestChainTransport = RequestChainNetworkTransport(interceptorProvider: provider,
endpointURL: url)
return ApolloClient(networkTransport: requestChainTransport,
store: store1)
}()
}
add NetworkInterceptorProvider in Network class
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
}
}
add CustomInterceptor also in Network class
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)
}
}
finally call this method from 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)")
}
}
}
1
-
For me this isn't working I have asked a new question Apollo GraphQL header always gives failure in iOS Swift please check this.
– PrincessMay 3, 2021 at 6:05
NetworkInterceptorProvider: LegacyInterceptorProvider changed as a "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
}
}
0
Updated solution for Apollo 1.6.1
import Foundation
import Apollo
class DataCoordinator: NSObject {
// MARK: Variables
static let shared: DataCoordinator = DataCoordinator()
private(set) lazy var apolloClient: ApolloClient = {
let cache = InMemoryNormalizedCache()
let store = ApolloStore(cache: cache)
let authPayloads = ["Authorization": "Bearer (token)"]
let configuration = URLSessionConfiguration.default
configuration.httpAdditionalHeaders = authPayloads
let client = URLSessionClient(sessionConfiguration: configuration, callbackQueue: nil)
let provider = NetworkInterceptorProvider(store: store, client: client)
let url = URL(string: "https://xxxxxxxxx/graphql")!
let requestChainTransport = RequestChainNetworkTransport(interceptorProvider: provider, endpointURL: url)
return ApolloClient(networkTransport: requestChainTransport, store: store)
}()
}
struct NetworkInterceptorProvider: InterceptorProvider {
// These properties will remain the same throughout the life of the `InterceptorProvider`, even though they
// will be handed to different interceptors.
private let store: ApolloStore
private let client: URLSessionClient
init(store: ApolloStore,
client: URLSessionClient) {
self.store = store
self.client = client
}
func interceptors<Operation>(for operation: Operation) -> [ApolloInterceptor] {
return [
MaxRetryInterceptor(),
CacheReadInterceptor(store: self.store),
NetworkFetchInterceptor(client: self.client),
ResponseCodeInterceptor(),
JSONResponseParsingInterceptor(),
AutomaticPersistedQueryInterceptor(),
CacheWriteInterceptor(store: self.store)
]
}
}
Happy Coding …
Did you try to set the header to "Bearer <token>" instead of "<token>"? What's the authorization method your server is using? Do you have a working cURL statement against the server that uses an authorization token?
Apr 1, 2019 at 13:49
did you find any solution?
Apr 29, 2019 at 12:01
Please refer my answer.
Apr 29, 2019 at 12:08