:robot: Β A strongly-typed, caching GraphQL client for the JVM, Android, and Kotlin multiplatform.
If you're using a chained memory + SQL cache, #5840 makes sure cache writes are wrapped in a transaction, making them much faster.
Plugin
is renamed to ApolloCompilerPlugin
. There is a new documentTransform
API as well as other fixes. More details in the compiler plugins documentation.
A new .websocket
package is available that makes it easier to retry WebSockets and handle errors. More details and migration guide in the experimental websockets documentation.
We recommend using reactive patterns to test your UI instead. See this article about ways to do so.
androidx.startup was introduced in beta.5 but is problematic for unit tests and other cases. beta.6 removes that dependency. More details in the network connectivity documentation.
You can see Wasm in action at https://wasm.confetti-app.dev/
Many thanks to @joreilly, @ychescale9 and @japhib for their contributions to this release π!
Plugin
to ApolloCompilerPlugin
and add error message for bad configurations (#5821)@ApolloEnumConstructor
and make enum as sealed class Unknown constructor opt-in (#5813)isOnline
to a suspend funApolloClient
with lazily initialized Call.Factory
. (#5784)androidx.startup
dependency (#5761, #5720)Version 3.8.3 is a maintenance release with two new convenience APIs and a Kotlin update. New developments happen in the 4.x versions.
Note: because Apollo Kotlin now depends on kotlin-stdlib version 1.9, you need the 1.8+ Kotlin compiler to compile your project.
ApolloClient.Builder(ApolloHttpCache)
(#5638) (#5640)buildPostBody
to write operation extensions (#5631).exception
(#5018)IOException
when calling ApolloHttpCache.remove
(#5730)PackageNameGenerator
and OperationOutputGenerator
are deprecated. See the documentation page about Apollo compiler plugins for more details.@semanticNonNull
or @catch
you should bump your @link
directives to use 0.3
. See the nullability documentation page for more details.https://go.apollo.dev/ij-plugin-snapshots
to get the latest weekly snapshots. (#5600)Many thanks to @ribafish, @molundb, @mboyd1993, @rohandhruva and @baconz for their help in this release π!
NetworkMonitor
(#5690)ApolloClient.retryOnError(Boolean)
(#5685)@catch
on fieldDefinitions, interfaces and objects (#5623)X-APOLLO-OPERATION-NAME
, X-APOLLO-OPERATION-ID
and the multipart boundary (#5533)generateAsInternal
code (#5526)4.0.0-beta.3
(#5452)This release adds initial support for WebAssembly by adding the wasmJs
target.
Executing queries/mutations is working but this target is experimental (Kotlin/Wasm is Alpha) and has multiple limitations:
Downloading a schema from introspection (./gradlew downloadServiceSchemaFromIntrospection
) got broken in the previous release (#5449) and is now fixed.
Many thanks @chris-hatton and @sdfgsdfgd for contributing this version π
β οΈ we're aware of a regression in downloadApolloSchema, we'll make a new release soon.
The normalized cache viewer can now display the contents of your in-memory cache. To do so, it relies on a debug server that you need to run in your debug builds:
val apolloClient = ApolloClient.Builder()
.serverUrl("https://example.com/graphql")
.build()
if (BuildConfig.DEBUG) {
ApolloDebugServer.registerApolloClient(apolloClient)
}
You can read more about it in the "Apollo debug server" documentation page.
@catch
and @semanticNonNull
support@catch
makes it possible to model GraphQL errors as FieldResult
Kotlin classes giving you inline access to errors:
query GetUser {
user {
id
# map name to FieldResult<String?> instead of stopping the parsing
name @catch
avatarUrl
}
}
@semanticNonNull
is a better @nonnull
. @semanticNonNull
makes it possible to mark a field as null only on error. The matching Kotlin property is then generated as non-null:
# mark User.name as semantically non-null
extend type User @semanticNonNull(field: "name")
Both those directives are experimental and require opt-in of the nullability directives
You can read more about them in the "handle nullability" documentation page.
@oneOf
support@oneOf
introduces input polymorphism to GraphQL:
input PetInput @oneOf {
cat: CatInput
dog: DogInput
fish: FishInput
}
input CatInput { name: String!, numberOfLives: Int }
input DogInput { name: String!, wagsTail: Boolean }
input FishInput { name: String!, bodyLengthInMm: Int }
type Mutation {
addPet(pet: PetInput!): Pet
}
With @oneOf
, only one of cat
, dog
or fish
can be set.
@oneOf
support is automatically enabled if your schema has the @oneOf
directive definition.
You can read more about it in the @oneOf
RFC
[all] @oneOf
support (#5394, #5388)
[all] @catch
and @semanticNonNull
support (#5405)
[all] Take default values into account when computing field cache keys (#5384)
[all] Bump Kotlin to 2.0.0-Beta1 (#5373)
[IJ Plugin] Add 'Input class constructor issue' inspection (#5427)
[IJ plugin] Update v3->v4 migration following API tweaks (#5421)
[IJ Plugin] Report invalid oneOf
input object builder uses (#5416)
[IJ Plugin] Add inspection for @oneOf
input type constructor invocation (#5395)
[IJ plugin] Make the refresh button work with all normalized cache sources. (#5400)
[IJ Plugin] Cache viewer: take numbers into account in key sorting (#5396)
[IJ Plugin] Bump pluginUntilBuild to 233 (#5377)
[IJ Plugin] Telemetry: don't use a libraries changed listener (#5361)
[IJ Plugin] Cache viewer: add cache size to selector (#5357)
[IJ plugin] Use apollo-debug-server to retrieve normalized caches (#5348)
[IJ plugin] Cache viewer: "Pull from Device" modal dialog instead of action menu (#5333)
[IJ Plugin] Fix v3->v4 migration with ApolloCompositeException (#5330)
[runtime] remove some of the ApolloResponse.Builders (#5426) [runtime] Add a few symbols as ERROR deprecation for the migration (#5422) [runtime] Add executeV3 + toFlowV3 (#5417) [runtime] Revive dataAssertNoErrors (#5419) [runtime] Allow no data and no exception in case of GraphQL errors (#5408) [runtime] Expose ExecutionContext to HttpEngine and add OkHttp helpers (#5383) [runtime] Improve deprecation messages (#5411) [runtime] Go back to just one Adapter class (#5403) [runtime] Fix Optional.getOrElse (#5399)
[compiler] Remove kotlin-labs-0.1 directives (#5404) [compiler] Throw a better exception than NullPointerException if a value is missing (#5402) [compiler] ExecutableValidationResult is returned by validateAsExecutable() and cannot be @ApolloInternal (#5406) [compiler] Rework the IrType hierarchy (#5392) [compiler] remove CCN (#5387) [compiler] Remove antlr (#5336) [compiler] Tweak description javadoc, there is no need to use the same escaping as Kotlin (#5424)
[mockserver] Support setting port for Apollo MockServer (#5389) [mockserver] Add WebSocket support to the MockServer (#5334) [tools] Implement 2-step introspection (#5371) [apollo-execution] Allow to pass arguments to the root types (#5352) [apollo-ksp] Initial support for interfaces (#5351)
We're continuing to progress towards the stable release of Apollo Kotlin v4 with this 2nd beta, which contains a few bug fixes and a new normalized cache viewer in the IDE plugin.
This is a great time to try out the new version and report any issues you might find!
The IDE plugin now has a graphical tool to inspect a normalized cache database. It lets you browse the records and see their contents. This is useful to debug cache issues, or to understand how the normalized cache works.
The tool is available from View
| Tool Windows
| Apollo Normalized Cache
.
More information about the plugin can be found here.
The first beta of the next major version of Apollo Kotlin is here!
While there still may be a few API changes before the stable release, we are getting close and this is a great time to try out the new version and report any issues you might find!
Many thanks to @baconz and @hbmartin for their awesome contributions to this release!
The GraphQL community is working hard at making it easier to work with nullability in GraphQL.
In Apollo Kotlin, it is now possible to change the nullability of fields and list elements at the schema level using schema extensions. This is useful if you believe the schema made a field nullable for error reasons only and you don't want to handle those errors. In these cases, the whole query will return as an error.
Given the following SDL:
# schema.graphqls
type Query {
random: Int
list: [String]
required: Int!
}
You can extend it like so:
# extra.graphqls
extend type Query {
# make random non-nullable
random: Int!
# make list and list items non-nullable
list: [String!]!
# make required nullable
required: Int
# add a new field
new: Float
}
generateMethods
option to control which model methods are generated (#5212)By default all Kotlin models, operations, fragments, and input objects are generated as data classes. This means that the Kotlin compiler will
auto-generate toString
, equals
hashCode
, copy
and componentN
. If you don't think you need all of those
methods, and/or you are worried about the size of the generated code, you can now choose which methods to generate with the generateMethods
option:
apollo {
service("service") {
// Generates equals/hashCode
generateMethods.set(listOf("equalsHashCode"))
// Also generates toString, equals, and hashcode
generateMethods.set(listOf("equalsHashCode", "toString"))
// Only generates copy
generateMethods.set(listOf("copy"))
// Generates data classes (the default)
generateMethods.set(listOf("dataClass"))
}
}
Enum.values()
is no longer recommended when using Kotlin 1.9+ and the generated code now uses entries
instead (#5208)Optional<V>.getOrThrow()
when V is nullable (#5192)useV3ExceptionHandling
only throws when there are no errors populated (#5231)urlEncode
algorithm (#5234)keyFields
on non-existent fields (#5215)mergeExtensions
and toFullSchemaGQLDocument
(#5162)Optional<V>.getOrThrow()
when V is nullable (#5192)registerOperations {}
(#5196)generateMethods
options to control which methods are generated on "data" classes (#5212)A lot of additions to the IntelliJ plugin as well as a new GraphQL parser, a new Ktor multiplatform engine and more!
Apollo Kotlin wouldn't be where it is today without the awesome feedback, discussions and contributions from community members. Specifically in this release, we want to give a huge THANK YOU to: @Emplexx, @sonatard, @yt8492, @mayakoneval, @Meschreiber, @pcarrier and @ashare80
The IntelliJ plugin now detects unused fields in your queries and greys them out:
https://github.com/apollographql/apollo-kotlin/assets/372852/6a573a78-4a07-4294-8fa5-92a9ebb02e6c
The IntelliJ plugin can migrate most of your codebase to v4. To try it out, go to:
Tools
-> Apollo
-> Migrate to Apollo Kotlin 4
Because Kotlin is such a rich language and we can't account for all possible ways to configure your build, you might have to do some manual tweaks after the migration. But the plugin should handle most of the repetitive tasks of migrating.
If you configured introspection, you can now download your schema directly from IntelliJ
The IntelliJ plugin now has its own dedicated documentation page.
Consult it to find out everything you can do with the plugin as well as installation instructions.
Apollo AST, the GraphQL parser powering Apollo Kotlin is now a manually written recursive descent parser, compared to an automatically generated Antlr parser before. Benchmarks show a x2 to x3 speed improvement and the parser also now supports all platforms Apollo Kotlin supports.
Client Controlled Nullability (CCN) is a GraphQL specification RFC aiming at making it easier to work with GraphQL in type safe languages like Kotlin and Swift.
To use CCN, use the !
and ?
CCN modifiers in your queries:
query GetUser {
user {
id
# name is required to display the user
name!
# phoneNumber is optional
phoneNumber?
}
}
The RFC is still in early stages and requires server support. The API and final shape of the RFC might still change. By adding support in Apollo Kotlin, we're hoping to unblock potential users and gather real life feedbacks helping the proposal move forward.
Apollo Kotlin now ships a apollo-engine-ktor
that you can use to replace the default HTTP and WebSocket engines of ApolloClient. To use it, add apollo-engine-ktor
to your dependencies:
dependencies {
implementation("com.apollographql.apollo3:apollo-engine-ktor")
}
And configure your client to use it:
val apolloClient = ApolloClient.Builder()
.serverUrl("https://example.com/graphql")
.httpEngine(KtorHttpEngine())
.webSocketEngine(KtorWebSocketEngine())
.build()
generateInputBuilders
(#5146)For Kotlin codegen, Apollo Kotlin relied on constructors with default arguments. While this works well in most cases, default arguments lack the ability to distinguish between null
and absent
meaning you have to wrap your values in Optional
before passing them to your constructor. If you had a lot of values, it could be cumbersome:
val input = SignupMemberInput(
dob = Utils.changeDateFormat(user.dobMMDDYYYY, "MM/dd/yyyy", "yyyy-MM-dd"),
firstName = Optional.Present(user.firstName),
lastName = user.lastName,
ssLast4 = Optional.Present(user.ssnLastFour),
email = user.email,
cellPhone = Optional.Present(user.phone),
password = user.password,
acceptedTos = true,
formIds = Optional.Present(formIds),
medium = Optional.Present(ConsentMediumEnum.android)
)
To generate Kotlin Builders, set generateInputBuilders
to true in your Gradle file:
apollo {
service("api") {
packageName.set("com.example")
generateInputBuilders.set(true)
}
}
With Builders, the same above code can be written in a more fluent way:
val input = SignupMemberInput.builder().apply {
dob(Utils.changeDateFormat(user.dobMMDDYYYY, "MM/dd/yyyy", "yyyy-MM-dd"))
firstName(user.firstName)
lastName(user.lastName)
ssLast4(user.ssnLastFour)
email(user.email)
cellPhone(user.phone)
password(user.password)
acceptedTos(true)
formIds(formIds)
medium(ConsentMediumEnum.ANDROID)
}.build()
Object
(#5156)useV3ExceptionHandling(true)
to ApolloClient.Builder()
. (#5135)A new alpha with updates to the IntelliJ/Android Studio plugin and better JS interop.
You can now navigate from Kotlin both GraphQL or Generated code:
https://github.com/apollographql/apollo-kotlin/assets/3974977/acd4bf34-db35-4442-a7af-b6151701620c
See blog the blog post and installation instructions for more information.
You can now connect the IJ/AS plugin to your GraphOS account. If your backend is configured to report field traces, the plugin will display a warning for expensive fields that may be slow to fetch.
You can configure it in your IJ/AS settings Languages & Frameworks
-> GraphQL
-> Apollo Kotlin
. See also #5048 for a video of the setup.
@jsExport
responseBased
codegen can now generate models annotated with @jsExport. This allows to fetch your response using faster JS-only APIs and cast them to the generated models. See the JS interoperability documentation for more information. Many thanks to @baconz for the deep dive π
Service.operationManifestFormat
(#4981)A maintenance release with bugfixes, mostly around WebSockets and subscriptions as well as a LocalTime adapter and options to work with operation manifests.
Huge THANK YOU to @baconz, @AlexHartford, @Oleur for the love they put in WebSocket contributions as well as @Jephuff for their first contribution π .
Service.operationManifestFormat
(#4981)watch()
(#4914)