Get started with Apollo iOS codegen


This short tutorial guides you through the basic concepts of generating Swift code with Apollo iOS. We'll introduce you the core capabilities of code generation, and walk through the process of generating Swift code using a GraphQL schema and GraphQL operations.

For more in-depth details, see Code generation.

Step 1: Project Setup

Start by creating a new directory, and navigating into it:

shell
1mkdir ios-code-gen-example
2cd ios-code-gen-example

Step 2: Download a GraphQL schema

We'll use the StarWars GraphQL API for this example. You can check this schema out using Apollo Studio.

Where to download a schema from Apollo Studio

On the right-hand side in Apollo Studio find the drop-down to download the schema, shown in the above screenshot. Apollo Studio supports both JSON or Raw formats. For this tutorial select Raw which downloads the GraphQL schema in the Schema Definition Language (SDL) format.

Clicking Raw will download a file named star-wars-swapi@current.graphql.

Step 3: Move the downloaded schema into your project

Download or move the already downloaded star-wars-swapi@current.graphql file into the directory you created in Step 1.

Rename the file extension from .graphql to .graphqls. Note the s on the end signifying a GraphQL schema file.

Step 4: Create a GraphQL operation

You'll also need to create a GraphQL operation file because the code generation engine requires both a schema and at least one operation to generate code.

We'll be using the allFilms Query operation as an example. Clicking this link will open Explorer in Apollo Studio where you can select the fields you would like to be fetched. Alternatively, the query text below already has fields selected.

Copy the query text and create a new file named AllFilmsQuery.graphql in the directory you created in Step 1. Paste this query into the new file.

GraphQL
1query Query {
2  allFilms {
3    films {
4      title
5      director
6      releaseDate
7      speciesConnection {
8        species {
9          name
10          classification
11          homeworld {
12            name
13          }
14        }
15      }
16    }
17  }
18}

Step 5: Download the CLI

Browse to the list of Apollo iOS releases in GitHub and find the latest release. In the Assets list for each release will be a pre-built CLI binary called apollo-ios-cli.tar.gz

Download and unzip this file then move the apollo-ios-cli binary file into the directory you created in Step 1.

For more information on the different ways to install the CLI, see the codegen CLI documentation.

Step 6: Create a codegen configuration

Run the following command:

Bash
1./apollo-ios-cli init --schema-namespace StarWarsAPI --module-type swiftPackageManager

The CLI will create a configuration file named apollo-codegen-configuration.json, pre-filled with default values. The file should look similar to this:

JSON
1{
2  "schemaNamespace": "StarWarsAPI",
3  "input": {
4    "operationSearchPaths": ["**/*.graphql"],
5    "schemaSearchPaths": ["**/*.graphqls"]
6  },
7  "output": {
8    "testMocks": {
9      "none": {}
10    },
11    "schemaTypes": {
12      "path": "./StarWarsAPI",
13      "moduleType": {
14        "swiftPackageManager": {}
15      }
16    },
17    "operations": {
18      "inSchemaModule": {}
19    }
20  }
21}

Step 7: Generate code

Now you are ready to generate some code! Run the following command:

Bash
1./apollo-ios-cli generate

You should see a new file created at StarWarsAPI/Sources/Operations/Queries/Query.graphql.swift, that looks similar to this:

