Introduction

I previously never had a chance to work with GraphQL. I was excited to learn when to apply this technology, what tools I can use, and how I can implement it. Here’s what I found:

For testing, I used the Star Wars GraphQL API with AllFilmsQuery:

query AllFilmsQuery {
  allFilms {
    films {
      title
      director
      created
      producers
      releaseDate
    }
  }
}

I requested allFilms with title, director, created, producers, and releaseDate information.

When to Apply This Technology

  • The best way to use GraphQL is when you have multiple platform applications such as web, mobile, and TV, and each client needs to request the specific data they require.
  • It’s also beneficial when you need to fetch complex, nested, or related data from multiple sources.

What Tools to Use

Caveats

Before diving into implementation, I would like to highlight a few nuances.

You need to add NetworkInterceptorProvider and AuthorizationInterceptor to authenticate your operations. Without them, you won’t be able to access the data on your server.

How to Implement It

Client

class NetworkInterceptorProvider: DefaultInterceptorProvider {

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

}
class AuthorizationInterceptor: ApolloInterceptor {

    let id: String = UUID().uuidString

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

}
private let 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://swapi-graphql.netlify.app/.netlify/functions/index")!
    let transport = RequestChainNetworkTransport(interceptorProvider: provider, endpointURL: url)
    return ApolloClient(networkTransport: transport, store: store)
}()

UI

import SwiftUI
import Apollo
import StarWarsAPI

struct ContentView: View {

    @State private var list: [AllFilmsQuery.Data.AllFilms.Film?] = []

    var body: some View {
        VStack {
            ForEach(list, id: \.self) { row in
                Text(row?.title ?? "")
            }
        }.onAppear(perform: {
            apollo.fetch(query: AllFilmsQuery()) { result in
                switch result {
                case .success(let response):
                    self.list = response.data?.allFilms?.films ?? []
                case .failure(let error):
                    print(error)
                }
            }
        })
        .padding()
    }
    
}

#Preview {
    ContentView()
}

References

Thank you for reading! 😊