Releases: apollographql/apollo-ios
2.0.0 Beta 2
Fixed
- Input Variable Lists & Custom Scalars(#742): Compilation errors for custom scalars and input variables that were list types have been fixed.
2.0.0 Beta 1
This is the first beta release of Apollo iOS 2.0 This release contains some APIs that are still in development and are subject to change prior to general release.
New
- Narrowly Scoped
SelectionSet
Equality (#736): Generated models now implementEquatable
andHashable
using only the relevant fields for the model. This means that named fragments that do not have access to fields from the parent operation that fetched them will be equal if only the fields the fragment can access are equal.
Changed
-
Remove Cocoapods Support (#723): Apollo iOS 2.0 will no longer support Cocoapods. While support was carried over in the alpha releases, this has been officially removed in beta 1.
-
Only Input Variables use
Int32
in generated models (#729): Generated models in alpha-2 generatedInt
asInt32
to more safely represent GraphQL spec compliant data. This made using the models much more cumbersome. Beta 1 changes this behavior so only input variables that may be sent to a GraphQL server useInt32
.
Fixed
- Fix nullable list of nullable items in
InputObject
(#730): Fixed a bug when generating a nullable list of nullable items on anInputObject
.
Apollo iOS 2.0.0 Alpha 2
This is the an alpha stage preview release of Apollo iOS 2.0. This preview release contains APIs that are still in development and are subject to change prior to stable release.
This version is likely to contain bugs and some features are still limited. This preview is intended to allow interested users to test out the new APIs and provide feedback to help shape the final product.
Feedback
We are looking for bug reports as well as use cases that may not be supported by the current APIs. Any general feedback on the project is welcome as well. Bug reports can be filed as GitHub issues. For feature requests and general feedback, please comment on the #3411.
Changes
Default type for integers changed to Int32
The generated models will now represent Integers using Int32
instead of Int
. The GraphQL spec specifically states that Int
is a 32-bit integer, so this aligns us more correctly with the specification.
The impact of this change on the usability of the generated models is unclear at this time. We are seeking feedback on if this change is too much of an issue for users. While we would like to keep this new behavior, if user feedback is negative, this may be reverted or made into an optional behavior based on a codegen configuration option.
All sub-projects updated to Swift 6
The codegen engine, apollo-ios-cli, pagination library, unit tests and other development projects have all been updated to Swift 6 with strict concurrency enabled.
Apollo iOS 2.0.0 Alpha 1 - First Preview Release
This is the first preview release of Apollo iOS 2.0. This preview release contains APIs that are still in development and are subject to change prior to stable release.
This version is likely to contain bugs and some features are still limited. This preview is intended to allow interested users to test out the new APIs and provide feedback to help shape the final product.
Feedback
We are looking for bug reports as well as use cases that may not be supported by the current APIs. Any general feedback on the project is welcome as well. Bug reports can be filed as GitHub issues. For feature requests and general feedback, please comment on the 2.0 RFC Megathread.
Web Socket & Pagination Support Not Included
Support for web sockets is not included in this preview release and will be implemented in a future release after 2.0.0. In the interim, WebSocketNetworkTransport
has been temporarily replaced with a stubbed type that throws an error. Subscriptions are still supported over HTTP via the RequestChainNetworkTransport
.
Support for pagination using the ApolloPagination
package is not included in this preview release and will be implemented prior to the first Beta release.
Installation
This preview is available now under the tag 2.0.0-alpha-1
. To try out the alpha, modify your SPM dependency to:
.package(
url: "https://github.com/apollographql/apollo-io.git", Version(2, 0, 0, prereleaseIdentifiers: ["alpha"]),
Temporary Deprecations
Many of the existing APIs from Apollo iOS 1.0 have been marked as deprecated, with only the minimal necessary modifications to compile Apollo iOS 2.0. These APIs are untested with the new underlying infrastructure and may not be reliable. All deprecated APIs will be removed prior to the stable release of 2.0. These APIs still exist only to aid users in the migration to the new APIs. By deprecating these APIs instead of just removing them, we hope that it will make it easier to incrementally migrate your codebase to Apollo iOS 2.0.
Key Changes
Apollo iOS 2.0 reimagines many of the APIs to take full advantage of the new Swift concurrency model. This is a non-exhaustive list of the key changes:
ApolloClient
& CachePolicy
The APIs of ApolloClient
have changed significantly to use async/await
. Rather than providing a resultHandler
closure that may be called one or more times, separate APIs are defined depending on if an operation expects single/multiple responses. CachePolicy
has been broken up into multiple types that will automatically force the function with the correct return signature.
// Single response
let response = try await client.fetch(query: query, cachePolicy: .cacheFirst)
let response = try await client.fetch(query: query, cachePolicy: .networkFirst)
let response = try await client.fetch(query: query, cachePolicy: .networkOnly)
// Single response with Optional return value
let response = try await client.fetch(query: query, cachePolicy: .cacheOnly)
// Multiple responses
// Returns an AsyncThrowingStream<GraphQLResponse<Query>, any Swift.Error>
let responses = try client.fetch(query: query, cachePolicy: .cacheAndNetwork)
Task {
for try await response in responses {
// Handle response
}
}
Subscriptions and operations that provide incremental data (via the @defer
directive and in the future @stream
), will always return an AsyncThrowingStream<GraphQLResponse<Query>, any Swift.Error>
of responses unless using the .cacheOnly
policy.
let responses = try client.fetch(query: deferQuery, cachePolicy: .cacheFirst) // -> AsyncThrowingStream
let responses = try client.fetch(query: deferQuery, cachePolicy: .networkFirst) // -> AsyncThrowingStream
let responses = try client.fetch(query: deferQuery, cachePolicy: .networkOnly) // -> AsyncThrowingStream
let responses = try client.fetch(query: deferQuery, cachePolicy: .cacheAndNetwork)
Task {
for try await response in responses {
// Handle response
}
}
let response = try await client.fetch(query: deferQuery, cachePolicy: .cacheOnly) // async throws -> GraphQLResponse<DeferQuery>?
The for try await response in responses
loop will continue to run until the operation is complete. For subscriptions, this may be indefinite. For this reason, the returned stream should be consumed within a Task
.
Sendable
Types
In order to support the new Swift concurrency model, most of the types in Apollo iOS have been made Sendable
. In order to make these types Sendable
, some limitations were necessary.
- Some fields that were mutable
var
properties have been converted to constantlet
properties. We don't believe this should prevent users from accessing any necessary functionality, but we are seeking feedback on the effect this change has on your usage. - Public
open
classes have been changed tofinal
classes or structs. This prevents subclassing types such asRequestChainNetworkTransport
,InterceptorProvider
,JSONRequest
, and others. If you are currently subclassing these types, you will need to convert your existing subclasses to wrappers that wrap these types and passthrough calls to them instead.
New Request Interceptor Framework
The RequestChain
and interceptor framework has been completely reimagined. The new version supports async/await
and provides the ability to interact with the request at each step within the chain more safely with more explicit APIs.
If you are providing your own custom InterceptorProvider
with your own interceptors, you will need to modify your code to utilize these new APIs.
The singular ApolloInterceptor
that was used to handle any step of the request chain has been broken up into discrete interceptor types for different portions of request execution. Additionally, requests are sent down the request chain pre-flight and then back up the chain post-flight, allowing each interceptors to interact with the both the request and response in a type-safe way.
Interceptors Types
ApolloInterceptor
has been separated into 4 different interceptor types.
GraphQLInterceptor
- Can inspect and mutate the
GraphQLRequest
andGraphQLResponse
- Can inspect and mutate the
HTTPInterceptor
- Can inspect and mutate the
URLRequest
- After network response can inspect the
HTTPURLResponse
(readonly) and mutate the actual raw responseData
prior to parsing
- Can inspect and mutate the
CacheInterceptor
- Handles read/write of cache data
- Read currently runs before
GraphQLInterceptors
(not sure if that is the desired behavior, we should discuss) - Write runs after parsing
ResponseParsingInterceptor
- Handles the parsing of the response Data into the
GraphQLResponse
- Handles the parsing of the response Data into the
NetworkFetchInterceptor
is no longer used, as the network fetch is managed by the ApolloURLSession
. See the section on ApolloURLSession
for more information.
Request Chain Flow
Requests are now processed by the RequestChain
using the following flow:
GraphQLInterceptors
receive and may mutateRequest
- Cache read executed via
CacheInterceptor
if necessary (based on cache policy) GraphQLRequest.toURLRequest()
called to obtainURLRequest
HTTPInterceptors
receive and may mutateURLRequest
ApolloURLSession
handles networking withURLRequest
HTTPInterceptors
receive stream ofHTTPResponse
objects for each chunk & may mutate raw chunkData
streamResponseParsingInterceptor
receivesHTTPResponse
and parses data chunks into stream ofGraphQLResponse
GraphQLInterceptors
receive and may mutateGraphQLResponse
with parsedGraphQLResult
and (possibly) cache records.- Cache write executed via
CacheInterceptor
if necessary (based on cache policy) GraphQLResponse
emitted out toNetworkTransport
GraphQLResponse
and HTTPResponse
separated
Previously, there was a single GraphQLResponse
which included the HTTPResponse
and optionally the ParsedResult
(if the parsing interceptor had been called already). Now, since different interceptors will be called pre/post parsing, we have separate types for these response objects.
Replacing ApolloErrorInterceptor
The ApolloErrorInterceptor
protocol has been removed. Instead, any GraphQLInterceptor
can handle errors using .mapErrors()
. If any following interceptors, or the ApolloURLSession
throw an error, the mapErrors
closures will be called. You can then re-throw it; throw a different error; or trigger a retry by throwing a RequestChain.Retry
error. If you would like to use a dedicated error handling interceptor, it is recommended to place it as the first interceptor returned by your provider to ensure all errors thrown by the chain are handled.
RequestChain.Retry
Interceptors are no longer provided a reference to the RequestChain
, so they cannot call RequestChain.retry(request:) directly
. Instead, any interceptor may throw a RequestChain.Retry
error that contains the request to kick-off the retry with. This error is caught internally by the RequestChain
which initiates a retry.
Network Fetching
The network fetch is now managed by an ApolloURLSession
provided to the ApolloClient
. For your convenience, Foundation.URLSession
already conforms to the ApolloURLSession
protocol. This allows you to provide your own URLSession
and have complete control over the session's configuration and delegate.
You may alternatively provide any other object that conforms to ApolloURLSession
, wrapping the URLSession
or providing an entirely separate networking stack.
Protocols Require async
Functions
Many of the public protocols in Apollo iOS have been modified to use async
functions. If you have custom implementations of these types, they will need to b...
1.23.0
New
- Added
requireNonOptionalMockFields
flag toApolloCodegenConfiguration.OutputOptions
. (#669): Added new flag to codegen output options to allow having non-optional fields in the test mocks if desired. Thank you to @dwroth for the contribution.
Improvement
- Added public initializer to
DatabaseRow
. (#664): Not having a public initializer onDatabasRow
was hindering the ability to create customSQLiteDatabase
implementations. This solves that by adding a public initializer toDatabaseRow
.Thank you to @ChrisLaganiere for the contribution.
Fixed
- Unncessary deprecation warning in codegen options initializer. (#3563): Added
@_disfavoredOverload
to the deprecated initialized inApolloCodegenConfiguration
to prevent possible warnings caused by the compiler selecting a deprecated initializer versus the new/current initializer. See PR #682. Thank you to @CraigSiemens for raising the issue.
1.22.0
Improvement
- Make cache public within
ReadTransaction
(#661): Some users have use cases for accessing a customNormalizedCache
implementation directly while performing cache transactions. A newReadOnlyNormalizedCache
protocol exposes the cache as read-only in theReadTransaction
and as writable in theReadWriteTransaction
. See PR #661.
Fixed
- Multiple deprecation warning directives not compiling (#3559): Codegen would generate an incorrect list-style character between the Swift deprecation annotations when using multiple deprecation directives in GraphQL. See PR #658. Thank you to @guilherme-anchorage for raising the issue.
- Non-
all
field merging causes selection set initializers to stop being generated for local cache mutations (#3554): Codegen will now force field merging behaviour and selection set initializer generation for local cache mutations. See PR #654. - Referenced fragments within a local cache mutation operation are generated as mutable (#3557): Any fragments referenced within a local cache mutation will now be generated as mutable too, including any fragments within those fragments. See PR #659.
1.21.0
New
- Enhanced Client Awareness (#638): Apollo iOS now sends the library name and version as metadata in the
extensions
key of each request. This Enhanced Client Awareness metric is collected in GraphOS along with the existing Client Awareness and general operation metrics.
Improvement
- Removed SQLite.swift dependency (#635): Removed the dependency on
SQLite.swift
and replaced it with direct interaction with the SQLite C API.
Fixed
- Fix possible data races in the WebSocketTransport (#636): Fixes possible data race issues in the
subscriptions
property inside ofWebSocketTransport
. Thank you to @tahirmt for the contribution. - Fix cache reading of null list items (#3527): Null list items would previously generate a
wrongType
error if stored and read from the cache. This refactors the execution logic to correctly handle values from cache references in lists. See PR #637.
1.20.0
1.19.0
New
- New function to mutate the properties of a local cache mutation fragment. (#3433): Removal of the setter for type conditions made it difficult to work with the properties on those types. A new
mutateIfFulfilled
function was added to facilitate that workflow while still preventing a fragment from being added or removed from an existing model. See PR #608. - Configure
URLRequest
timeout interval (#3522): Added a request context specialization protocol (RequestContextTimeoutConfigurable
) that specifies options for configuring the timeout interval of aURLRequest
. See PR #618.
1.18.0
New
- Reduce Generated Schema Types (#3505): Adds a new codegen configuration option to reduce the number of
Object
types that are generated so that only types that are referenced in an operation document or have a@typePolicy
will be generated. See PR #601.
Improvement
- Identifiable conformance for named fragments (#595): Identifiable conformance was previously implemented (#584) for selection sets and has now been extended to include named fragments. Thank you to @x-sheep for the contribution.
Fixed
- Accessing an unset deprecated field in input causes a crash (#3506):
InputObject
needed aGraphQLNullable
-specific subscript to prevent nil value keys being forcefully unwrapped. See PR #596. Thank you to @pixelmatrix for raising the issue. - Crash in
WebSocketTransport
due to data races (#3512): This data race would occur if starting or stopping a subscription at the same time as a message received on the websocket. To prevent these data races thesubscribers
property is now an@Atomic
property. See PR #599. Thank you to @tahirmt for the contribution.