mirror of
https://github.com/msfjarvis/compose-lobsters
synced 2025-08-15 02:57:04 +05:30
refactor(api): use ApiResult
in Shiori and wire into DI
This commit is contained in:
parent
62bffc33fd
commit
25a11bde59
3 changed files with 71 additions and 43 deletions
|
@ -7,6 +7,7 @@
|
||||||
package dev.msfjarvis.claw.api
|
package dev.msfjarvis.claw.api
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
|
import com.slack.eithernet.ApiResult
|
||||||
import dev.msfjarvis.claw.model.shiori.AuthRequest
|
import dev.msfjarvis.claw.model.shiori.AuthRequest
|
||||||
import dev.msfjarvis.claw.model.shiori.AuthResponse
|
import dev.msfjarvis.claw.model.shiori.AuthResponse
|
||||||
import dev.msfjarvis.claw.model.shiori.Bookmark
|
import dev.msfjarvis.claw.model.shiori.Bookmark
|
||||||
|
@ -23,30 +24,32 @@ import retrofit2.http.PUT
|
||||||
private const val SESSION_ID_HEADER = "X-Session-Id"
|
private const val SESSION_ID_HEADER = "X-Session-Id"
|
||||||
|
|
||||||
interface ShioriApi {
|
interface ShioriApi {
|
||||||
@POST("/api/login") suspend fun login(@Body body: AuthRequest): AuthResponse
|
@POST("/api/login") suspend fun login(@Body body: AuthRequest): ApiResult<AuthResponse, Unit>
|
||||||
|
|
||||||
@SuppressLint("RetrofitUsage") // POST without a body is apparently fine?
|
@SuppressLint("RetrofitUsage") // POST without a body is apparently fine?
|
||||||
@POST("/api/logout")
|
@POST("/api/logout")
|
||||||
suspend fun logout(@Header(SESSION_ID_HEADER) sessionId: String)
|
suspend fun logout(@Header(SESSION_ID_HEADER) sessionId: String): ApiResult<Unit, Unit>
|
||||||
|
|
||||||
@GET("/api/bookmarks")
|
@GET("/api/bookmarks")
|
||||||
suspend fun getBookmarks(@Header(SESSION_ID_HEADER) sessionId: String): BookmarksResponse
|
suspend fun getBookmarks(
|
||||||
|
@Header(SESSION_ID_HEADER) sessionId: String,
|
||||||
|
): ApiResult<BookmarksResponse, Unit>
|
||||||
|
|
||||||
@POST("/api/bookmarks")
|
@POST("/api/bookmarks")
|
||||||
suspend fun addBookmark(
|
suspend fun addBookmark(
|
||||||
@Header(SESSION_ID_HEADER) sessionId: String,
|
@Header(SESSION_ID_HEADER) sessionId: String,
|
||||||
@Body bookmarkRequest: BookmarkRequest,
|
@Body bookmarkRequest: BookmarkRequest,
|
||||||
): Bookmark
|
): ApiResult<Bookmark, Unit>
|
||||||
|
|
||||||
@PUT("/api/bookmarks")
|
@PUT("/api/bookmarks")
|
||||||
suspend fun editBookmark(
|
suspend fun editBookmark(
|
||||||
@Header(SESSION_ID_HEADER) sessionId: String,
|
@Header(SESSION_ID_HEADER) sessionId: String,
|
||||||
@Body bookmark: EditedBookmark,
|
@Body bookmark: EditedBookmark,
|
||||||
): Bookmark
|
): ApiResult<Bookmark, Unit>
|
||||||
|
|
||||||
@HTTP(method = "DELETE", path = "/api/bookmarks", hasBody = true)
|
@HTTP(method = "DELETE", path = "/api/bookmarks", hasBody = true)
|
||||||
suspend fun deleteBookmark(
|
suspend fun deleteBookmark(
|
||||||
@Header(SESSION_ID_HEADER) sessionId: String,
|
@Header(SESSION_ID_HEADER) sessionId: String,
|
||||||
@Body ids: List<Int>,
|
@Body ids: List<Int>,
|
||||||
): Int
|
): ApiResult<Int, Unit>
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@ import dagger.multibindings.IntKey
|
||||||
import dagger.multibindings.IntoMap
|
import dagger.multibindings.IntoMap
|
||||||
import dev.msfjarvis.claw.api.LobstersApi
|
import dev.msfjarvis.claw.api.LobstersApi
|
||||||
import dev.msfjarvis.claw.api.LobstersSearchApi
|
import dev.msfjarvis.claw.api.LobstersSearchApi
|
||||||
|
import dev.msfjarvis.claw.api.ShioriApi
|
||||||
import dev.msfjarvis.claw.api.converters.CSRFTokenConverter
|
import dev.msfjarvis.claw.api.converters.CSRFTokenConverter
|
||||||
import dev.msfjarvis.claw.api.converters.SearchConverter
|
import dev.msfjarvis.claw.api.converters.SearchConverter
|
||||||
import javax.inject.Qualifier
|
import javax.inject.Qualifier
|
||||||
|
@ -72,6 +73,8 @@ object RetrofitModule {
|
||||||
@Provides
|
@Provides
|
||||||
fun provideSearchApi(@SearchApi retrofit: Retrofit): LobstersSearchApi = retrofit.create()
|
fun provideSearchApi(@SearchApi retrofit: Retrofit): LobstersSearchApi = retrofit.create()
|
||||||
|
|
||||||
|
@Provides fun provideShioriApi(retrofit: Retrofit): ShioriApi = retrofit.create()
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@IntKey(0)
|
@IntKey(0)
|
||||||
@IntoMap
|
@IntoMap
|
||||||
|
|
|
@ -8,11 +8,17 @@ package dev.msfjarvis.claw.api
|
||||||
|
|
||||||
import com.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory
|
import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory
|
||||||
|
import com.slack.eithernet.ApiResultCallAdapterFactory
|
||||||
|
import com.slack.eithernet.ApiResultConverterFactory
|
||||||
|
import com.slack.eithernet.successOrNull
|
||||||
import dev.msfjarvis.claw.model.shiori.AuthRequest
|
import dev.msfjarvis.claw.model.shiori.AuthRequest
|
||||||
import dev.msfjarvis.claw.model.shiori.AuthResponse
|
import dev.msfjarvis.claw.model.shiori.AuthResponse
|
||||||
|
import dev.msfjarvis.claw.model.shiori.Bookmark
|
||||||
import dev.msfjarvis.claw.model.shiori.BookmarkRequest
|
import dev.msfjarvis.claw.model.shiori.BookmarkRequest
|
||||||
|
import dev.msfjarvis.claw.model.shiori.BookmarksResponse
|
||||||
import dev.msfjarvis.claw.model.shiori.EditedBookmark
|
import dev.msfjarvis.claw.model.shiori.EditedBookmark
|
||||||
import dev.msfjarvis.claw.model.shiori.Tag
|
import dev.msfjarvis.claw.model.shiori.Tag
|
||||||
|
import dev.msfjarvis.claw.util.TestUtils.assertIs
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.test.runTest
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
|
@ -31,7 +37,10 @@ class ShioriApiTest {
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
fun setUp() {
|
fun setUp() {
|
||||||
container.start()
|
container.start()
|
||||||
runBlocking { credentials = api.login(AuthRequest(USER, PASSWORD)) }
|
runBlocking {
|
||||||
|
credentials =
|
||||||
|
requireNotNull(api.login(AuthRequest(USER, PASSWORD)).successOrNull()) { "Login failed" }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@AfterEach
|
@AfterEach
|
||||||
|
@ -41,7 +50,8 @@ class ShioriApiTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun getBookmarks() = runTest {
|
fun getBookmarks() = runTest {
|
||||||
val response = api.getBookmarks(credentials.session)
|
val response = api.getBookmarks(credentials.session).successOrNull()
|
||||||
|
assertIs<BookmarksResponse>(response)
|
||||||
assertThat(response.page).isEqualTo(1)
|
assertThat(response.page).isEqualTo(1)
|
||||||
assertThat(response.bookmarks).isEmpty()
|
assertThat(response.bookmarks).isEmpty()
|
||||||
}
|
}
|
||||||
|
@ -49,21 +59,24 @@ class ShioriApiTest {
|
||||||
@Test
|
@Test
|
||||||
fun addBookmark() = runTest {
|
fun addBookmark() = runTest {
|
||||||
val response =
|
val response =
|
||||||
api.addBookmark(
|
api
|
||||||
credentials.session,
|
.addBookmark(
|
||||||
BookmarkRequest(
|
credentials.session,
|
||||||
"https://example.com",
|
BookmarkRequest(
|
||||||
false,
|
"https://example.com",
|
||||||
0,
|
false,
|
||||||
emptyList(),
|
0,
|
||||||
"Example Domain",
|
emptyList(),
|
||||||
"""
|
"Example Domain",
|
||||||
|
"""
|
||||||
This domain is for use in illustrative examples in documents.
|
This domain is for use in illustrative examples in documents.
|
||||||
You may use this domain in literature without prior coordination or asking for permission.
|
You may use this domain in literature without prior coordination or asking for permission.
|
||||||
"""
|
"""
|
||||||
.trimIndent(),
|
.trimIndent(),
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
.successOrNull()
|
||||||
|
assertIs<Bookmark>(response)
|
||||||
assertThat(response.url).isEqualTo("https://example.com")
|
assertThat(response.url).isEqualTo("https://example.com")
|
||||||
assertThat(response.title).isEqualTo("Example Domain")
|
assertThat(response.title).isEqualTo("Example Domain")
|
||||||
assertThat(response.excerpt)
|
assertThat(response.excerpt)
|
||||||
|
@ -80,21 +93,24 @@ class ShioriApiTest {
|
||||||
@Test
|
@Test
|
||||||
fun editBookmark() = runTest {
|
fun editBookmark() = runTest {
|
||||||
val response =
|
val response =
|
||||||
api.addBookmark(
|
api
|
||||||
credentials.session,
|
.addBookmark(
|
||||||
BookmarkRequest(
|
credentials.session,
|
||||||
"https://example.com",
|
BookmarkRequest(
|
||||||
false,
|
"https://example.com",
|
||||||
0,
|
false,
|
||||||
emptyList(),
|
0,
|
||||||
"Example Domain",
|
emptyList(),
|
||||||
"""
|
"Example Domain",
|
||||||
|
"""
|
||||||
This domain is for use in illustrative examples in documents.
|
This domain is for use in illustrative examples in documents.
|
||||||
You may use this domain in literature without prior coordination or asking for permission.
|
You may use this domain in literature without prior coordination or asking for permission.
|
||||||
"""
|
"""
|
||||||
.trimIndent(),
|
.trimIndent(),
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
.successOrNull()
|
||||||
|
assertIs<Bookmark>(response)
|
||||||
assertThat(response.tags).isEmpty()
|
assertThat(response.tags).isEmpty()
|
||||||
val newBookmark =
|
val newBookmark =
|
||||||
EditedBookmark(
|
EditedBookmark(
|
||||||
|
@ -103,7 +119,8 @@ class ShioriApiTest {
|
||||||
title = response.title,
|
title = response.title,
|
||||||
tags = listOf(Tag("examples")),
|
tags = listOf(Tag("examples")),
|
||||||
)
|
)
|
||||||
val edited = api.editBookmark(credentials.session, newBookmark)
|
val edited = api.editBookmark(credentials.session, newBookmark).successOrNull()
|
||||||
|
assertIs<Bookmark>(edited)
|
||||||
assertThat(edited.tags).isNotEmpty()
|
assertThat(edited.tags).isNotEmpty()
|
||||||
assertThat(edited.tags).containsExactly(Tag("examples"))
|
assertThat(edited.tags).containsExactly(Tag("examples"))
|
||||||
}
|
}
|
||||||
|
@ -111,22 +128,25 @@ class ShioriApiTest {
|
||||||
@Test
|
@Test
|
||||||
fun deleteBookmark() = runTest {
|
fun deleteBookmark() = runTest {
|
||||||
val response =
|
val response =
|
||||||
api.addBookmark(
|
api
|
||||||
credentials.session,
|
.addBookmark(
|
||||||
BookmarkRequest(
|
credentials.session,
|
||||||
"https://example.com",
|
BookmarkRequest(
|
||||||
false,
|
"https://example.com",
|
||||||
0,
|
false,
|
||||||
emptyList(),
|
0,
|
||||||
"Example Domain",
|
emptyList(),
|
||||||
"""
|
"Example Domain",
|
||||||
|
"""
|
||||||
This domain is for use in illustrative examples in documents.
|
This domain is for use in illustrative examples in documents.
|
||||||
You may use this domain in literature without prior coordination or asking for permission.
|
You may use this domain in literature without prior coordination or asking for permission.
|
||||||
"""
|
"""
|
||||||
.trimIndent(),
|
.trimIndent(),
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
.successOrNull()
|
||||||
val count = api.deleteBookmark(credentials.session, listOf(response.id))
|
assertIs<Bookmark>(response)
|
||||||
|
val count = api.deleteBookmark(credentials.session, listOf(response.id)).successOrNull()
|
||||||
assertThat(count).isEqualTo(1)
|
assertThat(count).isEqualTo(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -144,7 +164,9 @@ class ShioriApiTest {
|
||||||
get() =
|
get() =
|
||||||
Retrofit.Builder()
|
Retrofit.Builder()
|
||||||
.baseUrl("http://${container.host}:${container.firstMappedPort}")
|
.baseUrl("http://${container.host}:${container.firstMappedPort}")
|
||||||
|
.addConverterFactory(ApiResultConverterFactory)
|
||||||
.addConverterFactory(json.asConverterFactory(MediaType.get("application/json")))
|
.addConverterFactory(json.asConverterFactory(MediaType.get("application/json")))
|
||||||
|
.addCallAdapterFactory(ApiResultCallAdapterFactory)
|
||||||
.build()
|
.build()
|
||||||
.create<ShioriApi>()
|
.create<ShioriApi>()
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue