Skip to content
🤔 Documentation issue? Report or edit

How Ktorfit works under the hood

Ktorfit consists of three main components KSP-Plugin, Compiler plugin and the Ktorfit lib

KSP-Plugin

This will generate the code for the implementation of the interfaces

Compiler plugin

This transforms the create() function from the Ktorfit lib

Ktorfit lib

A wrapper around Ktor to simplify code generation

Example

package com.example

import com.example.model.People
import de.jensklingenberg.ktorfit.http.GET

interface ExampleApi  {
    @GET("/test")
    suspend fun exampleGet(): People
}
Let`s say we have a interface like this.

At compile time Ktorfit/KSP checks for all functions that are annotated with Ktorfit annotations like @GET.

Then it looks at the parent interfaces of that functions and generates, the source code of a Kotlin class that implements the interface. The classes are named like the interfaces but with an underscore at the beginning and “Impl” at the end, and they have the same package as the interfaces. In this case a class named _ExampleApiImpl will be generated.

@OptIn(InternalKtorfitApi::class)
public class _ExampleApiImpl(
    private val _ktorfit: Ktorfit,
) : ExampleApi {
    public val _converter: KtorfitConverterHelper = KtorfitConverterHelper(_ktorfit)

    override suspend fun exampleGet(): People {
        val _ext: HttpRequestBuilder.() -> Unit = {
            method = HttpMethod.parse("GET")
            url{
                takeFrom(_ktorfit.baseUrl + "/test")
            }
        }
        val _typeData = TypeData.createTypeData(qualifiedTypename = "com.example.model.People",
            typeInfo = typeInfo<People>())

        return _converter.suspendRequest<People, People>(_typeData,_ext)!!
    }
}

public fun Ktorfit.createExampleApi(): ExampleApi = this.create(_ExampleApiImpl(this))

The next part is the compiler plugin which is added by the gradle plugin. It looks for the every usage of the create function from the Ktorfit-lib and adds an object of the wanted implementation class as an argument. Because of the naming convention of the generated classes we can deduce the name of the class from the name of type parameter.

val api = jvmKtorfit.create<ExampleApi>()

will be transformed to:

val api = jvmKtorfit.create<ExampleApi>(_ExampleApiImpl(jvmKtorfit))

The create() function is used, checks that the compiler plugin replaced the default value

public fun <T> create(data: T? = null): T {
    if (data == null) {
        throw IllegalArgumentException(ENABLE_GRADLE_PLUGIN)
    }
    return data
}

Last update: October 29, 2023