Structuring a GraphQL application with the Apollo iOS SDK
Apollo iOS 1.0 can support complex applications composed of multiple modules and monolithic application targets.
The code generation engine and modularized structure of the Apollo iOS SDK provide flexible configuration options, enabling you to structure your project as you like.
This article covers the models generated by Apollo iOS, the modules that compose the Apollo iOS SDK, and how to structure these components in your project.
Apollo iOS generates the following groups of files for you:
- Operation models: Models for the queries, mutations, subscriptions, and fragments defined in your GraphQL files.
- Schema types: Your GraphQL schema's shared types and metadata (e.g., objects, enums, input objects).
- Test mocks: Test mock objects for your schema types, which you can use to create operation models in your tests.
Apollo iOS generates operation models from the files where you define your GraphQL operations (i.e., queries, mutations, subscriptions, and fragments).
Operation models are classes that represent your GraphQL operations, which you can then use to make GraphQL requests (via
Each operation model includes a set of type-safe response model objects, representing that operation's result. When
ApolloClient successfully executes a GraphQL request, it returns an instance of the corresponding response model for the executed operation.
To learn more about GraphQL operations, check out Defining operations.
GraphQL schemas use a type system to define the shape of your available data. GraphQL operations (and your generated operation models) depend on a schema to know how to shape their operations to access a server's data.
Apollo iOS generates a collection of types that provide the properties and metadata about each type in your GraphQL schema (i.e., objects, interfaces, unions, enums, input objects, etc.). Your generated operation models reference these shared schema types to provide type information without duplicating code.
Apollo iOS enables you to generate test mock objects that you can use in your test targets. These mocks enable you to create operation models for your tests.
For more details, see Test Mocks.
When including Apollo iOS in a new project, deciding how to structure your project is an essential first step. A large part of this step is determining where your generated GraphQL models fit.
You can include your GraphQL models in your main application target, spread them across many modules, or expose them as an independent module that multiple applications can use. Depending on the needs and constraints of your project, you'll configure the code generation engine and link to the Apollo iOS libraries differently.
Below, we cover the three primary decisions you'll need to make about your project structure.
1. Does your project consist of a single application target or multiple modules?
Depending on the size and complexity of your project, it might be built as a single monolithic application target or be composed of multiple modules.
For more information about the libraries that make up the Apollo iOS SDK, see the Apollo iOS SDK.
To include the Apollo iOS SDK in a project with multiple modules:
Apolloto the modules configuring or using the networking and caching APIs.
- Optionally, link
ApolloWebSocketto the module that sets up your
ApolloClientto enable them.
- Optionally, link
ApolloAPIto the modules that only include generated models.
Additionally, you can optionally link
ApolloTestSupport to your unit test target to create mocks of your generated models.
⚠️ Do not link
ApolloCodegenLib to your application targets.
ApolloCodegenLib only supports macOS, and you should only link it to development tools that want to use the Apollo code generation engine.
2. How do you want to include your generated schema types?
You can include generated schema types in your project by embedding them directly in your application target or as a separate module. You can configure this using the
output.schemaTypes property in your codegen configuration.
When setting up codegen for the first time, you'll need to specify a location path for the generated module and the
moduleType property configures how the code generation engine links generated schema types in your project.
For most projects, we recommend creating a separate schema module. This enables you to share your generated models across modules as your project grows. For simple single-target applications, you can embed your schema types directly in your target.
You can link a schema module to every module that includes or consumes your generated operation models.
The code generation engine can automate the creation of schema modules for the Swift Package Manager. The code generation engine is also flexible enough to support manual configuration for projects that require customized dependencies.
Most dependency managers (e.g., SPM and Cocoapods) can automatically include your generated files in the module's directory. This means that when generated files are added or removed from the generated module, they are linked to your project automatically.
You can also include schema types directly in a target that you created.
To do this, use
ModuleType.embeddedInTarget(name: String) as the value of the
output.schemaTypes.moduleType property. The generated schema types are scoped within a caseless enum used as a namespace to prevent conflicts with types you may already have defined in your target.
If you require more control over your schema types you can use the
ModuleType.other value. This gives you full control over the module and your choice of dependency manager.
These options makes you responsible for manually adding generated files to your chosen target or module. When the code generation engine creates or removes files, you'll need to manually add or remove them from the project navigator.
3. Where should your generated operation models live?
Finally, choose how you want to use operation models in your project. You can configure this using the
output.operations property in your codegen configuration.
The only requirements are that your operation models have access to your schema types and the
ApolloAPI target to compile successfully.
If you want to organize your generated models by specific feature areas or modules, use the
OperationsFileOutput.relative(subpath: String?) value for the
output.operations property. The code generation engine now generates your operation models relative to the
.graphql files that define them.
This option gives you the most flexibility and control over your operation models. You can generate them anywhere in your project structure by organizing your
.graphql operation definitions.
With relative paths, you can:
- Co-locate models alongside the feature code using them
- Include models in different modules across your project
- Organize models based on feature area
- Or use any other structure your project needs
You can also share your generated operation models across modules in your project. You can do this by including them within the shared schema types module or by manually including them in another shared module.
For most small projects, including your operation models within the shared schema type module is the most straightforward way to share them. With this structure, your operation models are in a sub-folder of the schema types module directory.
- If you have a schema module, the codegen engine includes your operations in that module, which you can then import into your project's other modules.
- If you are embedding your schema in another target, the codegen engine includes your operations in the generated schema namespace in your application target.
You can also generate your operation models into a single directory using the
.absolute(path:) option. Then, you can manually include this directory in your project however you see fit.
If you choose to generate the operation models to an absolute path, you are responsible for linking the generated files to the rest of your project. You must ensure that any targets included by your operation models link to both your schema types module and the
Above, we've shared the most common examples of modular architecture, but there are many alternative configurations we haven't covered.
Apollo iOS has different options to support flexible configurations of your schema types and operation models. We recommend familiarizing yourself with Apollo iOS's codegen configuration to find a combination that best suits your project needs.
For Cocoapods users:
Cocoapods combines subspecs into a single target. This means that:
Libraries that compose the Apollo iOS package:
The core Apollo client library.
Includes the networking and caching APIs, including
Any targets that need to access these core components directly should be linked against
Includes the common components that generated models use for your project.
Any targets that include your generated models should be linked to
Because generated models export the
Use this library if you'd like to persist cache data across application lifecycles. This library only needs to be linked to your targets that configure the
For more information on setting up a persistent SQLite cache, see
Provides a web socket transport implementation that supports
If your project uses GraphQL subscriptions, you must include this library. This library only needs to be linked to your targets that configure the
For more information, see Enabling GraphQL subscription support.
Includes the APIs for creating test mocks for your generated models
Link this library to unit test targets that need to create mocks of generated models.
Includes the code generation engine for generating GraphQL models.
For most projects, we strongly recommend using the Codegen CLI instead of using
Use this library if you want to run the code generation engine from your own Swift executable targets.
Link this library to development tools that want to use the Apollo code generation engine. This library only supports macOS.