Skip to content

Commit

Permalink
refactor: improved code readability and objects nomenclature
Browse files Browse the repository at this point in the history
  • Loading branch information
j0a0m4 committed Jun 20, 2023
1 parent 22ec97e commit b06e82f
Show file tree
Hide file tree
Showing 34 changed files with 401 additions and 304 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,27 @@ package io.j0a0m4.portsandadapters.adapter.driven

import io.j0a0m4.portsandadapters.adapter.NoSuchUUID
import io.j0a0m4.portsandadapters.domain.model.*
import io.j0a0m4.portsandadapters.domain.usecases.ContactStorage
import io.j0a0m4.portsandadapters.domain.usecases.dependencies.ContactRepository
import org.springframework.stereotype.Repository
import java.util.*

@Repository
class InMemoryContactStorage() : ContactStorage, MutableMap<UUID, Contact> by HashMap() {
class InMemoryContactRepository() : ContactRepository, MutableMap<UUID, Contact> by HashMap() {
override infix fun persist(contact: Contact) {
this[contact.id] = contact
}

override fun update(contactId: UUID, status: VerifiedStatus) =
updateStatus(contactId, status)

override fun findBy(contactId: UUID): Result<Contact> = get(contactId).let {
if (it != null) {
Result.success(it)
} else {
Result.failure(NoSuchUUID(contactId))
override fun findBy(contactId: UUID): Result<Contact> =
when (val contact = this[contactId]) {
null -> Result.failure(NoSuchUUID(contactId))
else -> Result.success(contact)
}
}

private fun updateStatus(contactId: UUID, newStatus: VerifiedStatus) =
findBy(contactId)
.map { it.patch { verifiedStatus = newStatus } }
.map { it.update { verifiedStatus = newStatus } }
.onSuccess { this[contactId] = it }
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@ import io.j0a0m4.portsandadapters.adapter.NoSuchOtpKey
import io.j0a0m4.portsandadapters.domain.model.SendMethod
import io.j0a0m4.portsandadapters.domain.model.VerificationCode
import io.j0a0m4.portsandadapters.domain.usecases.OtpRecord
import io.j0a0m4.portsandadapters.domain.usecases.OtpStorage
import io.j0a0m4.portsandadapters.domain.usecases.dependencies.OtpRepository
import org.springframework.stereotype.Repository
import java.security.InvalidKeyException
import java.util.*

@Repository
class InMemoryOtpStorage : OtpStorage, MutableMap<Pair<UUID, SendMethod>, VerificationCode> by HashMap() {
class InMemoryOtpRepository : OtpRepository, MutableMap<Pair<UUID, SendMethod>, VerificationCode> by HashMap() {
override fun persist(record: OtpRecord) {
this += record.toMap()
this += record.make()
}

override fun retrieveOtp(key: Pair<UUID, SendMethod>) =
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
package io.j0a0m4.portsandadapters.adapter.driven

import io.j0a0m4.portsandadapters.domain.usecases.OtpRecord
import io.j0a0m4.portsandadapters.domain.usecases.OtpSender
import io.j0a0m4.portsandadapters.domain.usecases.dependencies.Sender
import org.slf4j.LoggerFactory
import org.springframework.stereotype.Service

@Service
class OtpSenderImpl() : OtpSender {
class OtpSender() : Sender {
private val logger = LoggerFactory.getLogger(javaClass)
override fun send(record: OtpRecord) {

override infix fun send(record: OtpRecord) {
// TODO: Implement integration
logger.info("[ ${javaClass.simpleName} ] sent ${record.otp} to ${record.method}")
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package io.j0a0m4.portsandadapters.adapter.driver.http

import io.j0a0m4.portsandadapters.adapter.driver.http.request.*
import io.j0a0m4.portsandadapters.adapter.driver.http.response.toResponse
import io.j0a0m4.portsandadapters.domain.usecases.ContactUseCases
import org.springframework.stereotype.Controller
import org.springframework.web.reactive.function.server.*

@Controller
class ContactHandlers(
val contactPort: ContactUseCases,
val failureHandler: FailureHandler
) {

suspend fun createOne(request: ServerRequest) =
with(request) {
toContact()
}.let { contact ->
contactPort add contact
}.map { id ->
request locationOf id
}.run {
fold(
onSuccess = { ServerResponse.created(it) },
onFailure = failureHandler::invoke
)
}.run {
buildAndAwait()
}

suspend fun getOne(request: ServerRequest) =
with(request) {
pathId
}.let { contactId ->
contactPort findBy contactId
}.map { contact ->
contact.toResponse
}.run {
fold(
onSuccess = { ServerResponse.ok().bodyValueAndAwait(it) },
onFailure = { failureHandler(it).buildAndAwait() }
)
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package io.j0a0m4.portsandadapters.adapter.driver.http.response
package io.j0a0m4.portsandadapters.adapter.driver.http

import io.j0a0m4.portsandadapters.adapter.NoSuchKeyException
import io.j0a0m4.portsandadapters.domain.usecases.DomainException
import io.j0a0m4.portsandadapters.domain.DomainException
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.web.bind.annotation.ControllerAdvice
Expand All @@ -11,12 +11,12 @@ import org.springframework.web.reactive.function.server.ServerResponse
class FailureHandler() {
val logger: Logger = LoggerFactory.getLogger(javaClass)

operator fun invoke(e: Throwable) =
operator fun invoke(e: Throwable?) =
when (e) {
is NoSuchKeyException -> ServerResponse.notFound()
is DomainException -> ServerResponse.unprocessableEntity()
else -> ServerResponse.badRequest()
else -> ServerResponse.badRequest()
}.also {
logger.warn("FailureHandler [ ${e.javaClass.simpleName} ] ${e.message}")
logger.warn("FailureHandler [ ${e?.javaClass?.simpleName} ] ${e?.message}")
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package io.j0a0m4.portsandadapters.adapter.driver.http

import io.j0a0m4.portsandadapters.adapter.driver.http.request.*
import io.j0a0m4.portsandadapters.domain.usecases.OtpUseCases
import org.springframework.stereotype.Controller
import org.springframework.web.reactive.function.server.*

@Controller
class OtpHandlers(
private val otpPort: OtpUseCases,
private val failureHandler: FailureHandler
) {
suspend fun createOne(request: ServerRequest) =
with(request) {
pathId to sendMethod
}.let { (contactId, method) ->
otpPort.send(contactId, method)
}.run {
ServerResponse.accepted().buildAndAwait()
}

suspend fun verifyOne(request: ServerRequest) =
with(request) {
toVerifyOtpCommand()
}.let { (contactId, sendMethod, otp) ->
otpPort.verify(contactId, sendMethod, otp)
}.run {
fold(
onSuccess = { ServerResponse.noContent() },
onFailure = failureHandler::invoke
)
}.run {
buildAndAwait()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package io.j0a0m4.portsandadapters.adapter.driver.http

import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.http.MediaType.APPLICATION_JSON
import org.springframework.web.reactive.function.server.coRouter


@Configuration
class Routes {

@Bean
fun otpRoutes(handlers: OtpHandlers) = coRouter {
"/api/contact".nest {
accept(APPLICATION_JSON).nest {
POST("/{id}/otp", handlers::createOne)
PATCH("/{id}", handlers::verifyOne)
}
}
}

@Bean
fun contactRoutes(handler: ContactHandlers) = coRouter {
"/api".nest {
accept(APPLICATION_JSON).nest {
POST("/contact", handler::createOne)
GET("/contact/{id}", handler::getOne)
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import org.springframework.web.reactive.function.server.awaitBody

data class AddContactRequest(val name: String, val email: String, val phone: String)

suspend fun ServerRequest.parseContact() =
suspend fun ServerRequest.toContact() =
awaitBody<AddContactRequest>().run {
contact {
it.name = name
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,7 @@ import org.springframework.web.reactive.function.server.awaitBody

data class PatchContactRequest(val method: SendMethod, val otp: VerificationCode)

suspend fun ServerRequest.parseVerification() =
awaitBody<PatchContactRequest>()
suspend fun ServerRequest.toVerifyOtpCommand()=
awaitBody<PatchContactRequest>().run {
Triple(pathId, method, otp)
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ package io.j0a0m4.portsandadapters.adapter.driver.http.request
import io.j0a0m4.portsandadapters.domain.model.SendMethod
import org.springframework.web.reactive.function.server.ServerRequest

fun ServerRequest.parseMethod(): SendMethod =
queryParam("sendMethod")
val ServerRequest.sendMethod: SendMethod
get() = queryParam("sendMethod")
.map { SendMethod from it }
.orElseThrow()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ package io.j0a0m4.portsandadapters.adapter.driver.http.request
import org.springframework.web.reactive.function.server.ServerRequest
import java.util.*

fun ServerRequest.parseId(): UUID =
UUID.fromString(pathVariable("id"))
val ServerRequest.pathId: UUID
get() = UUID.fromString(pathVariable("id"))

infix fun ServerRequest.locationOf(id: UUID) = uriBuilder()
.path("/{id}")
.build(id.toString())
.build(id.toString())
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@ data class ContactResponse(
)

val Contact.toResponse: ContactResponse
get() = ContactResponse(verifiedStatus, name.first, name.last, phone.value, email.value)
get() = ContactResponse(verifiedStatus, name.first, name.last, phone.value, email.value)
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package io.j0a0m4.portsandadapters.domain.usecases
package io.j0a0m4.portsandadapters.domain

sealed class DomainException(override val message: String) : Exception()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@ interface ContactBuilder {
var verifiedStatus: VerifiedStatus
}

fun Contact.patch(block: ContactBuilder.() -> Unit) =
fun Contact.update(block: ContactBuilder.() -> Unit) =
object : ContactBuilder {
override var name = this@patch.name.full
override var email = this@patch.email.value
override var phone = this@patch.phone.value
override var verifiedStatus = this@patch.verifiedStatus
override var name = this@update.name.full
override var email = this@update.email.value
override var phone = this@update.phone.value
override var verifiedStatus = this@update.verifiedStatus
}.apply(block).run {
Contact(name.splitName, Email(email), Phone(phone), verifiedStatus, id)
}
Expand All @@ -45,4 +45,4 @@ val String.splitName: Name
operator fun Contact.get(method: SendMethod) = when (method) {
SendMethod.Email -> email
SendMethod.Phone -> phone
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ class Phone(phone: String) :
value = phone,
name = "phone",
regExp = "^[+]?[(]?[0-9]{3}[)]?[-\\s.]?[0-9]{3}[-\\s.]?[0-9]{4,7}\$"
)
)
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ package io.j0a0m4.portsandadapters.domain.model
enum class SendMethod {
Email, Phone;
companion object
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,4 @@ abstract class ValidatedString(
override fun hashCode() = value.hashCode()

override fun toString() = "ValidatedString(value='$value', name='$name')"
}
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
package io.j0a0m4.portsandadapters.domain.model

typealias VerificationCode = Int
typealias VerificationCode = Int
Loading

0 comments on commit b06e82f

Please sign in to comment.