11. Authenticate your operations
In this section you will learn how to add your login authorization token to your operations.
Create the AuthorizationInterceptor
Before you can book a trip, you need to be able to pass your authentication token along to the example server. To do that, let's dig a little deeper into how iOS's ApolloClient works.
The ApolloClient uses something called a NetworkTransport under the hood. By default, the client creates a RequestChainNetworkTransport instance to handle talking over HTTP to your server.
A RequestChain processes your request through a series of specialized interceptor types that handle different aspects of request execution. The RequestChain separates interceptor responsibilities into four discrete types:
GraphQLInterceptor- Handles pre-flight and post-flight work on theGraphQLRequestandGraphQLResponseCacheInterceptor- Handles cache read and write operationsHTTPInterceptor- Handles pre-flight and post-flight work on HTTP requests and responsesResponseParsingInterceptor- Handles parsing of HTTP response data intoGraphQLResponseobjects
The RequestChainNetworkTransport uses an object that conforms to the InterceptorProvider protocol to provide these interceptors for each operation it executes. The DefaultInterceptorProvider provides a standard set of interceptors, but you can create your own InterceptorProvider to customize this behavior.
You can also add your own interceptors to perform custom actions. In this case, you'll add an HTTPInterceptor that adds your authentication token to each request.
First, create the new interceptor. Go to File > New > File... and create a new Swift File. Name it AuthorizationInterceptor.swift, and make sure it's added to the RocketReserver target. Open that file, and add the following code:
1import Foundation
2import Apollo
3import ApolloAPI
4
5struct AuthorizationInterceptor: HTTPInterceptor {
6 func intercept(
7 request: URLRequest,
8 next: NextHTTPInterceptorFunction
9 ) async throws -> HTTPResponse {
10 // TODO
11 }
12}Next, import KeychainSwift at the top of the file so you can access the key you stored in the keychain in the last step of the tutorial:
1import KeychainSwiftThen, replace the TODO within the interceptAsync method with code to get the token from the keychain, and add it to your headers if it exists:
1var request = request
2let keychain = KeychainSwift()
3if let token = await keychain.get(LoginView.loginKeychainKey) {
4 request.addValue(token, forHTTPHeaderField: "Authorization")
5}
6
7return try await next(request)Create a custom interceptor provider
The InterceptorProvider protocol defines four separate methods that provide different types of interceptors for each operation:
graphQLInterceptors(for:)- Returns an array ofGraphQLInterceptorsfor pre-flight and post-flight workcacheInterceptor(for:)- Returns a singleCacheInterceptorfor cache operationshttpInterceptors(for:)- Returns an array ofHTTPInterceptorsfor HTTP request/response handlingresponseParser(for:)- Returns a singleResponseParsingInterceptorfor parsing responses
The DefaultInterceptorProvider uses the protocol's default implementations to provide a standard set of interceptors. To add your custom AuthorizationInterceptor, implement InterceptorProvider and override the httpInterceptors(for:) method to insert your interceptor at the beginning of the interceptor array.
Go to File > New > File... and create a new Swift File. Name it NetworkInterceptorProvider.swift, and make sure it's added to the RocketReserver target. Add code that inserts your AuthorizationInterceptor before the other HTTP interceptors provided by the default implementation:
1import Foundation
2import Apollo
3import ApolloAPI
4
5struct NetworkInterceptorProvider: InterceptorProvider {
6
7 func httpInterceptors<Operation: GraphQLOperation>(for operation: Operation) -> [any HTTPInterceptor] {
8 return [AuthorizationInterceptor()] + DefaultInterceptorProvider.shared.httpInterceptors(for: operation)
9 }
10
11}Use the interceptor
Next, go back to your ApolloClient+Setup.swift class. Replace the implementation of the static ApolloClient var with the following code that creates and uses your new InterceptorProvider:
1static let shared: ApolloClient = {
2 let cache = InMemoryNormalizedCache()
3 let store = ApolloStore(cache: cache)
4 let url = URL(string: "https://apollo-fullstack-tutorial.herokuapp.com/graphql")!
5
6 let networkTransport = RequestChainNetworkTransport(
7 urlSession: URLSession.shared,
8 interceptorProvider: NetworkInterceptorProvider(),
9 store: store,
10 endpointURL: url
11 )
12 return ApolloClient(networkTransport: networkTransport, store: store)
13}()Now, go back to AuthorizationInterceptor.swift.
Click on the line numbers to add a breakpoint at the line where you're instantiating the Keychain:
1let keychain = KeychainSwift()Build and run the application. Whenever a network request goes out, that breakpoint should now get hit. If you're logged in, your token will be sent to the server whenever you make a request!
Now that your operations are being authenticated, it's time to define additional mutations to be able to book and cancel trips.