Releases: apollographql/apollo-kotlin
v3.6.0
This version brings initial support for @defer
as well as data builders.
💙️ External contributors
Many thanks to @engdorm, @Goooler, @pt2121 and @StylianosGakis for their contributions!
✨️ [new] @defer
support
@defer
support is experimental in the Kotlin Client and currently a Stage 2 GraphQL specification draft to allow incremental delivery of response payloads.
@defer
allows you to specify a fragment as deferrable, meaning it can be omitted in the initial response and delivered as a subsequent payload. This improves latency for all fields that are not in that fragment. You can read more about @defer
in the RFC and contribute/ask question in the @defer
working group.
Apollo Kotlin supports @defer
by default and will deliver the successive payloads as Flow
items. Given the below query:
query GetComputer {
computer {
__typename
id
...ComputerFields @defer
}
}
fragment ComputerFields on Computer {
cpu
year
screen {
resolution
}
}
And the following server payloads:
payload 1:
{
"data": {
"computer": {
"__typename": "Computer",
"id": "Computer1"
}
},
"hasNext": true
}
payload 2:
{
"incremental": [
{
"data": {
"cpu": "386",
"year": 1993,
"screen": {
"resolution": "640x480"
}
},
"path": [
"computer",
]
}
],
"hasNext": true
}
You can listen to payloads by using toFlow()
:
apolloClient.query(query).toFlow().collectIndexed { index, response ->
// This will be called twice
if (index == 0) {
// First time without the fragment
assertNull(response.data?.computer?.computerFields)
} else if (index == 1) {
// Second time with the fragment
assertNotNull(response.data?.computer?.computerFields)
}
}
You can read more about it in the documentation.
As always, feedback is very welcome. Let us know what you think of the feature by
either opening an issue on our GitHub repo
, joining the community
or stopping by our channel in the KotlinLang Slack(get your
invite here).
✨️ [new] Data Builders (#4321)
Apollo Kotlin 3.0 introduced test builders. While they are working, they have several limitations. The main one was that being response based, they could generate a lot of code. Also, they required passing custom scalars using their Json encoding, which is cumbersome.
The data builders are a simpler version of the test builders that generate builders based on schema types. This means most of the generated code is shared between all your implementations except for a top level Data {}
function in each of your operation:
// Replace
val data = GetHeroQuery.Data {
hero = humanHero {
name = "Luke"
}
}
// With
val data = GetHeroQuery.Data {
hero = buildHuman {
name = "Luke"
}
}
✨️ [new] Kotlin 1.7 (#4314)
Starting with this release, Apollo Kotlin is built with Kotlin 1.7.10. This doesn't impact Android and JVM projects (the minimum supported version of Kotlin continues to be 1.5) but if you are on a project using Native, you will need to update the Kotlin version to 1.7.0+.
👷 All changes
- fix registering Java scalars. Many thanks @parker for catching this. (#4375)
- Data builders (#4359, #4338, #4331, #4330, #4328, #4323, #4321)
- Add a flag to disable fieldsCanMerge validation on disjoint types (#4342)
- Re-introduce @defer and use new payload format (#4351)
- Multiplatform: add enableCompatibilityMetadataVariant flag (#4329)
- Remove an unnecessary
file.source().buffer()
(#4326) - Always use String for defaultValue in introspection Json (#4315)
- Update Kotlin dependency to 1.7.10 (#4314)
- Remove schema and AST from the IR (#4303)
v2.5.13
A 2.x maintainance release with a couple of bugfixes. Many thanks to @eduardb for diving into #2818 💙
What's Changed
- Fix converting introspection to SDL by @martinbonnin in #4316
- Fix writing fragments overwrites cache entries (#2818) by @eduardb in #4358
Full Changelog: v2.5.12...v2.5.13
v3.5.0
With this release, Apollo Kotlin now uses Kotlin Native's new memory model. It also contains a number of other improvements and bug fixes.
💙️ External contributors
Many thanks to @glureau
for carefully adding new watch targets ⌚💙
✨️ [new] Kotlin Native: new memory manager (#4287)
Apollo Kotlin is now requiring applications to use the new memory manager, a.k.a. new memory model. Thanks to this change, the restriction that operations had to be executed from the main thread on Apple targets is now removed. You can also use kotlinx.coroutines.test.runTest. Last but not least, benchmarks seem to indicate that performance is better under the new memory manager!
✨️ [new] @targetName
directive (#4243)
This directive was introduced in v3.3.1 to allow overriding the name of enum values in the generated code. It has now been extended to allow configuring the generated name of Interfaces, Enums, Unions, Scalars and Input objects. This can be used to make the generated code nicer to use, or to avoid name clashes with Kotlin types (e.g. Long
) in Kotlin Native.
✨️ [new] Automatic resolution of Apollo artifacts versions from the plugin version (#4279)
From now on, you no longer need to specify explicitly the versions of Apollo dependencies: if omitted, the same version as the Apollo Gradle plugin will be used. This should facilitate upgrades and avoid potential mistakes:
plugins {
plugins {
id("org.jetbrains.kotlin.jvm").version("1.7.10")
id("com.apollographql.apollo3").version("3.5.0")
}
dependencies {
// Replace this
// implementation("com.apollographql.apollo3:apollo-runtime:3.5.0")
// with
implementation("com.apollographql.apollo3:apollo-runtime")
}
}
🚧 [deprecated] runTest
(#4292)
With the new memory model, Apollo's specific runTest
method from apollo-testing-support
is no longer useful and has been deprecated. If you were using it, you should now be able to use Kotlin's runTest
instead, or simply runBlocking
.
🚧 [breaking] Automatic detection of type
enum values.
If you have an enum with a type
value, this value used to name clash with the generated type
property. This version now detects this case automatically and escapes type
to type_
. If you had previously used @targetName
to workaround this issue, you can now remove it to avoid it being escaped twice:
# Remove this
extend enum SomeEnum {
type @targetName(name: "type_")
}
👷 All changes
- Support watchosArm32 (#4260)
- Support @TargetNAME on Interfaces, Enums, Unions, Scalars and Input objects (#4243)
- 🐘 support lazy APIs for newer AGP versions (#4264)
- Pagination: add connectionFields argument to @typePolicy (#4265)
- 🐘 Get the dependencies version from the plugin automagically (#4279)
- Automatically escape
type
in enum values (#4295) - Fix inferred variables in both nullable and non-nullable locations (#4306)
- Native: assume New Memory Manager (#4287)
- Use internal runTest in all tests (#4292)
v3.4.0
Version 3.4.0
2022-07-11
This release contains a few important bug fixes (#4214, #4224, #4247, #4256) and makes it possible to compile with Gradle 7.4 and apollo-gradle-plugin
(#4218).
It also introduces incubating
cache artifacts.
💙️ External contributors
Many thanks to @ArjanSM, @zebehringer, @mm-kk-experiments, @mune0903, @stengvac, @elenigen, @shamsidinb and @StylianosGakis for the awesome contributions 😃!
✨️ [new] incubating
cache artifacts.
This version introduces the below artifacts:
apollo-normalized-cache-incubating
apollo-normalized-cache-api-incubating
apollo-normalized-cache-sqlite-incubating
These artifacts introduce new APIs to work with cache expiration and pagination (as well as other cache improvements in the future).
These artifacts have no backward compatibility guarantees and most likely have worse performance than the non-incubating artifacts. Documentation will be added once the API stabilize. In the short term, the best place to look for examples are the integration tests:
Note: The experimental withDates: Boolean
argument was introduced in 3.3.1 in the regular artifacts and is removed as part of this release. Use the incubating
artifacts to use it.
👷 All changes
- add TrimmableNormalizedCacheFactory (#4239)
- 🚧 remove withDates (#4257)
- 🗄️ Chunk parameters in large responses (#4256)
- Fix for improper handling of JsonNumber in BufferedSinkJsonWriter (#4247)
- Incubating modules for the next gen cache (#4241)
- Pagination: fixes in FieldRecordMerger and MemoryCache (#4237)
- make it possible to reuse a File Upload (#4228)
- Persist Record arguments/metadata with the SQL Json backend (#4211)
- requestedDispatcher -> dispatcher (#4220)
- Fix test errors were emitted outside the Flow (#4224)
- Make it possible to compile with Kotlin 1.5 and apollo-gradle-plugin (#4218)
- 🏖️ Relax MapJsonReader endObject, fixes reading inline + named fragments with compat models (#4214)
- Introduce RecordMerger (#4197)
- Add @typePolicy(embeddedFields: String! = "") (#4196)
v3.3.2
This is a hot fix release that fixes a crash that could happen in the codegen when using responseBased
codegen in a
multimodule setup. It also includes a fix for incorrect generated code when using certain reserved names in enum values.
👷 All changes
v2.5.12
Version 2.5.12
is a maintenance release with a fix to restore downloading schemas as SDL, and a fix for Kotlin 1.7 compatibility.
💜 Many thanks to @eg-ndobrijevic and @remcomokveld for raising these issues! 💜
👷 All Changes
v3.3.1
This release introduces @typePolicy
on interface/enums, improvements on subscription error handling, and on Test Builders. It also contains a number of other improvements and bug fixes!
✨️ [new] @typePolicy
on interfaces and unions (#4131)
The @typePolicy
directive can now be declared on interfaces and unions. Thank you @bubba for the contribution!
🔌 WebSockets / Subscriptions error handling (#4147)
An issue where websocketReopenWhen
was not called in some cases was fixed. Also, this release introduces SubscriptionOperationException
. A SubscriptionOperationException
will be thrown instead of the more generic ApolloNetworkError
if a subscription fails due to a specific operation error.
📐 Test Builders improvements and fixes
- A DslMarker was added to improve usage with nested builders (#4089)
- When calling a builder, but not assigning it to a field, an error is now thrown, preventing mistakes (#4122)
- The error message displayed when
__typename
is missing was made clearer (#4146) - Fix: use
rawValue
instead ofname
for enums (#4121)
✨️ [new] ApolloClient implements Closable (#4142)
ApolloClient
now implements okio.Closable
so you can use use
with it. Thanks @yogurtearl for this contribution!
✨️ [new] experimental @targetName
directive on enum values (#4144)
If an enum value name is clashing with a reserved name (e.g. type
) you can now use this directive to instruct the codeGen to use the specified name for the value instead. This directive is experimental for now.
✨️ [new] experimental support for renaming directives (#4174)
As we add more client directives, the risk of nameclash with existing schema directives increases. If this happens, you can now import Apollo client directives using @link
:
# extra.graphqls
extend schema @link(url: "https://specs.apollo.dev/kotlin_labs/v0.1")
This adds a @kotlin_labs__
prefix to all Apollo client directives:
{
hero {
name @kotlin_labs__nonnull
}
}
🤖 SqlNormalizedCacheFactory
initialization on Android (#4104)
It is no longer necessary to pass a Context
when initializing the SqlNormalizedCacheFactory
on Android. A Context
is automatically provided, via App Startup.
// Before
val sqlNormalizedCacheFactory = SqlNormalizedCacheFactory(context, "apollo.db")
// After
val sqlNormalizedCacheFactory = SqlNormalizedCacheFactory("apollo.db")
📝 [new] Public API tracking
This release starts tracking the public API of all modules, including MockServer. Even if the API remains experimental, we'll try to keep the number of breaking changes low in the future.
👷 All changes
- 🐘 publish
apollo-gradle-plugin-external
(#4078) - publish the R8 mapping file along the relocated jar (#4085)
- Fix test directories not cleared (#4083)
- Do not use 'header' as a enum value name as it breaks the Kotlin compiler (#4086)
- 🧪 @experimental support (#4091)
- @experimental -> @requiresOptIn (#4175)
- Do not buffer entire body in Http Cache (#4076)
- ⬇️ add SchemaDownloader.download() (#4088)
- add DslMarker for test builders (#4089)
- MockServer: make MockResponse.body a Flow (#4096)
- Issue-3909: add ApolloResponse cache headers (#4102)
- Use rawValue instead of name for enums in test builders (#4121)
- 💧 first drop for a SQLite backend that stores when each field was last updated (#4104)
- Add Operation.Data.toJsonString() convenience function for the jvm (#4124)
- Check for unassigned fields in Test Builders (#4122)
- Add non-breaking spaces after 'return' (#4127)
- 🧶 Use a getter instead of a const val OPERATION_QUERY (#4130)
- Uploads should be read only once even when logging (#4125)
- Keep the 'interfaces' field on the JSON introspection (#4129)
- Allow @typePolicy directive on interfaces and unions (#4131)
- typePolicy on interface: exclude empty keyfields (#4140)
- Sort the type names in the list so the code gen is deterministic. (#4138)
- Use okio.Closable.close instead of dispose on ApolloClient (#4142)
- Parse the interface's interface field in introspection (#4143)
- TestBuilders: improve error message when __typename is missing (#4146)
- Do not bypass websocketReopenWhen {} (#4147)
- SDLWriter: join implemented interfaces with & instead of space (#4151)
- Escape "type" in enums and sealed classes (#4144)
- 🧰 introduce apollo-tooling and apollo-cli (#4153)
- Fix incorrect content-length in MockServer (#4162)
- Allow capitalized field names if flattenModels is true (#4154)
- 🏷️ Allow namespacing and renaming of directives (#4174)
❤️ External contributors
Many thanks to @tajchert, @asimonigh, @hrach, @ArjanSM, @yshrsmz, @ephemient, @bubba, @eboudrant and @yogurtearl for contributing to this release! 🙏
v3.3.0
This is the first release with HMPP support. If you're using multiplatform, updating to Kotlin 1.6.21 is strongly encouraged.
This release also brings WebSocket related improvements and other fixes!
✨️ [new] Hierarchical MultiPlatform Project (HMPP) (#4033)
When using Apollo Kotlin on a multiplatform project, this release is compatible with the hierarchical project structure, which makes it easier to share common code among several targets. Using HMPP in your project also fixes some issues when compiling Kotlin metadata. See #4019 and https://youtrack.jetbrains.com/issue/KT-51970/ for more details.
✋ Note: If you're using multiplatform, we strongly encourage updating to Kotlin 1.6.21. If that is not an option, you might have issues resolving dependencies. More infos in this issue.
✨️ [new] WebSocketNetworkTransport.closeConnection
(#4049)
This new method can be used in conjunction with reopenWhen
to force a reconnection to the server. This could be useful for instance when needing to pass new auth tokens in the headers. If you were using subscriptionManager.reconnect()
in 2.x, closeConnection
is a simple way to achieve the same behaviour.
✨️ [new] GraphQLWsProtocol.connectionPayload
is now a lambda (#4043)
With GraphQLWsProtocol
, if you need to pass parameters to the connection payload, previously you would pass them as a static map to the builder. With this change you can now pass a lambda providing them as needed. This facilitates passing fresh auth tokens when connecting.
✨️ [new] Add insecure option to download schema (#4021)
You can now use the --insecure
flag when downloading a schema with downloadApolloSchema
, to bypass the certificate check, which can be useful if a server is configured with a self-signed certificate for instance.
👷 All changes
- Add WebSocketNetworkTransport.closeConnection (#4049)
- Made connectionPayload as suspend function in GraphQLWsProtocol (#4043)
- ⚡ Ignore unknown websocket messages (#4066)
- Kotlin 1.6.21 & HMPP (#4033)
- Provide a Content-Length when using Upload (#4056)
- ☁️ add HttpRequest.newBuilder(url, method) (#4038)
- Escape enum constants (#4035)
- Fix the Moshi adapter used for OperationOutput. Moshi cannot get the type parameters from the typealias
automagically (#4022) - Add insecure option to download schema (#4021)
- Try to reduce allocations in MapJsonReader (#3935)
- 🔒 Deprecate BearerTokenInterceptor and provide tests and docs instead (#4068)
❤️ External contributors
Many thanks to @CureleaAndrei and @kdk96 for contributing to this release! 🙏
⚙️ Deprecations
BearerTokenInterceptor
was provided as an example but is too simple for most use cases, and has therefore been deprecated
in this release. This page provides more details
about authentication.- The previous ways of passing parameters to the connection payload with
GraphQLWsProtocol
has been deprecated (see above).
v3.2.2
Version 3.2.2
Many thanks to @benedict-lim, @OlivierG13, @konomae and @sproctor for their contributions 💙
3.2.2 is a maintenance release to fix the addJvmOverloads
option added in 3.2.0 as well as other fixes. If you're using APQs, the mutations are now always send using POST
. See #4006 for details and a way to override the behaviour if you need to.
👷 All changes
- Use a constant for JvmOverloads to avoid a crash due to relocation (#4008)
- Always use POST for Mutations in APQs (Auto Persisted Queries) (#4011)
- Add configurable headers to WebSocketNetworkTransport (#3995)
- Handle SqlNormalizedCache merge APIs Exceptions with ApolloExceptionHandler (#4002)
- Add adapter for java.time.OffsetDateTime (#4007)
- ⏰ Add tests for date adapters (#3999)
- Fix wrong LocalDate and LocalDateTime formats in JavaTimeAdapters (#3997)
v3.2.1
This release introduces a few improvements and bug fixes.
✨️ [new] ApolloCall<D>.emitCacheMisses(Boolean)
(#3980)
When observing the cache with watch
, the behavior was to not emit cache misses at all, which may not desirable in certain cases. With this new option, you can now choose to emit them: in that case responses will be emitted with a null data
.
This can be used like so:
apolloClient.query(query)
.fetchPolicy(FetchPolicy.CacheOnly)
.emitCacheMisses(true)
.watch()
.collect { response ->
// response.data will be null in case of cache misses
}
This is also closer to the behavior that was in place in v2. Many thanks to @mateuszkwiecinski for the insights and raising the issue!
⚙️ [breaking] Allow configuration of frame types used in SubscriptionWsProtocol
and default to Text (#3992)
When using subscriptions over WebSockets with SubscriptionWsProtocol
(the default), the frames were sent in the binary format. It was reported that this was not compatible with certain servers (DGS, graphql-java-kickstart) that are expecting text frames. This is now fixed and the default is to send text frames.
⚠️ This may be a breaking change if your server expects binary frames only!
If that is the case, you can use the newframeType
option to configure the frame type to be sent:
client = ApolloClient.Builder()
.webSocketServerUrl("wss://...")
.wsProtocol(GraphQLWsProtocol.Factory(frameType = WsFrameType.Binary))
.build()
Many thanks to @Krillsson and @aviewfromspace1 for the insights and raising the issue!
👷 All changes
- Allow configuration of frame types used in SubscriptionWsProtocol and default to Text (#3992)
- add
ApolloRequest.newBuilder(operation: Operation<E>)
(#3988) - Add exception handlers to ApolloCacheInterceptor and SqlNormalizedCache (#3989)
- 📠 Fix some @DeprecatedSince annotations (#3983)
- 👓 add ApolloCall.emitCacheMisses(Boolean) (#3980)
- ⚙️ Fix fragments on the root query type in operationBased codegen (#3973)
❤️ External contributors
Many thanks to @AdamMTGreenberg and @Krillsson for the contributions! 🙏