menu

Apollo

A community of developers, designers and others who love Apollo and GraphQL. 🚀

Channels
# All channels
view-forward
# General
view-forward
# Apollo Angular
view-forward
# Announcements
view-forward
# Apollo Android
view-forward
# Apollo Client
view-forward
# Apollo iOS
view-forward
# Apollo Link
view-forward
# Apollo Link Rest
view-forward
# Local State
view-forward
# Apollo Studio
view-forward
# Apollo Server
view-forward
# Apollo Tooling
view-forward
# Contributing
view-forward
# Docs
view-forward
# Events
view-forward
# GraphQL Tools
view-forward
# Jobs
view-forward
# Random
view-forward
# React Apollo
view-forward
# Showcase
view-forward
# Subscriptions
view-forward
# Testing
view-forward
# Vue Apollo
view-forward
Team

Fragment or CustomTypeMapping?

February 25, 2021 at 6:52pm

Fragment or CustomTypeMapping?

February 25, 2021 at 6:52pm
I want to reuse data class in graphql auto generated code and after check this post (https://spectrum.chat/thread/3141578b-c8e8-473e-9108-d385394440bf),https://spectrum.chat/apollo/apollo-android/object-oriented-responses~3141578b-c8e8-473e-9108-d385394440bf), I understand fragment can make it and I create a test project (https://github.com/coolcard-app/TestGraphFragment.git) transplanting from official tutorial and it works fine but the fragment always belongs to many class, I think it's a little redundant, ex:LaunchListQuery.Data.launches.fragments.launchesData.launchList What I expect:LaunchListQuery.Data.launchList However I also found customTypeMapping can make my existing data class reuse in graphql auto generated code but i am not sure would it still work it nested data class. (It's the best If the type of auto generated data class is the same as my existing data class)
I'm afraid I don't know Graphql so much and I want to know: Q1. Should I choose Fragment or CustomTypeMapping or any better solution? Q2. If fragment is the best solution ,can I directly get list like LaunchListQuery.Data.launchList?

February 25, 2021 at 7:09pm
Hi 👋!! Fragments are indeed the correct solution here 👍. CustomTypeMapping is only about custom GraphQL scalar types so won't be any help there. Re: Q2, it's something we are looking into by generating fragments as interfaces but it's unfortunately not easy as there can be multiple fragments in the same objects and even fragments inside fragments. If you want an early look, you can check com.apollographql.apollo3:apollo-runtime-kotlin:3.0.0-dev2 but it's all very experimental right now.
like-fill
1
  • reply
  • like

February 26, 2021 at 7:06am
Thanks for your reply. 🙂 But I scalar DateTime to make some field of api return java.util.Date, is it a kind of reusing data class? Below is part of code: Build.gradle(app)
apollo {
customTypeMapping = [
"Upload": "com.apollographql.apollo.api.FileUpload",
"DateTime": "java.util.Date"
]
}
NetworkModule
fun provideCoolCardService(config: NetConfig, okHttpClient: OkHttpClient, myApolloCall: MyApolloCall,
myApolloMutationCall: MyApolloMutationCall): ICoolCardService {
val apolloClient = ApolloClient.builder()
.serverUrl(config.serverUrl)
.okHttpClient(okHttpClient)
.addCustomTypeAdapter(CustomType.DATETIME, dateCustomTypeAdapter)
.build()
return CoolCardService(apolloClient, myApolloCall, myApolloMutationCall)
}
Schema.json
# A datetime string with format `Y-m-d H:i:s`, e.g. `2018-01-01 13:00:00`.
scalar DateTime
type User {
name: String!
created_at: DateTime!
updated_at: DateTime!
}
CustomTypeAdapter.kt
val dateCustomTypeAdapter = object : CustomTypeAdapter<Date> {
val DATE_FORMAT = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINESE)
override fun decode(value: CustomTypeValue<*>): Date {
return try {
DATE_FORMAT.parse(value.value.toString())!!
} catch (e: ParseException) {
throw RuntimeException(e)
}
}
override fun encode(value: Date): CustomTypeValue<*> {
return CustomTypeValue.GraphQLString(DATE_FORMAT.format(value))
}
}
Finally the filed with type DateTime in graphql will change into java.util.Date Below is part of my auto generated code:
public static class User {
static final ResponseField[] $responseFields = {
ResponseField.forString("name", "name", null, false, Collections.<ResponseField.Condition>emptyList()),
ResponseField.forCustomType("created\_at", "created\_at", null, false, CustomType.DATETIME, Collections.<ResponseField.Condition>emptyList()),
ResponseField.forCustomType("updated\_at", "updated\_at", null, false, CustomType.DATETIME, Collections.<ResponseField.Condition>emptyList())
};
final @NotNull String name;
final @NotNull Date created\_at;
final @NotNull Date updated\_at;
...
With this feature I think making some api field return my existing data class is also possible, Do I misunderstand it ?🤔
And I will check com.apollographql.apollo3:apollo-runtime-kotlin:3.0.0-dev2. Thanks again
Edited
  • reply
  • like
Hi 👋, the answer is yes and no :). It's true that you can reuse your classes with customTypeMapping but that will only work for custom scalar types defined in your schema. Your User type is a regular GraphQL type and you won't be able to use customTypeMapping there.
There are multiple reasons for that. The first one being that writing adapters is time consuming and error prone so one of the value of the lib is that it does it for you. One other reason is that generated adapters can work with the cache and normalize records (more about normalization here : https://www.apollographql.com/blog/demystifying-cache-normalization/). Custom scalars are stored in one chunk in the cache so the cache wouldn't be reactive if we were to use that everywhere.
Fragments is generally the way to go for data reuse. If you want to have control over the class, what I generally recommend is to write mappers that can transform the generated model into whatever class you need in your model.
Hope this helps!
  • reply
  • like
It helps, I will take mappers into consideration. No other ideas for the time being🙂 and thank you for your careful explanation.
like-fill
1
  • reply
  • like