first commit

This commit is contained in:
Raymond Yang
2023-05-15 16:02:39 +08:00
commit 7c2839cade
18 changed files with 632 additions and 0 deletions
@@ -0,0 +1,13 @@
package com.ray650128
import com.ray650128.plugins.configureRouting
import com.ray650128.plugins.configureSerialization
import io.ktor.server.engine.*
import io.ktor.server.netty.*
fun main() {
embeddedServer(Netty, port = 8080, host = "0.0.0.0") {
configureRouting()
configureSerialization()
}.start(wait = true)
}
@@ -0,0 +1,10 @@
package com.ray650128.dto
import kotlinx.serialization.Serializable
@Serializable
data class PersonDto(
val id: String? = null,
val name: String,
val age: Int
)
@@ -0,0 +1,17 @@
package com.ray650128.extension
import com.ray650128.dto.PersonDto
import com.ray650128.model.Person
fun Person.toDto(): PersonDto =
PersonDto(
id = this.id.toString(),
name = this.name,
age = this.age
)
fun PersonDto.toPerson(): Person =
Person(
name = this.name,
age = this.age
)
@@ -0,0 +1,11 @@
package com.ray650128.model
import kotlinx.serialization.Serializable
@Serializable
data class ErrorResponse(val message: String) {
companion object {
val NOT_FOUND_RESPONSE = ErrorResponse("Person was not found")
val BAD_REQUEST_RESPONSE = ErrorResponse("Invalid request")
}
}
@@ -0,0 +1,11 @@
package com.ray650128.model
import org.bson.codecs.pojo.annotations.BsonId
import org.litote.kmongo.Id
data class Person(
@BsonId
val id: Id<Person>? = null,
val name: String,
val age: Int
)
@@ -0,0 +1,75 @@
package com.ray650128.plugins
import com.ray650128.dto.PersonDto
import com.ray650128.extension.toDto
import com.ray650128.extension.toPerson
import com.ray650128.model.ErrorResponse
import com.ray650128.model.Person
import com.ray650128.service.PersonService
import io.ktor.http.*
import io.ktor.server.routing.*
import io.ktor.server.response.*
import io.ktor.server.application.*
import io.ktor.server.request.*
fun Application.configureRouting() {
val service = PersonService()
routing {
get("/") {
call.respondText("Hello World!")
}
route("/person") {
post {
val request = call.receive<PersonDto>()
val person = request.toPerson()
service.create(person)
?.let { userId ->
call.response.headers.append("My-User-Id-Header", userId.toString())
call.respond(HttpStatusCode.Created)
} ?: call.respond(HttpStatusCode.BadRequest, ErrorResponse.BAD_REQUEST_RESPONSE)
}
get {
val peopleList = service.findAll().map(Person::toDto)
call.respond(peopleList)
}
get("/{id}") {
val id = call.parameters["id"].toString()
service.findById(id)
?.let { foundPerson -> call.respond(foundPerson.toDto()) }
?: call.respond(HttpStatusCode.NotFound, ErrorResponse.NOT_FOUND_RESPONSE)
}
get("/search") {
val name = call.request.queryParameters["name"].toString()
val foundPeople = service.findByName(name).map(Person::toDto)
call.respond(foundPeople)
}
put("/{id}") {
val id = call.parameters["id"].toString()
val personRequest = call.receive<PersonDto>()
val person = personRequest.toPerson()
val updatedSuccessfully = service.updateById(id, person)
if (updatedSuccessfully) {
call.respond(HttpStatusCode.NoContent)
} else {
call.respond(HttpStatusCode.BadRequest, ErrorResponse.BAD_REQUEST_RESPONSE)
}
}
delete("/{id}") {
val id = call.parameters["id"].toString()
val deletedSuccessfully = service.deleteById(id)
if (deletedSuccessfully) {
call.respond(HttpStatusCode.NoContent)
} else {
call.respond(HttpStatusCode.NotFound, ErrorResponse.NOT_FOUND_RESPONSE)
}
}
}
}
}
@@ -0,0 +1,18 @@
package com.ray650128.plugins
import io.ktor.serialization.kotlinx.json.*
import io.ktor.server.plugins.contentnegotiation.*
import io.ktor.server.response.*
import io.ktor.server.application.*
import io.ktor.server.routing.*
fun Application.configureSerialization() {
install(ContentNegotiation) {
json()
}
routing {
get("/json/kotlinx-serialization") {
call.respond(mapOf("hello" to "world"))
}
}
}
@@ -0,0 +1,40 @@
package com.ray650128.service
import com.ray650128.model.Person
import org.bson.types.ObjectId
import org.litote.kmongo.*
import org.litote.kmongo.id.toId
class PersonService {
private val client = KMongo.createClient("mongodb://www.ray650128.com:27017")
private val database = client.getDatabase("person")
private val personCollection = database.getCollection<Person>()
fun create(person: Person): Id<Person>? {
personCollection.insertOne(person)
return person.id
}
fun findAll(): List<Person> = personCollection.find().toList()
fun findById(id: String): Person? {
val bsonId: Id<Person> = ObjectId(id).toId()
return personCollection.findOne(Person::id eq bsonId)
}
fun findByName(name: String): List<Person> {
val caseSensitiveTypeSafeFilter = Person::name regex name
return personCollection.find(caseSensitiveTypeSafeFilter).toList()
}
fun updateById(id: String, request: Person): Boolean =
findById(id)?.let { person ->
val updateResult = personCollection.replaceOne(person.copy(name = request.name, age = request.age))
updateResult.modifiedCount == 1L
} ?: false
fun deleteById(id: String): Boolean {
val deleteResult = personCollection.deleteOneById(ObjectId(id))
return deleteResult.deletedCount == 1L
}
}
+12
View File
@@ -0,0 +1,12 @@
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<root level="trace">
<appender-ref ref="STDOUT"/>
</root>
<logger name="org.eclipse.jetty" level="INFO"/>
<logger name="io.netty" level="INFO"/>
</configuration>
@@ -0,0 +1,21 @@
package com.ray650128
import io.ktor.client.request.*
import io.ktor.client.statement.*
import io.ktor.server.testing.*
import kotlin.test.*
import io.ktor.http.*
import com.ray650128.plugins.*
class ApplicationTest {
@Test
fun testRoot() = testApplication {
application {
configureRouting()
}
client.get("/").apply {
assertEquals(HttpStatusCode.OK, status)
assertEquals("Hello World!", bodyAsText())
}
}
}