androidretrofitktorktor-client

How to remove a header set using plugin for a particular API request in KTOR


I have created a custom plugin to set headers for requests in ktor

internal fun headersPlugin(defaultHeaders: DefaultHeaders) = createClientPlugin("headersPlugin") {
    onRequest { request, _ ->
        request.headers.apply {
            append("requestFrom", defaultHeaders.requestFrom)
            append("clientType", defaultHeaders.clientType)
            append("User-Agent", defaultHeaders.userAgent)
            append("AUTHTOKEN", defaultHeaders.authToken)
            append("SESSIONID", defaultHeaders.sessionId)
        }
    }
}

Now I want to remove AUTHTOKEN for a purticular API request in

fun getApiClient(): HttpClient = httpClient {

    install(headersPlugin(DefaultHeaders()))


    defaultRequest {
        /* logic to remove AUTHTOKEN header by checking some annotation or something when a purticular API request is annotated or some variable to check */
    }

    /* Logging */
    install(Logging) {
        logger = object : Logger {
            override fun log(message: String) {
                Napier.v("HTTP Client", null, message)
            }
        }

        level = LogLevel.ALL
    }
}.also {
    Napier.base(DebugAntilog())
}

I already use retrofit and I am tring to migrate to KTOR

in retrofit I annotate method in service class with @IGNORE annotation and in interceptor I check for IGNORE annotation and remove the header if present

val tag: Invocation? = request.tag(Invocation::class.java)
        val method: Method? = tag?.method()

        builder
            .addHeader("requestFrom", networkUtil.requestFrom)
            .addHeader("clientType", "17")
            .addHeader("User-Agent", networkUtil.userAgentInfo)
            .addHeader("AUTHTOKEN", networkUtil.authKey)
            .addHeader("SESSIONID", networkUtil.sessionId)

        method?.also {
            it.getAnnotation(Ignore::class.java)?.run {
                if (this.keyName.contains(Ignore.AUTH_TOKEN)) {
                    builder.removeHeader("AUTHTOKEN")
                }
    
                if (!this.keyName.contains(Ignore.BASE_URL)) {
                    builder.url(reformedUrl)
                }

                if (this.keyName.contains(Ignore.SESSION_ID) || networkUtil.sessionId.isEmpty()) {
                    builder.removeHeader("SESSIONID")
                }
            } ?: run {
                builder.url(reformedUrl)
            }

Solution

  • You can use Attributes to control which default headers must be included in the request. You can have a specific attribute key for the AUTHTOKEN header to avoid sending it when the attribute is present. Here is an example:

    val disableAuthKey = AttributeKey<Boolean>("noAuthKey")
    fun headersPlugin(defaultHeaders: DefaultHeaders) = createClientPlugin("headersPlugin") {
        onRequest { request, _ ->
            request.headers.apply {
                if (!request.attributes.contains(disableAuthKey)) {
                    append("AUTHTOKEN", defaultHeaders.authToken)
                }
            }
        }
    }
    
    suspend fun main() {
        val client = HttpClient(OkHttp) {
            install(headersPlugin(DefaultHeaders()))
        }
    
        client.get("https://httpbin.org/get") {
            attributes.put(disableAuthKey, true)
        }
    }