Generated Code
Swift
1
2// @generated
3// This file was automatically generated and should not be edited.
4
5@_exported import ApolloAPI
6import StarWarsAPI
7
8public class Query: GraphQLQuery {
9  public static let operationName: String = "Query"
10  public static let document: DocumentType = .notPersisted(
11    definition: .init(
12      """
13      query Query {
14        allFilms {
15          __typename
16          films {
17            __typename
18            title
19            director
20            releaseDate
21            speciesConnection {
22              __typename
23              species {
24                __typename
25                name
26                classification
27                homeworld {
28                  __typename
29                  name
30                }
31              }
32            }
33          }
34        }
35      }
36      """
37    ))
38
39  public init() {}
40
41  public struct Data: StarWarsAPI.SelectionSet {
42    public let __data: DataDict
43    public init(data: DataDict) { __data = data }
44
45    public static var __parentType: ParentType { StarWarsAPI.Objects.Root }
46    public static var __selections: [Selection] { [
47      .field("allFilms", AllFilms?.self),
48    ] }
49
50    public var allFilms: AllFilms? { __data["allFilms"] }
51
52    /// AllFilms
53    ///
54    /// Parent Type: `FilmsConnection`
55    public struct AllFilms: StarWarsAPI.SelectionSet {
56      public let __data: DataDict
57      public init(data: DataDict) { __data = data }
58
59      public static var __parentType: ParentType { StarWarsAPI.Objects.FilmsConnection }
60      public static var __selections: [Selection] { [
61        .field("films", [Film?]?.self),
62      ] }
63
64      /// A list of all of the objects returned in the connection. This is a convenience
65      /// field provided for quickly exploring the API; rather than querying for
66      /// "{ edges { node } }" when no edge data is needed, this field can be be used
67      /// instead. Note that when clients like Relay need to fetch the "cursor" field on
68      /// the edge to enable efficient pagination, this shortcut cannot be used, and the
69      /// full "{ edges { node } }" version should be used instead.
70      public var films: [Film?]? { __data["films"] }
71
72      /// AllFilms.Film
73      ///
74      /// Parent Type: `Film`
75      public struct Film: StarWarsAPI.SelectionSet {
76        public let __data: DataDict
77        public init(data: DataDict) { __data = data }
78
79        public static var __parentType: ParentType { StarWarsAPI.Objects.Film }
80        public static var __selections: [Selection] { [
81          .field("title", String?.self),
82          .field("director", String?.self),
83          .field("releaseDate", String?.self),
84          .field("speciesConnection", SpeciesConnection?.self),
85        ] }
86
87        /// The title of this film.
88        public var title: String? { __data["title"] }
89        /// The name of the director of this film.
90        public var director: String? { __data["director"] }
91        /// The ISO 8601 date format of film release at original creator country.
92        public var releaseDate: String? { __data["releaseDate"] }
93        public var speciesConnection: SpeciesConnection? { __data["speciesConnection"] }
94
95        /// AllFilms.Film.SpeciesConnection
96        ///
97        /// Parent Type: `FilmSpeciesConnection`
98        public struct SpeciesConnection: StarWarsAPI.SelectionSet {
99          public let __data: DataDict
100          public init(data: DataDict) { __data = data }
101
102          public static var __parentType: ParentType { StarWarsAPI.Objects.FilmSpeciesConnection }
103          public static var __selections: [Selection] { [
104            .field("species", [Specy?]?.self),
105          ] }
106
107          /// A list of all of the objects returned in the connection. This is a convenience
108          /// field provided for quickly exploring the API; rather than querying for
109          /// "{ edges { node } }" when no edge data is needed, this field can be be used
110          /// instead. Note that when clients like Relay need to fetch the "cursor" field on
111          /// the edge to enable efficient pagination, this shortcut cannot be used, and the
112          /// full "{ edges { node } }" version should be used instead.
113          public var species: [Specy?]? { __data["species"] }
114
115          /// AllFilms.Film.SpeciesConnection.Specy
116          ///
117          /// Parent Type: `Species`
118          public struct Specy: StarWarsAPI.SelectionSet {
119            public let __data: DataDict
120            public init(data: DataDict) { __data = data }
121
122            public static var __parentType: ParentType { StarWarsAPI.Objects.Species }
123            public static var __selections: [Selection] { [
124              .field("name", String?.self),
125              .field("classification", String?.self),
126              .field("homeworld", Homeworld?.self),
127            ] }
128
129            /// The name of this species.
130            public var name: String? { __data["name"] }
131            /// The classification of this species, such as "mammal" or "reptile".
132            public var classification: String? { __data["classification"] }
133            /// A planet that this species originates from.
134            public var homeworld: Homeworld? { __data["homeworld"] }
135
136            /// AllFilms.Film.SpeciesConnection.Specy.Homeworld
137            ///
138            /// Parent Type: `Planet`
139            public struct Homeworld: StarWarsAPI.SelectionSet {
140              public let __data: DataDict
141              public init(data: DataDict) { __data = data }
142
143              public static var __parentType: ParentType { StarWarsAPI.Objects.Planet }
144              public static var __selections: [Selection] { [
145                .field("name", String?.self),
146              ] }
147
148              /// The name of this planet.
149              public var name: String? { __data["name"] }
150            }
151          }
152        }
153      }
154    }
155  }
156}

And that's it! You can also review all the additional generated files to get a deeper understanding of how code generation works using the Apollo iOS client.

Feedback

Edit on GitHub

Forums