icerockdev / moko-network

Network components with codegeneration of rest api for mobile (android & ios) Kotlin Multiplatform development
https://moko.icerock.dev
Apache License 2.0
154 stars 30 forks source link

Append CURL-style logging feature for HttpClient #6

Open DevTchernov opened 4 years ago

Alex009 commented 3 years ago

here implementation - https://gist.github.com/adevone/34e95f20560316a21453a9baaa90c5b6

import io.ktor.client.request.HttpRequest
import io.ktor.content.TextContent
import java.util.*

class CurlBuilder(
    request: HttpRequest,
    private val ignoreHeaders: List<String> = emptyList()
) {
    private val url: String = request.url.toString()
    private val method: String = request.method.value
    private var contentType: String? = null
    private var body: String? = null
    private val headers = LinkedList<Header>()

    init {
        val content = request.content
        if (content.contentType != null) {
            this.contentType = content.contentType.toString()
            this.body = (content as TextContent).text
        }

        request.headers.forEach { name, values ->
            val header = Header(name, values[0])
            this.headers.add(header)
        }
    }

    fun build(): String {
        val parts = ArrayList<String>()
        parts.add("curl")
        parts.add(String.format(FORMAT_METHOD, method.toUpperCase()))

        parts.add(String.format(FORMAT_URL, url))

        for (header in headers) {
            if (header.name !in ignoreHeaders) {
                val headerPart = String.format(FORMAT_HEADER, header.name, header.value)
                parts.add(headerPart)
            }
        }

        if (contentType != null && !containsName(CONTENT_TYPE, headers) && CONTENT_TYPE !in ignoreHeaders) {
            parts.add(String.format(FORMAT_HEADER, CONTENT_TYPE, contentType))
        }

        if (body != null) {
            parts.add(String.format(FORMAT_BODY, body))
        }

        return parts.joinToString(" ")
    }

    private fun containsName(name: String, headers: List<Header>): Boolean {
        for (header in headers) {
            if (header.name == name) {
                return true
            }
        }
        return false
    }

    companion object {
        private const val FORMAT_HEADER = "-H \"%1\$s:%2\$s\""
        private const val FORMAT_METHOD = "-X %1\$s"
        private const val FORMAT_BODY = "-d '%1\$s'"
        private const val FORMAT_URL = "\"%1\$s\""
        private const val CONTENT_TYPE = "Content-Type"
    }
}

private data class Header(
    val name: String,
    val value: String
)

thx to @adevone :)