Skip to content

Commit

Permalink
Adding the get playlist info api. (#13)
Browse files Browse the repository at this point in the history
  • Loading branch information
rubenquadros authored Apr 27, 2024
1 parent e2bde05 commit e7b5c57
Show file tree
Hide file tree
Showing 9 changed files with 23,314 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import io.github.rubenquadros.kovibes.api.response.Categories
import io.github.rubenquadros.kovibes.api.response.ErrorBody
import io.github.rubenquadros.kovibes.api.response.Genres
import io.github.rubenquadros.kovibes.api.response.NewAlbumReleases
import io.github.rubenquadros.kovibes.api.response.Playlist
import io.github.rubenquadros.kovibes.api.response.PlaylistTracks
import io.github.rubenquadros.kovibes.api.response.Playlists
import io.github.rubenquadros.kovibes.api.response.Recommendations
Expand Down Expand Up @@ -48,6 +49,24 @@ interface SpotifyService {
offset: Int = 0
): SpotifyApiResponse<Playlists, ErrorBody>

/**
* Get playlist API returns information about the current playlist.
*
* See the [Spotify doc](https://developer.spotify.com/documentation/web-api/reference/get-playlist).
*
* @param id
* @param market
* @param fields
* @param additionalTypes
* @return [Playlist] when success and [ErrorBody] when error.
*/
suspend fun getPlaylist(
id: String,
market: String? = null,
fields: List<String>? = null,
additionalTypes: List<String> = listOf("track")
): SpotifyApiResponse<Playlist, ErrorBody>

/**
* Get playlist tracks API returns all the tracks for a particular playlist.
* This is a paginated API.
Expand All @@ -70,7 +89,8 @@ interface SpotifyService {
suspend fun getPlaylistTracks(
id: String,
market: String? = null,
fields: String? = null,
fields: List<String>? = null,
additionalTypes: List<String> = listOf("track"),
limit: Int = 20,
offset: Int = 0
): SpotifyApiResponse<PlaylistTracks, ErrorBody>
Expand Down Expand Up @@ -212,7 +232,7 @@ interface SpotifyService {
*
* The recommendations are returned from the information provided via [GetRecommendationsRequest].
*
* See [Spotify Doc](https://developer.spotify.com/documentation/web-api/reference/get-recommendations).
* See the [Spotify Doc](https://developer.spotify.com/documentation/web-api/reference/get-recommendations).
*
* @param getRecommendationsRequest
* @return [Recommendations] when success and [ErrorBody] when error.
Expand All @@ -224,7 +244,7 @@ interface SpotifyService {
/**
* Get artist API returns the information about the artist.
*
* See [Spotify Doc](https://developer.spotify.com/documentation/web-api/reference/get-an-artist).
* See the [Spotify Doc](https://developer.spotify.com/documentation/web-api/reference/get-an-artist).
*
* @param id
* @return [Artist] when success and [ErrorBody] when error.
Expand All @@ -241,7 +261,7 @@ interface SpotifyService {
*
* You can know if there are more pages from [Albums.isNext].
*
* See [Spotify doc](https://developer.spotify.com/documentation/web-api/reference/get-an-artists-albums).
* See the [Spotify doc](https://developer.spotify.com/documentation/web-api/reference/get-an-artists-albums).
*
* @param id
* @param includeGroups
Expand All @@ -261,7 +281,7 @@ interface SpotifyService {
/**
* Get artist top tracks API returns the top tracks of the artist.
*
* See [Spotify doc](https://developer.spotify.com/documentation/web-api/reference/get-an-artists-top-tracks).
* See the [Spotify doc](https://developer.spotify.com/documentation/web-api/reference/get-an-artists-top-tracks).
*
* @param id
* @param market
Expand All @@ -275,7 +295,7 @@ interface SpotifyService {
/**
* Get related artists API returns the artists similar to the given artist.
*
* See [Spotify doc](https://developer.spotify.com/documentation/web-api/reference/get-an-artists-related-artists).
* See the [Spotify doc](https://developer.spotify.com/documentation/web-api/reference/get-an-artists-related-artists).
*
* @param id
* @return [RelatedArtists] when success and [ErrorBody] when error.
Expand All @@ -285,7 +305,7 @@ interface SpotifyService {
/**
* Get album API returns the details about an album.
*
* See [Spotify doc](https://developer.spotify.com/documentation/web-api/reference/get-an-album).
* See the [Spotify doc](https://developer.spotify.com/documentation/web-api/reference/get-an-album).
*
* @param id
* @param market
Expand All @@ -303,7 +323,7 @@ interface SpotifyService {
*
* You can know if there are more pages from [Tracks.isNext].
*
* See [Spotify doc](https://developer.spotify.com/documentation/web-api/reference/get-an-albums-tracks).
* See the [Spotify doc](https://developer.spotify.com/documentation/web-api/reference/get-an-albums-tracks).
*
* @param id
* @param market
Expand All @@ -328,7 +348,7 @@ interface SpotifyService {
*
* You can know if there are more pages from [NewAlbumReleases.isNext].
*
* See [Spotify doc](https://developer.spotify.com/documentation/web-api/reference/get-new-releases).
* See the [Spotify doc](https://developer.spotify.com/documentation/web-api/reference/get-new-releases).
*
* @param limit
* @param offset
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import io.github.rubenquadros.kovibes.api.browse.toCategories
import io.github.rubenquadros.kovibes.api.mapper.toAlbum
import io.github.rubenquadros.kovibes.api.mapper.toAlbums
import io.github.rubenquadros.kovibes.api.mapper.toArtist
import io.github.rubenquadros.kovibes.api.mapper.toPlayList
import io.github.rubenquadros.kovibes.api.playlist.PlaylistApi
import io.github.rubenquadros.kovibes.api.playlist.toFeaturedPlayLists
import io.github.rubenquadros.kovibes.api.playlist.toPlaylistTracks
Expand All @@ -27,6 +28,7 @@ import io.github.rubenquadros.kovibes.api.response.Categories
import io.github.rubenquadros.kovibes.api.response.ErrorBody
import io.github.rubenquadros.kovibes.api.response.Genres
import io.github.rubenquadros.kovibes.api.response.NewAlbumReleases
import io.github.rubenquadros.kovibes.api.response.Playlist
import io.github.rubenquadros.kovibes.api.response.PlaylistTracks
import io.github.rubenquadros.kovibes.api.response.Playlists
import io.github.rubenquadros.kovibes.api.response.Recommendations
Expand Down Expand Up @@ -67,14 +69,27 @@ internal class SpotifyServiceImpl(
return response.getParsedApiResponse { it.toFeaturedPlayLists() }
}

override suspend fun getPlaylist(
id: String,
market: String?,
fields: List<String>?,
additionalTypes: List<String>
): SpotifyApiResponse<Playlist, ErrorBody> {
val response = playlistApi.getPlaylist(id, market, fields, additionalTypes)

return response.getParsedApiResponse { it.toPlayList() }
}

override suspend fun getPlaylistTracks(
id: String,
market: String?,
fields: String?,
fields: List<String>?,
additionalTypes: List<String>,
limit: Int,
offset: Int
): SpotifyApiResponse<PlaylistTracks, ErrorBody> {
val response = playlistApi.getPlaylistTracks(id, market, fields, limit, offset)
val response =
playlistApi.getPlaylistTracks(id, market, fields, additionalTypes, limit, offset)

return response.getParsedApiResponse { it.toPlaylistTracks() }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ internal data class PlaylistInfo(
@SerialName("owner")
val owner: PlaylistOwner,
@SerialName("primary_color")
val primaryColor: String?,
val primaryColor: String? = null,
@SerialName("public")
val public: Boolean? = null,
@SerialName("snapshot_id")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.github.rubenquadros.kovibes.api.playlist

import io.github.rubenquadros.kovibes.api.ApiResponse
import io.github.rubenquadros.kovibes.api.models.PlaylistInfo
import io.github.rubenquadros.kovibes.api.playlist.models.FeaturedPlaylistsResponse
import io.github.rubenquadros.kovibes.api.playlist.models.PlaylistTracksResponse
import io.github.rubenquadros.kovibes.api.response.ErrorBody
Expand All @@ -26,6 +27,22 @@ internal interface PlaylistApi {
offset: Int
): ApiResponse<FeaturedPlaylistsResponse, ErrorBody>

/**
* Get playlist API returns the information about the playlist.
*
* @param id
* @param market
* @param fields
* @param additionalTypes
* @return [PlaylistInfo] when success and [ErrorBody] when error.
*/
suspend fun getPlaylist(
id: String,
market: String?,
fields: List<String>?,
additionalTypes: List<String>
): ApiResponse<PlaylistInfo, ErrorBody>

/**
* Get playlist tracks API returns all the tracks for the current playlist.
*
Expand All @@ -39,7 +56,8 @@ internal interface PlaylistApi {
suspend fun getPlaylistTracks(
id: String,
market: String?,
fields: String?,
fields: List<String>?,
additionalTypes: List<String>,
limit: Int,
offset: Int
): ApiResponse<PlaylistTracksResponse, ErrorBody>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package io.github.rubenquadros.kovibes.api.playlist
import io.github.rubenquadros.kovibes.api.ApiResponse
import io.github.rubenquadros.kovibes.api.KtorService
import io.github.rubenquadros.kovibes.api.getParsedHttpResponse
import io.github.rubenquadros.kovibes.api.models.PlaylistInfo
import io.github.rubenquadros.kovibes.api.playlist.models.FeaturedPlaylistsResponse
import io.github.rubenquadros.kovibes.api.playlist.models.PlaylistTracksResponse
import io.github.rubenquadros.kovibes.api.response.ErrorBody
Expand Down Expand Up @@ -48,10 +49,36 @@ internal class PlaylistApiImpl(
return response.getParsedHttpResponse()
}

override suspend fun getPlaylist(
id: String,
market: String?,
fields: List<String>?,
additionalTypes: List<String>
): ApiResponse<PlaylistInfo, ErrorBody> {
val response = withContext(dispatcher) {
ktorService.client.get {
url {
path("v1/playlists/$id")

parameters.appendAll(
StringValues.build {
market?.let { this["market"] = market }
fields?.let { this["fields"] = fields.joinToString { it } }
this["additional_types"] = additionalTypes.joinToString { it }
}
)
}
}
}

return response.getParsedHttpResponse()
}

override suspend fun getPlaylistTracks(
id: String,
market: String?,
fields: String?,
fields: List<String>?,
additionalTypes: List<String>,
limit: Int,
offset: Int
): ApiResponse<PlaylistTracksResponse, ErrorBody> {
Expand All @@ -63,7 +90,8 @@ internal class PlaylistApiImpl(
parameters.appendAll(
StringValues.build {
market?.let { this["market"] = market }
fields?.let { this["fields"] = fields }
fields?.let { this["fields"] = fields.joinToString { it } }
this["additional_types"] = additionalTypes.joinToString { it }
this["limit"] = limit.toString()
this["offset"] = offset.toString()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,45 @@ class PlaylistApiTest {
response.assertApiResponseFailure()
}

@Test
fun `when playlist info spotify api responds success then result is received`() = runTest {
MockKtorService.isSuccess = true

val response = playlistApi.getPlaylist(
id = "456",
market = "US",
fields = listOf("description"),
additionalTypes = listOf("track")
)

response.assertApiResponseSuccess(
{ it.id == "37i9dQZF1DXdGUQjVlqY2Q" }
)
}

@Test
fun `when playlist info spotify api responds error then failure is received`() = runTest {
MockKtorService.isSuccess = false

val response = playlistApi.getPlaylist(
id = "456",
market = null,
fields = null,
additionalTypes = listOf("track")
)

response.assertApiResponseFailure()
}

@Test
fun `when playlist tracks spotify api responds success then result is received`() = runTest {
MockKtorService.isSuccess = true

val response = playlistApi.getPlaylistTracks(
id = "123",
market = null,
fields = null,
market = "US",
fields = listOf("description"),
additionalTypes = listOf("track"),
limit = 20,
offset = 0
)
Expand All @@ -68,6 +99,7 @@ class PlaylistApiTest {
id = "123",
market = null,
fields = null,
additionalTypes = listOf("track"),
limit = 20,
offset = 0
)
Expand All @@ -80,6 +112,10 @@ class PlaylistApiTest {
expectedSuccessResponsePath = "playlist/featured_playlists.json",
expectedErrorResponsePath = errorResponsePath
),
"playlists/456" to MockResponse(
expectedSuccessResponsePath = "playlist/playlist.json",
expectedErrorResponsePath = errorResponsePath
),
"playlists/123/tracks" to MockResponse(
expectedSuccessResponsePath = "playlist/playlist_tracks.json",
expectedErrorResponsePath = errorResponsePath
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.github.rubenquadros.kovibes.api.test.service

import io.github.rubenquadros.kovibes.api.ApiResponse
import io.github.rubenquadros.kovibes.api.models.PlaylistInfo
import io.github.rubenquadros.kovibes.api.playlist.PlaylistApi
import io.github.rubenquadros.kovibes.api.playlist.models.FeaturedPlaylistsResponse
import io.github.rubenquadros.kovibes.api.playlist.models.PlaylistTracksResponse
Expand All @@ -25,10 +26,22 @@ internal class FakePlaylistApi : PlaylistApi {
}
}

override suspend fun getPlaylist(
id: String,
market: String?,
fields: List<String>?,
additionalTypes: List<String>
): ApiResponse<PlaylistInfo, ErrorBody> {
return getApiResponse(isSuccess) {
json.decodeFromString(getExpectedResponse("playlist/playlist.json"))
}
}

override suspend fun getPlaylistTracks(
id: String,
market: String?,
fields: String?,
fields: List<String>?,
additionalTypes: List<String>,
limit: Int,
offset: Int
): ApiResponse<PlaylistTracksResponse, ErrorBody> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,26 @@ class SpotifyServiceTest {
response.assertSpotifyApiError()
}

@Test
fun `when get playlist info responds success then response is received`() = runTest {
FakePlaylistApi.isSuccess = true

val response = spotifyService.getPlaylist("123")

response.assertSpotifyApiSuccess(
{ it.id == "37i9dQZF1DXdGUQjVlqY2Q" }
)
}

@Test
fun `when get playlist info responds error then error is received`() = runTest {
FakePlaylistApi.isSuccess = false

val response = spotifyService.getPlaylist("123")

response.assertSpotifyApiError()
}

@Test
fun `when get playlist tracks responds success then response is received`() = runTest {
FakePlaylistApi.isSuccess = true
Expand Down
Loading

0 comments on commit e7b5c57

Please sign in to comment.