GraphQL Using the Apollo Framework: Getting Started

In this Apollo Framework for iOS tutorial, you will learn how to consume GraphQL APIs in a simple and type-safe way. By Felipe Laso-Marsetti.

4.2 (29) · 7 Reviews

Download materials
Save for later
Share
You are currently viewing page 2 of 4 of this article. Click here to view the first page.

Adding a Code Generator Script

Apollo requires a GraphQL schema file to generate the code. This schema is a JSON file that contains information from an introspection query. The schema describes the types and fields you can query. It also includes any relationships between those types. The file is usually called schema.json. You can find it inside the Jedi Archives folder of your project.

Now you need to add the script that will generate the code for your queries. Select your project in the Project navigator. Then select the Jedi Archives target, and click Build Phases:

Build Phases Project Tab

Click the + button and select New Run Script Phase.

Adding New Run Script

Paste the following script into the window to let Apollo work its code-gen magic:

# Go to the build root and search up the chain to find the 
# Derived Data Path where the source packages are checked out.
DERIVED_DATA_CANDIDATE="${BUILD_ROOT}"

while ! [ -d "${DERIVED_DATA_CANDIDATE}/SourcePackages" ]; do
  if [ "${DERIVED_DATA_CANDIDATE}" = / ]; then
    echo >&2 "error: Unable to locate SourcePackages directory from BUILD_ROOT: '${BUILD_ROOT}'"
    exit 1
  fi

  DERIVED_DATA_CANDIDATE="$(dirname "${DERIVED_DATA_CANDIDATE}")"
done

# Grab a reference to the directory where scripts are checked out
SCRIPT_PATH="${DERIVED_DATA_CANDIDATE}/SourcePackages/checkouts/apollo-ios/scripts"

if [ -z "${SCRIPT_PATH}" ]; then
    echo >&2 "error: Couldn't find the CLI script in your checked out SPM packages; make sure to add the framework to your project."
    exit 1
fi

cd "${SRCROOT}/${TARGET_NAME}"
"${SCRIPT_PATH}"/run-bundled-codegen.sh codegen:generate --target=swift --includes=./**/*.graphql --localSchemaFile="schema.json" GraphQL/API.swift

This script sets up all the environment variables needed by Apollo’s code generator. It then launches the code generator, using schema.json as a reference to generate the code. The generated code will be saved in API.swift.

Note: You can change the file where Apollo generates the API or the path to your schema. To do this, just modify the last line of the script to point to the desired location.

Now, click the title of your new build phase, and rename it to Generate Apollo GraphQL API. Then, drag and drop it below the Dependencies build phase. This is what your build phases will look like after that:

Final Build Phases

If you try to build your project right now, you’ll get an error. This is because you haven’t written any GraphQL queries, and the script will fail. You’ll take care of that in the next step!

Populating the Films Screen

Now it’s time to write your GraphQL queries. But how do you know what to write? How do you even know what a GraphQL query can do? Fortunately, the SWAPI GraphQL wrapper has a cool GraphQL playground. You can use this playground to experiment all you want with GraphQL queries!

Writing Your Query Definition

You’re going to write a query to retrieve data for all the Star Wars films. You need the film names and information associated with each film. And you need the characters in those films.

Open Queries.graphql and paste the following queries:

# 1
query AllFilms {
  # 2
  allFilms {
    # 3
    films {
      # 4
      id
      director
      episodeID
      title
      releaseDate
      
      #5
      characterConnection(first: 10) {
        # 6
        characters {
          # 7
          id
          name
          birthYear
          eyeColor
          hairColor
          
          # 8
          homeworld {
            # 9
            name
          }
        }
      }
    }
  }
}

Here’s what you’re doing in this code:

  1. You define a query called AllFilms. The query will fetch the desired films along with information about them.
  2. You specify that you want all the films available.
  3. For each film within your collection, what attributes and values do you want to get? This is how you define the scope of data to fetch for an individual film.
  4. You want the ID, director, episode ID, title, and release date for each film.
  5. For an individual film, you also want to fetch the first ten characters associated with it.
  6. For each character, you specify what information to retrieve.
  7. You want the ID, name, birth year, eye color, and hair color of each character.
  8. You also want the homeworld for the character.
  9. And, for that homeworld, you need its name.

As you can see, it looks a bit Swift-y or JSON-y. Feel free to experiment with the GraphQL playground for SWAPI. Add or remove things in the query, run it, and check out the results.

Build and run. Now API.swift contains some generated models and the Swift API!

Open API.swift, but don’t modify it. This is the generated code and models your app will use. Feel free to look at the code and see what Apollo generated for you. The most important are these:

  • AllFilmsQuery: This is the query class you’ll use to access the server data.
  • Film: This structure contains the data for every movie. It includes the fields you specified in the query file generated by Apollo.
  • Character: This structure contains the character information. It has the properties you defined in the query.

You’ll use the data structures in the API to display the movie information in the app. But first, you need to implement the network client so that you can retrieve your data.

Implementing Your Network Client

Open Apollo.swift and add an import for the Apollo framework at the top of the file:

import Apollo

Then, add the following code inside Apollo:

// 1
static let shared = Apollo()
// 2
let client: ApolloClient
// 3
init() {
  client = ApolloClient(url: URL(string: "http://localhost:49241")!)
}

This is what your code does:

  1. You define Apollo as a singleton, since you only want one instance of the Apollo client for the app.
  2. You define a property to store the actual ApolloClient provided by the Apollo Framework.
  3. You instantiate a new ApolloClient with the location of your GraphQL server. You’ll need to replace 49241 with your local server port. This is the port your local GraphQL server returned after you ran the yarn start command, above.
Note: The project has App Transport Security settings modified to permit plain HTTP calls to localhost.

Now you’re ready to start working with Star Wars data!

Retrieving Films Data

Switch to FilmsViewController.swift. Replace the whole line where you declare the films property with the following:

var films: [AllFilmsQuery.Data.AllFilm.Film] = []

Here you change films from an array of strings to an array of Film objects. Apollo automatically generated that structure from the information in the queries file. Notice how Film resides inside AllFilmsQuery, within its Data and AllFilm structures.

Moving on, add the following code inside loadData():

// 1
let query = AllFilmsQuery()
// 2
Apollo.shared.client.fetch(query: query) { result in
  // 3
  switch result {
  case .success(let graphQLResult):
    if let films = graphQLResult.data?.allFilms?.films?.compactMap({ $0 }) {
      // 4          
      self.films = films
      self.tableView.reloadData()
    }
        
  case .failure(let error):
    // 5
    print("Error loading data \(error)")
  }
}

In this code, you do the following:

  1. First, you create an AllFilmsQuery object.
  2. Then you use the Apollo client you created earlier to fetch the data. You use the AllFilmsQuery query to do this.
  3. In the closure, you check whether the query succeeded or failed.
  4. If the query succeeded, you retrieve the result list into films.
  5. If the query failed, you print an error to the console so you can find out what went wrong.

Next, you’ll display your data in the main table view.