Update example application
This commit is contained in:
parent
b6bb3aafaa
commit
97d0567489
@ -7,7 +7,7 @@ plugins {
|
|||||||
}
|
}
|
||||||
|
|
||||||
application {
|
application {
|
||||||
mainClassName = "io.ktor.server.netty.DevelopmentEngine"
|
mainClassName = "io.ktor.server.netty.EngineMain"
|
||||||
}
|
}
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
ktorVersion=0.9.0
|
ktorVersion=1.0.0-beta-3
|
||||||
logbackVersion=1.2.3
|
logbackVersion=1.2.3
|
||||||
|
@ -27,6 +27,7 @@ import com.github.michaelbull.result.mapBoth
|
|||||||
import com.github.michaelbull.result.mapError
|
import com.github.michaelbull.result.mapError
|
||||||
import com.github.michaelbull.result.toResultOr
|
import com.github.michaelbull.result.toResultOr
|
||||||
import io.ktor.application.Application
|
import io.ktor.application.Application
|
||||||
|
import io.ktor.application.ApplicationCall
|
||||||
import io.ktor.application.call
|
import io.ktor.application.call
|
||||||
import io.ktor.application.install
|
import io.ktor.application.install
|
||||||
import io.ktor.features.CallLogging
|
import io.ktor.features.CallLogging
|
||||||
@ -35,12 +36,12 @@ import io.ktor.features.ContentNegotiation
|
|||||||
import io.ktor.features.DefaultHeaders
|
import io.ktor.features.DefaultHeaders
|
||||||
import io.ktor.gson.gson
|
import io.ktor.gson.gson
|
||||||
import io.ktor.http.HttpStatusCode
|
import io.ktor.http.HttpStatusCode
|
||||||
|
import io.ktor.http.Parameters
|
||||||
import io.ktor.request.receive
|
import io.ktor.request.receive
|
||||||
import io.ktor.response.respond
|
import io.ktor.response.respond
|
||||||
import io.ktor.routing.get
|
import io.ktor.routing.get
|
||||||
import io.ktor.routing.post
|
import io.ktor.routing.post
|
||||||
import io.ktor.routing.routing
|
import io.ktor.routing.routing
|
||||||
import io.ktor.util.ValuesMap
|
|
||||||
|
|
||||||
fun Application.main() {
|
fun Application.main() {
|
||||||
install(DefaultHeaders)
|
install(DefaultHeaders)
|
||||||
@ -52,30 +53,35 @@ fun Application.main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
routing {
|
routing {
|
||||||
get("/customers/{id}") {
|
get("/customers/{id}") {
|
||||||
readId(call.parameters)
|
call.parameters.readId()
|
||||||
.andThen(CustomerId.Companion::create)
|
.andThen(CustomerId.Companion::create)
|
||||||
.andThen(CustomerService::getById)
|
.andThen(CustomerService::getById)
|
||||||
.mapError(::messageToResponse)
|
.mapError(::messageToResponse)
|
||||||
.mapBoth(
|
.mapBoth(
|
||||||
{ call.respond(HttpStatusCode.OK, CustomerDto.from(it)) },
|
success = { customer ->
|
||||||
{ call.respond(it.first, it.second) }
|
call.respond(HttpStatusCode.OK, CustomerDto.from(customer))
|
||||||
|
},
|
||||||
|
failure = { (status, message) ->
|
||||||
|
call.respond(status, message)
|
||||||
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
post("/customers/{id}") {
|
post("/customers/{id}") {
|
||||||
readId(call.parameters)
|
call.parameters.readId()
|
||||||
.andThen {
|
.andThen { id ->
|
||||||
val dto = call.receive<CustomerDto>()
|
val dto = call.receive<CustomerDto>()
|
||||||
dto.id = it
|
dto.id = id
|
||||||
Ok(dto)
|
Ok(dto)
|
||||||
}
|
}
|
||||||
.andThen(Customer.Companion::from)
|
.andThen(Customer.Companion::from)
|
||||||
.andThen(CustomerService::upsert)
|
.andThen(CustomerService::upsert)
|
||||||
.mapError(::messageToResponse)
|
.mapError(::messageToResponse)
|
||||||
.mapBoth(
|
.mapBoth(
|
||||||
{ event ->
|
success = { event ->
|
||||||
if (event == null) {
|
if (event == null) {
|
||||||
call.respond(HttpStatusCode.NotModified)
|
call.respond(HttpStatusCode.NotModified)
|
||||||
} else {
|
} else {
|
||||||
@ -83,15 +89,17 @@ fun Application.main() {
|
|||||||
call.respond(status, message)
|
call.respond(status, message)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{ call.respond(it.first, it.second) }
|
failure = { (status, message) ->
|
||||||
|
call.respond(status, message)
|
||||||
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun readId(values: ValuesMap): Result<Long, DomainMessage> {
|
private fun Parameters.readId(): Result<Long, DomainMessage> {
|
||||||
return values["id"]
|
return this["id"]
|
||||||
?.toLongOrNull()
|
?.toLongOrNull()
|
||||||
.toResultOr { CustomerRequired }
|
.toResultOr { CustomerRequired }
|
||||||
}
|
}
|
||||||
|
@ -2,18 +2,22 @@ package com.github.michaelbull.result.example.model.domain
|
|||||||
|
|
||||||
import com.github.michaelbull.result.Err
|
import com.github.michaelbull.result.Err
|
||||||
import com.github.michaelbull.result.Ok
|
import com.github.michaelbull.result.Ok
|
||||||
|
import com.github.michaelbull.result.Result
|
||||||
|
|
||||||
data class EmailAddress(
|
data class EmailAddress(
|
||||||
val address: String
|
val address: String
|
||||||
) {
|
) {
|
||||||
companion object {
|
companion object {
|
||||||
private val pattern = ".+@.+\\..+".toRegex() // crude validation
|
private const val MAX_LENGTH = 20
|
||||||
|
private val PATTERN = ".+@.+\\..+".toRegex() // crude validation
|
||||||
|
|
||||||
fun create(address: String?) = when {
|
fun create(address: String?): Result<EmailAddress, DomainMessage> {
|
||||||
address == null || address.isBlank() -> Err(EmailRequired)
|
return when {
|
||||||
address.length > 20 -> Err(EmailTooLong)
|
address.isNullOrBlank() -> Err(EmailRequired)
|
||||||
!address.matches(pattern) -> Err(EmailInvalid)
|
address.length > MAX_LENGTH -> Err(EmailTooLong)
|
||||||
else -> Ok(EmailAddress(address))
|
!address.matches(PATTERN) -> Err(EmailInvalid)
|
||||||
|
else -> Ok(EmailAddress(address))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,18 +2,23 @@ package com.github.michaelbull.result.example.model.domain
|
|||||||
|
|
||||||
import com.github.michaelbull.result.Err
|
import com.github.michaelbull.result.Err
|
||||||
import com.github.michaelbull.result.Ok
|
import com.github.michaelbull.result.Ok
|
||||||
|
import com.github.michaelbull.result.Result
|
||||||
|
|
||||||
data class PersonalName(
|
data class PersonalName(
|
||||||
val first: String,
|
val first: String,
|
||||||
val last: String
|
val last: String
|
||||||
) {
|
) {
|
||||||
companion object {
|
companion object {
|
||||||
fun create(first: String?, last: String?) = when {
|
private const val MAX_LENGTH = 10
|
||||||
first == null || first.isBlank() -> Err(FirstNameRequired)
|
|
||||||
last == null || last.isBlank() -> Err(LastNameRequired)
|
fun create(first: String?, last: String?): Result<PersonalName, DomainMessage> {
|
||||||
first.length > 10 -> Err(FirstNameTooLong)
|
return when {
|
||||||
last.length > 10 -> Err(LastNameTooLong)
|
first.isNullOrBlank() -> Err(FirstNameRequired)
|
||||||
else -> Ok(PersonalName(first, last))
|
last.isNullOrBlank() -> Err(LastNameRequired)
|
||||||
|
first.length > MAX_LENGTH -> Err(FirstNameTooLong)
|
||||||
|
last.length > MAX_LENGTH -> Err(LastNameTooLong)
|
||||||
|
else -> Ok(PersonalName(first, last))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
package com.github.michaelbull.result.example.service
|
package com.github.michaelbull.result.example.service
|
||||||
|
|
||||||
import com.github.michaelbull.result.Err
|
|
||||||
import com.github.michaelbull.result.Ok
|
|
||||||
import com.github.michaelbull.result.Result
|
import com.github.michaelbull.result.Result
|
||||||
import com.github.michaelbull.result.andThen
|
import com.github.michaelbull.result.andThen
|
||||||
import com.github.michaelbull.result.example.model.domain.Customer
|
import com.github.michaelbull.result.example.model.domain.Customer
|
||||||
@ -14,6 +12,7 @@ import com.github.michaelbull.result.example.model.domain.DomainMessage
|
|||||||
import com.github.michaelbull.result.example.model.domain.EmailAddressChanged
|
import com.github.michaelbull.result.example.model.domain.EmailAddressChanged
|
||||||
import com.github.michaelbull.result.example.model.entity.CustomerEntity
|
import com.github.michaelbull.result.example.model.entity.CustomerEntity
|
||||||
import com.github.michaelbull.result.map
|
import com.github.michaelbull.result.map
|
||||||
|
import com.github.michaelbull.result.mapAll
|
||||||
import com.github.michaelbull.result.mapBoth
|
import com.github.michaelbull.result.mapBoth
|
||||||
import com.github.michaelbull.result.mapError
|
import com.github.michaelbull.result.mapError
|
||||||
import com.github.michaelbull.result.toResultOr
|
import com.github.michaelbull.result.toResultOr
|
||||||
@ -25,26 +24,18 @@ object CustomerService {
|
|||||||
fun getAll(): Result<Collection<Customer>, DomainMessage> {
|
fun getAll(): Result<Collection<Customer>, DomainMessage> {
|
||||||
return Result.of(repository::findAll)
|
return Result.of(repository::findAll)
|
||||||
.mapError(::exceptionToDomainMessage)
|
.mapError(::exceptionToDomainMessage)
|
||||||
.andThen { result: Collection<CustomerEntity> ->
|
.mapAll(Customer.Companion::from)
|
||||||
Ok(result.map {
|
|
||||||
val customer = Customer.from(it)
|
|
||||||
when (customer) {
|
|
||||||
is Ok -> customer.value
|
|
||||||
is Err -> return customer
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getById(id: CustomerId): Result<Customer, DomainMessage> {
|
fun getById(id: CustomerId): Result<Customer, DomainMessage> {
|
||||||
return getAll().andThen { it.findCustomer(id) }
|
return getAll().andThen { customers -> customers.findCustomer(id) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun upsert(customer: Customer): Result<DomainMessage?, DomainMessage> {
|
fun upsert(customer: Customer): Result<DomainMessage?, DomainMessage> {
|
||||||
val entity = CustomerEntity.from(customer)
|
val entity = CustomerEntity.from(customer)
|
||||||
return getById(customer.id).mapBoth(
|
return getById(customer.id).mapBoth(
|
||||||
{ existing -> updateCustomer(entity, existing, customer) },
|
success = { existing -> updateCustomer(entity, existing, customer) },
|
||||||
{ createCustomer(entity) }
|
failure = { createCustomer(entity) }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
ktor {
|
ktor {
|
||||||
deployment {
|
deployment {
|
||||||
port = 9000
|
port = 9090
|
||||||
}
|
}
|
||||||
|
|
||||||
application {
|
application {
|
||||||
|
@ -35,7 +35,7 @@ inline infix fun <V, E> Result<V, E>.orElse(transform: (E) -> Result<V, E>): Res
|
|||||||
* otherwise this [Ok].
|
* otherwise this [Ok].
|
||||||
*/
|
*/
|
||||||
inline infix fun <V, E> Result<V, E>.recover(transform: (E) -> V): Ok<V> {
|
inline infix fun <V, E> Result<V, E>.recover(transform: (E) -> V): Ok<V> {
|
||||||
return when(this) {
|
return when (this) {
|
||||||
is Ok -> this
|
is Ok -> this
|
||||||
is Err -> Ok(transform(error))
|
is Err -> Ok(transform(error))
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user