Skip to content

Codegen Migration

Maxwell edited this page Jul 24, 2026 · 3 revisions

Switching to Code Generation

This guide covers migrating an existing retrofit-graphql project from the asset-based workflow (@GraphQuery + QueryContainerBuilder + .graphql files in assets/) to the build-time code generation workflow.

Note: The asset-based workflow remains fully supported. Code generation is an optional enhancement, not a replacement. You can also use both approaches in the same project.

Why Switch?

Asset-Based Codegen
@GraphQuery annotation on Retrofit methods Generated operation constants and request helpers
QueryContainerBuilder for manual variable construction Typed variable classes with named parameters
Runtime file discovery from assets/ Build-time document registry — no runtime file I/O
String-based variable keys Type-safe variable classes
No enum generation GraphQL enums generated as Kotlin enum classes

Step 1: Apply the Plugin

plugins {
    id("co.anitrend.retrofit.graphql.codegen") version "{tag}"
}

Step 2: Move .graphql Files

Move your .graphql files from assets/graphql/ to src/main/graphql/:

# Before
app/src/main/assets/graphql/queries/GetMarketPlaceApps.graphql

# After
app/src/main/graphql/queries/GetMarketPlaceApps.graphql

Add the schema file:

app/src/main/graphql/schema.graphql

Step 3: Configure the DSL

retrofitGraphQL {
    packageName.set("your.package.generated")
    schema.set(file("src/main/graphql/schema.graphql"))
    operations.from(fileTree("src/main/graphql") {
        include("**/*.graphql")
    })
    common {
        generateVariables.set(true)
        generateResponses.set(true) // optional response model generation
    }
    scalars {
        // Map any custom scalars in your schema
        map("DateTime", "kotlin.String")
        map("GitObjectID", "kotlin.String")
    }
}

Step 4: Update Dependencies

Remove direct :android-assets and :annotations dependencies — they are no longer needed for codegen-only projects:

// Before
dependencies {
    implementation(project(":runtime"))
    implementation(project(":api"))
    implementation(project(":android-assets"))
    implementation(project(":annotations"))
}

// After
dependencies {
    implementation(project(":runtime"))
    implementation(project(":api"))
}

:runtime still pulls :android-assets and :annotations transitively, so asset-based fallback remains available if needed.

Step 5: Update Converter Wiring

Replace manual converter construction with the registry-based factory:

// Before
val factory = GraphConverter(
    processor = GraphProcessor(AssetManagerDiscoveryPlugin(context.assets)),
    gson = Gson(),
)

// After
val factory = GraphConverter.create(
    context = context,
    registry = GeneratedGraphQLRegistry,
)

Step 6: Update Retrofit Interface

Replace @GraphQuery + QueryContainerBuilder with GraphQLRequest:

// Before
@POST("/graphql")
@GraphQuery("GetMarketPlaceApps")
suspend fun getMarketPlaceApps(
    @Body builder: QueryContainerBuilder,
): Response<GraphContainer<MarketPlaceListings>>

// After
@POST("/graphql")
suspend fun getMarketPlaceApps(
    @Body request: GraphQLRequest<GetMarketPlaceAppsVariables>,
): Response<GraphContainer<MarketPlaceListings>>

If you enable generateResponses, you can also replace hand-written payload DTOs with generated operation-scoped response models:

suspend fun getMarketPlaceApps(
    @Body request: GraphQLRequest<GetMarketPlaceAppsVariables>,
): Response<GraphContainer<GetMarketPlaceAppsData>>

Step 7: Update Call Sites

Replace QueryContainerBuilder with generated request helpers:

// Before
val builder = QueryContainerBuilder()
    .putVariable("first", 15)
    .putVariable("after", cursor)
service.getMarketPlaceApps(builder)

// After
val request = GetMarketPlaceApps.request(
    first = 15,
    after = cursor,
)
service.getMarketPlaceApps(request)

Step 8: Handle File Uploads

For multipart uploads, add a RequestBodyPassThroughConverterFactory before the GraphConverter:

Retrofit.Builder()
    .addConverterFactory(RequestBodyPassThroughConverterFactory())
    .addConverterFactory(GraphConverter.create(context, registry = GeneratedGraphQLRegistry))
    .baseUrl(baseUrl)
    .build()

Use the generated operation metadata:

val request = UploadToStorageBucket.request(upload = filePath)
// Build MultipartBody from the GraphQLRequest fields

See GraphQL File Uploads for details.

Gradual Migration

You don't have to migrate everything at once. Both workflows can coexist:

  1. Apply the codegen plugin alongside existing @GraphQuery usage.
  2. Migrate one operation at a time — remove @GraphQuery from a method and switch to GraphQLRequest.
  3. Enable generateResponses only for operations where you want generated payload models.
  4. Once all operations are migrated, remove :annotations and :android-assets direct dependencies.

Further Reading

Clone this wiki locally