-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Issue #7 - Move http and serialization to common
Move to coroutines. Create a fake `app-ios-lib` module as a workaround for JetBrains/kotlin-native#2423. Update `app-ios` project due to changed framework name. Add Ktor-client. Add tests. Use server version "2.0". Bump self version to "1.0.0".
- Loading branch information
Showing
50 changed files
with
530 additions
and
218 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
3 changes: 3 additions & 0 deletions
3
app-android/src/main/kotlin/name/antonsmirnov/notes/app/controller/rest/RestApiExt.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
package name.antonsmirnov.notes.app.controller.rest | ||
|
||
lateinit var restApiInstance: RestApi |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
plugins { | ||
id 'idea' | ||
id 'kotlin-multiplatform' | ||
id 'kotlinx-serialization' | ||
} | ||
|
||
kotlin { | ||
targets { | ||
jvm() | ||
iosX64() // iOS simulator | ||
} | ||
|
||
sourceSets { | ||
commonMain { | ||
dependencies { | ||
implementation 'org.jetbrains.kotlin:kotlin-stdlib' | ||
api "io.ktor:ktor-client-core:$rootProject.ktor_version" | ||
api "io.ktor:ktor-client-serialization:$rootProject.ktor_version" | ||
api "name.antonsmirnov.notes:app-api-metadata:$rootProject.server_module_version" | ||
// 'app-api' ^ has 'kotlinx-coroutines-core-common' and 'kotlinx-coroutines-core' so no need to import here | ||
} | ||
} | ||
jvmMain { | ||
dependencies { | ||
implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk8' | ||
// some ktor-client engine impl dependency is requires in end module, | ||
// (see https://ktor.io/clients/http-client/engines.html) | ||
implementation "io.ktor:ktor-client-apache:$rootProject.ktor_version" | ||
api "io.ktor:ktor-client-serialization-jvm:$rootProject.ktor_version" | ||
api "org.jetbrains.kotlinx:kotlinx-serialization-runtime:$rootProject.serialization_version" | ||
api "name.antonsmirnov.notes:app-api-jvm:$rootProject.server_module_version" | ||
} | ||
} | ||
jvmTest { | ||
dependencies { | ||
implementation 'org.jetbrains.kotlin:kotlin-test' | ||
implementation 'org.jetbrains.kotlin:kotlin-test-junit' | ||
implementation "com.nhaarman.mockitokotlin2:mockito-kotlin:$mockito_kotlin_version" | ||
implementation 'com.github.tomakehurst:wiremock-jre8:2.25.1' | ||
implementation 'org.slf4j:slf4j-simple:1.7.30' // for wiremock | ||
} | ||
} | ||
iosX64Main { | ||
dependencies { | ||
implementation "io.ktor:ktor-client-ios:$rootProject.ktor_version" | ||
implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime-native:$rootProject.serialization_version" | ||
implementation "io.ktor:ktor-client-serialization-native:$rootProject.ktor_version" | ||
api "name.antonsmirnov.notes:app-api-iosx64:$rootProject.server_module_version" | ||
api "org.jetbrains.kotlinx:kotlinx-coroutines-core-native:$rootProject.coroutines_version" | ||
} | ||
} | ||
} | ||
|
||
// All exceptions in Kotlin are not checked, but in Swift they are checked. | ||
// So we need @Throws annotation for iOS compatibility to generate swift signatures with `.. throws -> ..` | ||
// This requires @ExperimentalMultiplatform annotation in all methods with @Throws. | ||
// In order to prevent adding @ExperimentalMultiplatform every here and there we can use compiler option: | ||
targets.all { | ||
compilations.all { | ||
kotlinOptions { | ||
freeCompilerArgs += '-Xuse-experimental=kotlin.ExperimentalMultiplatform' | ||
} | ||
} | ||
} | ||
} | ||
|
||
version = "$rootProject.module_version" |
14 changes: 14 additions & 0 deletions
14
...or/src/commonMain/kotlin/name/antonsmirnov/notes/app/controller/rest/AddNoteController.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
package name.antonsmirnov.notes.app.controller.rest | ||
|
||
import name.antonsmirnov.notes.usecase.AddNote | ||
import name.antonsmirnov.notes.usecase.NoteJson | ||
|
||
class AddNoteController( | ||
val api: RestApi | ||
) : AddNote { | ||
|
||
override suspend fun execute(request: AddNote.Request): AddNote.Response { | ||
val response = api.addNote(NoteJson(null, request.title, request.body)) | ||
return AddNote.Response(response.id) | ||
} | ||
} |
15 changes: 15 additions & 0 deletions
15
.../src/commonMain/kotlin/name/antonsmirnov/notes/app/controller/rest/ListNotesController.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package name.antonsmirnov.notes.app.controller.rest | ||
|
||
import name.antonsmirnov.notes.usecase.ListNotes | ||
|
||
class ListNotesController( | ||
val api: RestApi | ||
) : ListNotes { | ||
|
||
override suspend fun execute(): ListNotes.Response { | ||
val response = api.listNotes() | ||
return ListNotes.Response(response.notes.map { | ||
ListNotes.Note(it.id, it.title, it.body) | ||
}) | ||
} | ||
} |
36 changes: 36 additions & 0 deletions
36
...ra-rest-ktor/src/commonMain/kotlin/name/antonsmirnov/notes/app/controller/rest/RestApi.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
package name.antonsmirnov.notes.app.controller.rest | ||
|
||
import io.ktor.client.HttpClient | ||
import io.ktor.client.features.json.JsonFeature | ||
import io.ktor.client.features.json.serializer.KotlinxSerializer | ||
import io.ktor.client.request.get | ||
import io.ktor.client.request.url | ||
import name.antonsmirnov.notes.usecase.AddResponseJson | ||
import name.antonsmirnov.notes.usecase.ListResponseJson | ||
import name.antonsmirnov.notes.usecase.NoteJson | ||
|
||
class RestApi(val baseUrl: String) { | ||
private val client = HttpClient { | ||
install(JsonFeature) { | ||
serializer = KotlinxSerializer() | ||
} | ||
} | ||
|
||
private inline fun apiPath(relativePath: String) = "/api$relativePath" | ||
|
||
suspend fun listNotes(): ListResponseJson = client.get { | ||
url { | ||
url(baseUrl) | ||
encodedPath = apiPath("/list") | ||
} | ||
} | ||
|
||
suspend fun addNote(note: NoteJson): AddResponseJson = client.get { | ||
url { | ||
url(baseUrl) | ||
encodedPath = apiPath("/add") | ||
parameters["title"] = note.title | ||
note.body?.let { parameters["body"] = it } | ||
} | ||
} | ||
} |
5 changes: 5 additions & 0 deletions
5
...est-ktor/src/commonMain/kotlin/name/antonsmirnov/notes/app/controller/rest/RestApiImpl.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
package name.antonsmirnov.notes.app.controller.rest | ||
|
||
fun buildRestApiImpl(protocol: String, host: String, port: UInt) : RestApi { | ||
return RestApi("$protocol://$host:$port") | ||
} |
21 changes: 21 additions & 0 deletions
21
app-infra-rest-ktor/src/commonMain/kotlin/name/antonsmirnov/notes/usecase/Dto.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package name.antonsmirnov.notes.usecase | ||
|
||
import kotlinx.serialization.Serializable | ||
|
||
/** | ||
* Add response model | ||
*/ | ||
@Serializable | ||
data class AddResponseJson(val id: String) | ||
|
||
@Serializable | ||
data class NoteJson( | ||
val id: String?, | ||
val title: String, | ||
val body: String?) | ||
|
||
/** | ||
* List response model | ||
*/ | ||
@Serializable | ||
data class ListResponseJson(val notes: Array<NoteJson>) // using of `List` requires custom de-/serializer on K/N |
79 changes: 79 additions & 0 deletions
79
...a-rest-ktor/src/jvmTest/kotlin/name/antonsmirnov/notes/app/controller/rest/RestApiTest.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
package name.antonsmirnov.notes.app.controller.rest | ||
|
||
import com.github.tomakehurst.wiremock.client.WireMock.* | ||
import com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig | ||
import com.github.tomakehurst.wiremock.junit.WireMockRule | ||
import kotlinx.coroutines.runBlocking | ||
import name.antonsmirnov.notes.usecase.NoteJson | ||
import org.junit.Assert.* | ||
import org.junit.Before | ||
import org.junit.Rule | ||
import org.junit.Test | ||
import java.util.* | ||
import kotlin.math.absoluteValue | ||
|
||
class RestApiTest { | ||
private val random = Random() | ||
|
||
@Rule | ||
@JvmField | ||
val wireMockRule = WireMockRule(wireMockConfig().dynamicPort()) | ||
|
||
private lateinit var api: RestApi | ||
|
||
@Before | ||
fun setUp() { | ||
api = RestApi(wireMockRule.baseUrl()) | ||
} | ||
|
||
private fun generateString() = random.nextLong().absoluteValue.toString() | ||
|
||
@Test | ||
fun testAddNote() { | ||
val expectedId = generateString() | ||
val expectedNote = NoteJson(null, generateString(), generateString()) | ||
wireMockRule.stubFor(get(urlMatching("/api/add.*")) | ||
.willReturn(aResponse() | ||
.withStatus(200) | ||
.withHeader("Content-Type", "application/json") | ||
.withBody("""{ "id":"$expectedId" }"""))) | ||
|
||
runBlocking { | ||
val response = api.addNote(expectedNote) | ||
println(response) | ||
assertEquals(expectedId, response.id) | ||
} | ||
|
||
verify(getRequestedFor(urlEqualTo("/api/add?title=${expectedNote.title}&body=${expectedNote.body}"))) | ||
} | ||
|
||
@Test | ||
fun testListNotes() { | ||
val expectedNote = NoteJson(null, generateString(), generateString()) | ||
wireMockRule.stubFor(get(urlEqualTo("/api/list")) | ||
.willReturn(aResponse() | ||
.withStatus(200) | ||
.withHeader("Content-Type", "application/json") | ||
.withBody( | ||
""" | ||
|{ "notes": [ | ||
| { | ||
| "id":"${expectedNote.id}", | ||
| "title":"${expectedNote.title}", | ||
| "body":"${expectedNote.body}" | ||
| } | ||
|]}""".trimMargin()))) | ||
|
||
runBlocking { | ||
val response = api.listNotes() | ||
println(response) | ||
assertNotNull(response.notes) | ||
assertTrue(response.notes.isNotEmpty()) | ||
val actualNote = response.notes.find { | ||
it.title == expectedNote.title && it.body == expectedNote.body | ||
} | ||
assertNotNull(actualNote) | ||
assertNotNull(actualNote!!.id) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.