
Enables interaction with Deezer's REST API, facilitating artist, album, and track searches. Supports asynchronous operations, advanced queries, and paginated responses, integrating with popular build tools like Gradle and Maven.
A Kotlin Multiplatform client for Deezer’s official REST API. Using Ktor Client. Supports Android (min SDK 24 / JVM 8+), JVM Java, Kotlin/JVM, Kotlin/JS, Kotlin/WasmJs.
[!TIP]
It's recommended to configure Content Encoding to reduce the size of the response.
If you consume a lot of images, consider using Caching
Gradle
// common main
implementation("io.github.kingg22:deezer-client-kt:<latest-version>")Maven
<dependency>
<groupId>io.github.kingg22</groupId>
<artifactId>deezer-client-kt-jvm</artifactId>
<version>current-version</version>
</dependency>Install a Ktor client engine, see detail.
Example with CIO (Coroutines based):
Gradle
implementation("io.ktor:ktor-client-cio:$ktor_version")Maven
<dependency>
<groupId>io.ktor</groupId>
<artifactId>ktor-client-cio-jvm</artifactId>
<version>${ktor_version}</version>
</dependency>val httpClient = HttpClient {
install(DeezerClientPlugin)
// Others configuration
}
val client = DeezerApiClient(httpClient)
val artist: Artist = client.artists.getById(27) // suspend fun
println("Artist: ${artist.name}") // Artist: Daft Punkpublic class Test {
static void main(String[] args) {
final HttpClient httpClient = HttpClientKt.HttpClient(CIO.INSTANCE.create(unused -> null), builder -> {
builder.install(DeezerClientPlugin.INSTANCE, unused -> null);
// Other configuration
return null;
});
final var client = new DeezerApiJavaClient(httpClient);
final Artist artist = client.artists.getById(27);
System.out.println("Artist: " + artist.getName()); // Artist: Daft Punk
}
}import java.util.concurrent.CompletableFuture;
public class Test {
static void main(String[] args) {
final HttpClient httpClient = HttpClientKt.HttpClient(CIO.INSTANCE.create(unused -> null), builder -> {
builder.install(DeezerClientPlugin.INSTANCE, unused -> null);
// Other configuration
return null;
});
final var client = new DeezerApiJavaClient(httpClient);
final CompletableFuture<Artist> future = client.artists.getByIdFuture(27);
future.whenComplete((artist, err) -> {
if (err != null) err.printStackTrace();
else System.out.println("Artist: " + artist.getName()); // Artist: Daft Punk
});
}
}Kotlin
val client: DeezerApiClient // use the same client in the app
val result: PaginatedResponse<Track> = client.searches.search("eminem")
checkNotNull(result.next)
val nextPage: PaginatedResponse<Track> = checkNotNull(tested.fetchNext(client, expand=true))
// because the next is not null, fetchNext don't return null
// expand means the previous data (List<Track>) going to expand with the new response
// fetchNext is an extension function*Java
import java.util.concurrent.CompletableFuture;
public class Test {
static void main(String[] args) {
final DeezerApiJavaClient client; // use the same client in the app
final PaginatedResponse<Track> response = client.searches.search("eminem");
// Blocking
final PaginatedResponse<Track> nextPage = response.fetchNext(client, Track.class, /* expand */ true);
// async
final CompletableFuture<PaginatedResponse<Track>> nextPageFuture =
response.fetchNextFuture(client, Track.class, /* expand */ true);
// Null type is the same, but in java isn't a mandatory check, is recommended!
}
}Kotlin
val client: DeezerApiClient // use the same client in the app
val episode: Episode = client.episodes.getById(526673645) // suspend fun
// after do things ...
val freshEpisode: Episode = episode.reload(client) // suspend funJava (Needs explicit cast, because of abstract Resource)
import java.util.concurrent.CompletableFuture;
class Test {
static void main(String[] args) {
final DeezerApiJavaClient client = "";// use the same client in the app
final Episode episode = client.episodes.getById(526673645);
final Episode freshEpisode = (Episode) episode.reload(client); // blocking
final CompletableFuture<Episode> freshEpisodeFuture =
(CompletableFuture<Episode>) episode.reloadFuture(client); // async
}
}Kotlin
import io.github.kingg22.deezer.client.api.objects.SearchOrder
import io.github.kingg22.deezer.client.api.routes.SearchRoutes.Companion.buildAdvancedQuery
import io.github.kingg22.deezer.client.api.routes.SearchRoutes.Companion.setStrict
import kotlin.time.Duration.Companion.minutes
val client: DeezerApiClient // use the same client in the app
val query = buildAdvancedQuery { // DSL builder
artist = "eminem"
durationMin = 1.minutes
}
client.searches.searchPlaylist(query, strict = setString(true))
client.searches.searchTrack(
q = buildAdvancedQuery(q = "Not Afraid", artist = "eminem"), // function
order = SearchOrder.RANKING,
limit = 15,
index = 10,
)Java
import static io.github.kingg22.deezer.client.api.routes.SearchRoutes.buildAdvancedQuery;
import static io.github.kingg22.deezer.client.api.routes.SearchRoutes.setStrict;
public class Test {
static void main(String[] args) {
final DeezerApiJavaClient client = "";// use the same client in the app
client.searches.searchAlbum(
/* q =*/ buildAdvancedQuery(/* q = */ "King") // Only access to Java builder style
.artist("eminem")
.build(),
/* strict = */ setStrict(true),
/* order = */ SearchOrder.RATING_DESC,
/* index = */ 10,
/* limit = */ 15
);
}
}Why not data class?
Read more about this here. I take the decision to use class with Poko because immutability is guaranteed and equals are generated. The idea of this api client is stateless, fetch what u need, and that's it.
Please include one of the following types in your issue title or description:
Also state if the issue refers to an official Deezer change or unofficial additional field.
We welcome contributions if:
Please fork, open PRs, and ensure tests pass.
Licensed under AGPL-3.0 — contributions must respect Deezer API Terms & Conditions, including attribution and rate‑limit policies.
A Kotlin Multiplatform client for Deezer’s official REST API. Using Ktor Client. Supports Android (min SDK 24 / JVM 8+), JVM Java, Kotlin/JVM, Kotlin/JS, Kotlin/WasmJs.
[!TIP]
It's recommended to configure Content Encoding to reduce the size of the response.
If you consume a lot of images, consider using Caching
Gradle
// common main
implementation("io.github.kingg22:deezer-client-kt:<latest-version>")Maven
<dependency>
<groupId>io.github.kingg22</groupId>
<artifactId>deezer-client-kt-jvm</artifactId>
<version>current-version</version>
</dependency>Install a Ktor client engine, see detail.
Example with CIO (Coroutines based):
Gradle
implementation("io.ktor:ktor-client-cio:$ktor_version")Maven
<dependency>
<groupId>io.ktor</groupId>
<artifactId>ktor-client-cio-jvm</artifactId>
<version>${ktor_version}</version>
</dependency>val httpClient = HttpClient {
install(DeezerClientPlugin)
// Others configuration
}
val client = DeezerApiClient(httpClient)
val artist: Artist = client.artists.getById(27) // suspend fun
println("Artist: ${artist.name}") // Artist: Daft Punkpublic class Test {
static void main(String[] args) {
final HttpClient httpClient = HttpClientKt.HttpClient(CIO.INSTANCE.create(unused -> null), builder -> {
builder.install(DeezerClientPlugin.INSTANCE, unused -> null);
// Other configuration
return null;
});
final var client = new DeezerApiJavaClient(httpClient);
final Artist artist = client.artists.getById(27);
System.out.println("Artist: " + artist.getName()); // Artist: Daft Punk
}
}import java.util.concurrent.CompletableFuture;
public class Test {
static void main(String[] args) {
final HttpClient httpClient = HttpClientKt.HttpClient(CIO.INSTANCE.create(unused -> null), builder -> {
builder.install(DeezerClientPlugin.INSTANCE, unused -> null);
// Other configuration
return null;
});
final var client = new DeezerApiJavaClient(httpClient);
final CompletableFuture<Artist> future = client.artists.getByIdFuture(27);
future.whenComplete((artist, err) -> {
if (err != null) err.printStackTrace();
else System.out.println("Artist: " + artist.getName()); // Artist: Daft Punk
});
}
}Kotlin
val client: DeezerApiClient // use the same client in the app
val result: PaginatedResponse<Track> = client.searches.search("eminem")
checkNotNull(result.next)
val nextPage: PaginatedResponse<Track> = checkNotNull(tested.fetchNext(client, expand=true))
// because the next is not null, fetchNext don't return null
// expand means the previous data (List<Track>) going to expand with the new response
// fetchNext is an extension function*Java
import java.util.concurrent.CompletableFuture;
public class Test {
static void main(String[] args) {
final DeezerApiJavaClient client; // use the same client in the app
final PaginatedResponse<Track> response = client.searches.search("eminem");
// Blocking
final PaginatedResponse<Track> nextPage = response.fetchNext(client, Track.class, /* expand */ true);
// async
final CompletableFuture<PaginatedResponse<Track>> nextPageFuture =
response.fetchNextFuture(client, Track.class, /* expand */ true);
// Null type is the same, but in java isn't a mandatory check, is recommended!
}
}Kotlin
val client: DeezerApiClient // use the same client in the app
val episode: Episode = client.episodes.getById(526673645) // suspend fun
// after do things ...
val freshEpisode: Episode = episode.reload(client) // suspend funJava (Needs explicit cast, because of abstract Resource)
import java.util.concurrent.CompletableFuture;
class Test {
static void main(String[] args) {
final DeezerApiJavaClient client = "";// use the same client in the app
final Episode episode = client.episodes.getById(526673645);
final Episode freshEpisode = (Episode) episode.reload(client); // blocking
final CompletableFuture<Episode> freshEpisodeFuture =
(CompletableFuture<Episode>) episode.reloadFuture(client); // async
}
}Kotlin
import io.github.kingg22.deezer.client.api.objects.SearchOrder
import io.github.kingg22.deezer.client.api.routes.SearchRoutes.Companion.buildAdvancedQuery
import io.github.kingg22.deezer.client.api.routes.SearchRoutes.Companion.setStrict
import kotlin.time.Duration.Companion.minutes
val client: DeezerApiClient // use the same client in the app
val query = buildAdvancedQuery { // DSL builder
artist = "eminem"
durationMin = 1.minutes
}
client.searches.searchPlaylist(query, strict = setString(true))
client.searches.searchTrack(
q = buildAdvancedQuery(q = "Not Afraid", artist = "eminem"), // function
order = SearchOrder.RANKING,
limit = 15,
index = 10,
)Java
import static io.github.kingg22.deezer.client.api.routes.SearchRoutes.buildAdvancedQuery;
import static io.github.kingg22.deezer.client.api.routes.SearchRoutes.setStrict;
public class Test {
static void main(String[] args) {
final DeezerApiJavaClient client = "";// use the same client in the app
client.searches.searchAlbum(
/* q =*/ buildAdvancedQuery(/* q = */ "King") // Only access to Java builder style
.artist("eminem")
.build(),
/* strict = */ setStrict(true),
/* order = */ SearchOrder.RATING_DESC,
/* index = */ 10,
/* limit = */ 15
);
}
}Why not data class?
Read more about this here. I take the decision to use class with Poko because immutability is guaranteed and equals are generated. The idea of this api client is stateless, fetch what u need, and that's it.
Please include one of the following types in your issue title or description:
Also state if the issue refers to an official Deezer change or unofficial additional field.
We welcome contributions if:
Please fork, open PRs, and ensure tests pass.
Licensed under AGPL-3.0 — contributions must respect Deezer API Terms & Conditions, including attribution and rate‑limit policies.