Changelog History
Page 1
-
v3.3.2 Changes
2022-06-17
๐ 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
- โก๏ธ Update to KotlinPoet
1.12.0
, fixes generating enum values whose name clashes with other symbols (#4034) - โก๏ธ Update to Ktor 2 (#4190)
- ๐ Fix NPE in checkCapitalizedFields (#4201)
- โก๏ธ Update to KotlinPoet
-
v3.3.1 Changes
2022-06-13
๐ 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 introducesSubscriptionOperationException
. ASubscriptionOperationException
will be thrown instead of the more genericApolloNetworkError
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 implementsokio.Closable
so you can useuse
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
: -
v3.3.0 Changes
2022-05-04
๐ 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 https://github.com/apollographql/apollo-kotlin/issues/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 usingsubscriptionManager.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 withdownloadApolloSchema
, 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 Changes
2022-04-11
๐ 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 usingPOST
. See #4006 for details and a way to override the behaviour if you really need to.Many thanks to @benedict-lim, @olivierg13, @konomae and @sproctor for their contributions ๐
๐ทโ 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 Changes
2022-04-05
๐ 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 nulldata
.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)0๏ธโฃ 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 new
frameType
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! ๐
-
v3.2.0 Changes
2022-03-29
๐ ๐ Thanks to @undermark5, @demoritas, @rkoron007, @akshay253101, @StylianosGakis, @Goooler, @jeffreydecker, @theBradfo, @anderssandven and @olivierg13 for contributing to this release.
๐ This version adds JS WebSocket support, more options to deal with
__typename
amongst other features and bugfixes.๐ โจ๏ธ [new] JS WebSocket support (#3913)
๐ Version 3.2.0 now has WebSocket support for Javascript targets courtesy of @undermark5! This is a huge milestone and means the JS target is now even closer to its JVM and iOS counterparts.
๐ง | |
jvm
| Apple |js
|linuxX64
| --- | :---: |:-----:|:----:| :---: | |apollo-api
(models)|โ | โ | โ |โ | |apollo-runtime
(network, query batching, apq, ...) |โ | โ | โ |๐ซ| |apollo-normalized-cache
|โ | โ | โ |๐ซ| |apollo-adapters
|โ | โ | โ |๐ซ| |apollo-normalized-cache-sqlite
|โ | โ | ๐ซ |๐ซ| |apollo-http-cache
|โ | ๐ซ | ๐ซ |๐ซ|๐ป The implementation is based on the
ws
library on Node and theWebSocket
API on the browser and inspired by Ktor.โจ๏ธ [new] Fine grained
__typename
control (#3939)This version generates non-nullable fragments when it knows the fragment is always present:
{ cat { # Because Animal is a supertype of Cat this condition will always be true ... on Animal { species } } }
๐ In addition, it introduces a
addTypename
Gradle option to have better control over when to add the__typename
field:/** * When to add __typename. One of "always", "ifFragments", "ifAbstract" or "ifPolymorphic" * * - "always": Add '__typename' for every compound field * * - "ifFragments": Add '__typename' for every selection set that contains fragments (inline or named) * This is adding a lot more '__typename' than the other solutions and will be certainly removed in * a future version. If you require '__typename' explicitly, you can add it to your queries. * This causes cache misses when introducing fragments where no fragment was present before and will be certainly removed in * a future version. * * - "ifAbstract": Add '__typename' for abstract fields, i.e. fields that are of union or interface type * Note: It also adds '__typename' on fragment definitions that satisfy the same property because fragments * could be read from the cache and we don't have a containing field in that case. * * - "ifPolymorphic": Add '__typename' for polymorphic fields, i.e. fields that contains a subfragment * (inline or named) whose type condition isn't a super type of the field type. * If a field is monomorphic, no '__typename' will be added. * This adds the bare minimum amount of __typename but the logic is substantially more complex and * it could cause cache misses when using fragments on monomorphic fields because __typename can be * required in some cases. * * Note: It also adds '__typename' on fragment definitions that satisfy the same property because fragments * could be read from the cache and we don't have a containing field in that case. * * Default value: "ifFragments" */
๐ You can read more in the corresponding Typename.md design document.
๐ โจ๏ธ [new] Maven publishing for multi-module apollo metadata (#3904)
๐ The Apollo Gradle plugin now creates a new "apollo" publication if
maven-publish
is found. This means you can now publish the Apollo metadata to a maven repository: -
v3.1.0 Changes
2022-02-07
๐ Version 3.1.0 introduces new APIs for testing, mapping scalars as well a redesigned cache pipeline. ๐ It also contains bugfixes around the
@include
directives, MemoryCache and GraphQL validation amongst other changes.๐ฆ โ๏ธ [breaking] Fragment package name and
useSchemaPackageNameForFragments
(#3775)๐ฆ If you're using
packageNamesFromFilePaths()
, the package name of generated fragment classes has changed.๐ฆ Different generated types have different package names:
- Generated types coming from operations are generated based on the operation path
- Generated types coming from the schema (input objects, custom scalars and enums) are generated based on the schema path
Previously, fragments were using the schema path which is inconsistent because fragments are not defined in the schema but are executable files, like operations.
๐ Version 3.1.0 now uses the same logic for fragments as for operations. To revert to the previous behaviour, you can use
useSchemaPackageNameForFragments
:apollo { useSchemaPackageNameForFragments.set(true) }
๐ฆ This is also done automatically if you're using
useVersion2Compat()
. Moving forward, the plan is to removeuseSchemaPackageNameForFragments
in favor of setting a customPackageNameGenerator
. If you have use cases that requireuseSchemaPackageNameForFragments
, please reach out.โ โจ [New]
QueueTestNetworkTransport
(#3757)โ 3.1.0 introduces
QueueTestNetworkTransport
to test at the GraphQL layer without needing to run an HTTP server.๐ง To use it, configure your
ApolloClient
:// This uses a QueueTestNetworkTransport that will play the queued responses val apolloClient = ApolloClient.Builder() .networkTransport(QueueTestNetworkTransport()) .build()
โ You can then use the
enqueueTestResponse
extension function to specify the GraphQL responses to return:val testQuery = GetHeroQuery("001") val testData = GetHeroQuery.Data { hero = droidHero { name = "R2D2" } } apolloClient.enqueueTestResponse(testQuery, testData) val actual = apolloClient.query(testQuery).execute().data!! assertEquals(testData.hero.name, actual.hero.name)
๐คก โจ [New]
MockServerHandler
(#3757)โ If you're testing at the HTTP layer, you can now define your own
MockServerHandler
to customize how the server is going to answer to requests:val customHandler = object : MockServerHandler { override fun handle(request: MockRequest): MockResponse { return if (/* Your custom logic here */) { MockResponse( body = """{"data": {"random": 42}}""", headers = mapOf("X-Test" to "true"), ) } else { MockResponse( body = "Internal server error", statusCode = 500, ) } } } val mockServer = MockServer(customHandler)
โจ [New]
FetchPolicy.CacheAndNetwork
(#3828)Previously,
FetchPolicy
s were limited to policies that emitted at most one response. There was aexecuteCacheAndNetwork()
method but it felt asymmetrical. This version introducesFetchPolicy.CacheAndNetwork
that can emit up to two responses:apolloClient.query(query) // Check the cache and also use the network (1 or 2 values can be emitted) .fetchPolicy(FetchPolicy.CacheAndNetwork) // Execute the query and collect the responses .toFlow().collect { response -> // ... }
โจ [New]
ApolloCall<D>.fetchPolicyInterceptor(interceptor: ApolloInterceptor)
(#3743)If you need more customized ways to fetch data from the cache or more fine-grained error handling that does not come with the built-in
FetchPolicy
, you can now usefetchPolicyInterceptor
:// An, interceptor that will only use the network after getting a successful response val refetchPolicyInterceptor = object : ApolloInterceptor { var hasSeenValidResponse: Boolean = false override fun <D : Operation.Data> intercept(request: ApolloRequest<D>, chain: ApolloInterceptorChain): Flow<ApolloResponse<D>> { return if (!hasSeenValidResponse) { CacheOnlyInterceptor.intercept(request, chain).onEach { if (it.data != null) { // We have valid data, we can now use the network hasSeenValidResponse = true } } } else { // If for some reason we have a cache miss, get fresh data from the network CacheFirstInterceptor.intercept(request, chain) } } } apolloClient.query(myQuery) .refetchPolicyInterceptor(cacheOnlyInterceptor) .watch() .collect { // }
โจ [New]
Service.mapScalar
Gradle API (#3779)You can now use
mapScalar
to specify your scalar mappings:apollo { // Replace customScalarsMapping.set(mapOf( "Date" to "java.util.Date" )) // With mapScalar("Date", "java.util.Date") }
mapScalar
also works with built-in scalar types so you can map theID
type to a kotlin Long:apollo { // This requires registering an adapter at runtime with `addCustomScalarAdapter()` mapScalar("ID", "kotlin.Long") }
As an optimization, you can also provide the adapter at compile time. This will avoid a lookup at runtime everytime such a scalar is read:
apollo { // No need to call `addCustomScalarAdapter()`, the generated code will use the provided adapter mapScalar("ID", "kotlin.Long", "com.apollographql.apollo3.api.LongAdapter") }
For convenience, a helper function is provided for common types:
apollo { // The generated code will use `kotlin.Long` and the builtin LongAdapter mapScalarToKotlinLong("ID") // The generated code will use `kotlin.String` and the builtin StringAdapter mapScalarToKotlinString("Date") // The generated code will use `com.apollographql.apollo3.api.Upload` and the builtin UploadAdapter mapScalarToUpload("Upload") }
๐ง [Changed]
convertApolloSchema
anddownloadApolloSchema
now use paths relative to the root of the project (#3773, #3752)Apollo Kotlin adds two tasks to help to manage schemas:
convertApolloSchema
anddownloadApolloSchema
. These tasks are meant to be used from the commandline.๐ Previously, paths were interpreted using the current working directory with
File(path)
. Unfortunately, this is unreliable because Gradle might change the current working directory in some conditions (see Gradle#13927 or Gradle#6074 for an example).With 3.1.0 and onwards, paths, will be interpreted relative to the root project directory (
project.rootProject.file(path)
): -
v3.0.0 Changes
2021-12-15
๐ This is the first stable release for ~Apollo Android 3~ Apollo Kotlin 3 ๐!
๐ There is documentation, a migration guide and a blog post coming soon (we'll update these notes when it's out).
In a nutshell, Apollo Kotlin 3 brings:
- ๐ coroutine APIs for easier concurrency
- ๐ multiplatform support makes it possible to run the same code on Android, JS, iOS, MacOS and linux
- ๐ responseBased codegen is a new optional codegen that models fragments as interfaces
- SQLite batching makes reading from the SQLite cache significantly faster
- ๐ Test builders offer a simple APIs to build fake models for your tests
- ๐ The @typePolicy and @fieldPolicy directives make it easier to define your cache ids at compile time
- ๐ The @nonnull directive catches null values at parsing time, so you don't have to deal with them in your UI code
๐ Feel free to ask questions 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).
-
v3.0.0-rc03 Changes
2021-12-13
๐ Compared to the previous RC, this version adds a few new convenience API and fixes 3 annoying issues.
๐ Many thanks to @ mateuszkwiecinski, @ schoeda and @ fn-jt for all the feedback ๐
โจ New APIs
- ๐ Make
ApolloCall.operation
public (#3698) - โ Add
SubscriptionWsProtocolAdapter
(#3697) - โ Add
Operation.composeJsonRequest
(#3697)
๐ ๐ชฒ Bug fixes
- ๐ Allow repeated
@fieldPolicy
(#3686) - ๐ Fix incorrect merging of nested objects in JSON (#3672)
- ๐ Fix duplicate query detection (#3699)
- ๐ Make
-
v3.0.0-rc02 Changes
2021-12-10
๐ Many thanks to @michgauz, @joeldenke, @rohandhruva, @schoeda, @CoreFloDev and @sproctor for all the feedback ๐
๐ โ๏ธ [breaking] Merge ApolloQueryCall, ApolloSubscriptionCall, ApolloMutationCall (#3676)
In order to simplify the API and keep the symmetry with
ApolloRequest<D>
andApolloResponse<D>
,ApolloQueryCall<D, E>
,ApolloSubscriptionCall<D, E>
,ApolloMutationCall<D, E>
are replaced withApolloCall<D>
. This change should be mostly transparent but it's technically a breaking change. If you are passingApolloQueryCall<D, E>
variables, it is safe to drop the second type parameter and useApolloCall<D>
instead.โจ [New] Add
WebSocketNetworkTransport.reconnectWhen {}
(#3674)You now have the option to reconnect a WebSocket automatically when an error happens and re-subscribe automatically after the reconnection has happened. To do so, use the
webSocketReconnectWhen
parameter:val apolloClient = ApolloClient.Builder() .httpServerUrl("http://localhost:8080/graphql") .webSocketServerUrl("http://localhost:8080/subscriptions") .wsProtocol( SubscriptionWsProtocol.Factory( connectionPayload = { mapOf("token" to upToDateToken) } ) ) .webSocketReconnectWhen { // this is called when an error happens on the WebSocket it is ApolloWebSocketClosedException && it.code == 1001 } .build()
๐ Better Http Batching API (#3670)
๐ง The
HttpBatchingEngine
has been moved to anHttpInterceptor
. You can now configure Http batching with a specific method:apolloClient = ApolloClient.Builder() .serverUrl(mockServer.url()) .httpBatching(batchIntervalMillis = 10) .build()
All changes:
- โ Add 2.x symbols (
Rx2Apollo
,prefetch()
,customAttributes()
,ApolloIdlingResource.create()
) to help the transition (#3679) - โ Add canBeBatched var to ExecutionOptions (#3677)
- ๐ Merge ApolloQueryCall, ApolloSubscriptionCall, ApolloMutationCall (#3676)
- โ Add
WebSocketNetworkTransport.reconnectWhen {}
(#3674) - ๐ Move BatchingHttpEngine to a HttpInterceptor (#3670)
- โ Add exposeErrorBody (#3661)
- ๐ fix the name of the downloadServiceApolloSchemaFromRegistry task (#3669)
- ๐ Fix DiskLruHttpCache concurrency (#3667)
- โ Add 2.x symbols (