Wednesday, September 3, 2025

HOW TO: Integrating GraphQL into a SwiftUI App with Apollo iOS

Integrating GraphQL into a SwiftUI App

GraphQL makes it easier to fetch only the data your app needs, and Apollo iOS provides the tools to generate strongly-typed Swift code from your GraphQL schema. Here’s a step-by-step guide to setting up GraphQL in a SwiftUI project.


1. Project Setup

  • Create a GraphQL/ folder in your Xcode project.

  • This folder will hold:

    • schema.graphqls

    • Queries.graphql (and Mutations/Subscriptions if needed)

    • Generated files (API.swift)


2. Install Apollo iOS

  1. In Xcode, go to File → Add Packages…

  2. Add the package:

    https://github.com/apollographql/apollo-ios
  3. Select Apollo and ApolloCodegenLib.


3. Download the Schema

Use the Apollo CLI to download your schema from the GraphQL endpoint:

apollo schema:download --endpoint=https://yourapi/graphql schema.graphqls

4. Define Queries

Create a Queries.graphql file in your GraphQL/ folder. Add operations (queries, mutations, subscriptions):

query GetUser { user { id name } }

5. Code Generation

Add a Build Phase Script in Xcode:

apollo codegen generate \ GraphQL/Queries.graphql \ --schema GraphQL/schema.graphqls \ --output-directory GraphQL/

This generates API.swift with strongly-typed models.


6. Create Apollo Client

Create a Network.swift file for a shared client:

import Apollo class Network { static let shared = Network() private(set) lazy var apollo = ApolloClient(url: URL(string: "https://yourapi/graphql")!) }

7. Build ViewModels

Each feature should have its own ViewModel. Example:

import Foundation class UserViewModel: ObservableObject { @Published var user: GetUserQuery.Data.User? @Published var isLoading = false @Published var errorMessage: String? func loadUser() { isLoading = true Network.shared.apollo.fetch(query: GetUserQuery()) { [weak self] result in DispatchQueue.main.async { self?.isLoading = false switch result { case .success(let graphQLResult): self?.user = graphQLResult.data?.user case .failure(let error): self?.errorMessage = error.localizedDescription } } } } }

8. Connect to SwiftUI Views

Use the ViewModel in your SwiftUI view:

import SwiftUI struct UserView: View { @StateObject private var viewModel = UserViewModel() var body: some View { VStack { if let user = viewModel.user { Text(user.name) } else if viewModel.isLoading { ProgressView() } else if let error = viewModel.errorMessage { Text("Error: \(error)") } } .onAppear { viewModel.loadUser() } } }

9. Mutations (Optional)

You can perform mutations using Apollo:

Network.shared.apollo.perform(mutation: UpdateUserMutation(id: "123", name: "New Name")) { result in // handle response }

10. Async/Await (Optional)

Apollo iOS also supports async/await for cleaner code:

Task { do { let result = try await Network.shared.apollo.fetchAsync(query: GetUserQuery()) self.user = result.data?.user } catch { self.errorMessage = error.localizedDescription } }