Full reference for every KtorToCurlConfig / CurlOptions option. Each section is a standalone,
runnable example — see the README for a quick start.
import io.github.kabirnayeem99.ktor2curl.KtorToCurl
import io.github.kabirnayeem99.ktor2curl.CurlLogger
import io.ktor.client.HttpClient
import io.ktor.client.engine.cio.CIO
val client = HttpClient(CIO) {
install(KtorToCurl) {
logger = CurlLogger.console()
}
}Every request sent through client now logs a curl command.
Implement CurlLogger to send curl output anywhere: Logcat, a file, a remote debug dashboard.
import io.github.kabirnayeem99.ktor2curl.CurlLogger
import io.github.kabirnayeem99.ktor2curl.KtorToCurl
class RemoteCurlLogger : CurlLogger {
override suspend fun log(curl: String) {
analyticsService.trackRequest(curl)
}
}
val client = HttpClient(CIO) {
install(KtorToCurl) {
logger = RemoteCurlLogger()
}
}Replace a header's value with [masked] instead of dropping it, so the header is still visible
but the secret is not.
install(KtorToCurl) {
logger = CurlLogger.console()
maskedHeaders = setOf(HttpHeaders.Authorization, "X-API-Key")
}curl -H 'Authorization: [masked]' 'https://api.example.com/users'Drop noisy headers (User-Agent, Content-Length) from the rendered output.
install(KtorToCurl) {
logger = CurlLogger.console()
excludedHeaders = setOf(HttpHeaders.UserAgent, HttpHeaders.ContentLength)
}install(KtorToCurl) {
logger = CurlLogger.console()
maskedQueryParams = setOf("token", "api_key")
}A request to https://api.example.com/search?token=secret&q=kotlin renders with
token=[masked]&q=kotlin.
Deep-redacts matching keys inside a JSON request body, at any nesting depth.
install(KtorToCurl) {
logger = CurlLogger.console()
maskedJsonKeys = setOf("password", "ssn")
}A body of {"user":"alice","password":"hunter2"} renders with "password":"[masked]".
install(KtorToCurl) {
logger = CurlLogger.console()
maskedHeaders = setOf(HttpHeaders.Authorization)
maskPlaceholder = "<redacted>"
}Pick the quoting style for the shell you paste the output into.
import io.github.kabirnayeem99.ktor2curl.CurlShell
install(KtorToCurl) {
logger = CurlLogger.console()
shell = CurlShell.PowerShell // or CurlShell.Posix (default), CurlShell.WindowsCmd
}install(KtorToCurl) {
logger = CurlLogger.console()
maxBodyLength = 2000 // characters; longer bodies get a trailing "...[truncated]" indicator
}Multipart bodies larger than this are not read into memory; they render as
[multipart body omitted] instead.
install(KtorToCurl) {
logger = CurlLogger.console()
maxMultipartBytes = 512 * 1024 // 512 KiB, default is 1 MiB
}install(KtorToCurl) {
logger = CurlLogger.console()
insecure = true // --insecure
compressed = true // --compressed
followRedirects = true // -L
connectTimeoutSeconds = 5 // --connect-timeout 5
maxTimeSeconds = 30 // --max-time 30
retry = 3 // --retry 3
}Split arguments across lines with \ continuations, for readability in logs.
install(KtorToCurl) {
logger = CurlLogger.console()
multiLine = true
}install(KtorToCurl) {
logger = CurlLogger.console()
showHeaders = false // omit all -H arguments
showBody = false // omit --data-binary / -F
}Runs after masking and exclusion, so a masked header's real value is never exposed to the
transformer. Return null to drop a value.
install(KtorToCurl) {
logger = CurlLogger.console()
headerTransformer = { name, value ->
if (name == "Authorization") value.removePrefix("Bearer ") else value
}
}install(KtorToCurl) {
logger = CurlLogger.console()
shouldLog = { request -> !request.url.encodedPath.startsWith("/health") }
}toCurl() is a suspend extension on HttpRequestBuilder for one-off renders, tests, or custom
pipelines.
import io.github.kabirnayeem99.ktor2curl.toCurl
import io.github.kabirnayeem99.ktor2curl.CurlOptions
import io.ktor.client.request.HttpRequestBuilder
val request = HttpRequestBuilder().apply {
url("https://api.example.com/users")
method = HttpMethod.Post
setBody("""{"name":"Alice"}""")
}
println(request.toCurl())
println(request.toCurl(CurlOptions(maskedHeaders = setOf("Authorization"))))Renders correctly out of the box, no extra config needed.
client.post("https://api.example.com/upload") {
setBody(MultiPartFormDataContent(formData {
append("file", InputProvider { "file content".byteInputStream() },
Headers.build { append(HttpHeaders.ContentDisposition, "filename=data.txt") })
append("field", "value")
}))
}curl 'https://api.example.com/upload' -F 'file=@data.txt' -F 'field=value'