Spotr

Ktor-like HTTP client for Spotube plugins - builder DSL, JSON, interceptors.

Spotr is the primary HTTP API for plugins. It wraps the HttpClientAPI host service with a Ktor-like builder DSL, automatic kotlinx.serialization JSON, and interceptor chains.

Never call HttpClientAPI.request() directly. Always use Spotr.

Setup

Create one client per API provider, or a shared client with a default base URL:

val client = SpotrClient(httpClient) {
    defaultUrl = "https://api.example.com"
    defaultHeaders {
        set("Authorization", "Bearer $token")
    }
}

Making requests

All HTTP methods are available with a builder DSL:

val response = client.get {
    url { encodedPath = "/v1/search" }
    parameter("q", query)
    parameter("type", "track")
}

val data: SearchResponse = response.body()

POST with a JSON body:

val response = client.post {
    url("https://api.example.com/v1/tracks/save")
    jsonBody(SaveRequest(trackIds))
}

Available methods: get, post, put, delete, patch, head, options.

Response handling

Method Returns Use case
bodyAsText() String Raw text or manual parsing
bodyAsBytes() ByteArray Binary data
body<T>() T JSON deserialization to a @Serializable type

The body<T>() method uses kotlinx.serialization. If a default serializer is set on the client, it uses that; pass one explicitly otherwise.

Interceptors

Sit between your request and the network. Run in registration order. Call context.proceed() to continue the chain, or return early to short-circuit:

val client = SpotrClient(httpClient) {
    interceptor { context ->
        logger.d { "--> ${context.request.method} ${context.request.url}" }
        val response = context.proceed()
        logger.i { "<-- ${response.statusCode}" }
        response
    }

    interceptor { context ->
        context.request.headers.set("Authorization", "Bearer ${getAccessToken()}")
        context.proceed()
    }
}

URL builder

Use url("...") for simple string URLs, or url { ... } for the builder DSL:

client.get {
    url {
        protocol = "https"
        host = "api.example.com"
        encodedPath = "/v2/tracks"
        parameter("market", "US")
    }
}

Custom serialization

Spotr defaults to JsonContentSerializer (ignores unknown keys). Override:

val client = SpotrClient(httpClient) {
    serializer = JsonContentSerializer(Json {
        ignoreUnknownKeys = true
        isLenient = true
        explicitNulls = false
    })
}

Implement ContentSerializer for non-JSON formats.