Compare commits
2 Commits
ee26a56627
...
f98e1227e8
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f98e1227e8 | ||
|
|
ed0acfc5dc |
11
bruno-rest/GiteaActionsWorkshop/Get all products.bru
Normal file
11
bruno-rest/GiteaActionsWorkshop/Get all products.bru
Normal file
@@ -0,0 +1,11 @@
|
||||
meta {
|
||||
name: Get all products
|
||||
type: http
|
||||
seq: 2
|
||||
}
|
||||
|
||||
get {
|
||||
url: {{url}}/api/products
|
||||
body: none
|
||||
auth: none
|
||||
}
|
||||
9
bruno-rest/GiteaActionsWorkshop/bruno.json
Normal file
9
bruno-rest/GiteaActionsWorkshop/bruno.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"version": "1",
|
||||
"name": "GiteaActionsWorkshop",
|
||||
"type": "collection",
|
||||
"ignore": [
|
||||
"node_modules",
|
||||
".git"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
vars {
|
||||
url: http://localhost:8080
|
||||
}
|
||||
@@ -1,13 +1,6 @@
|
||||
object Versions {
|
||||
const val springBoot = "3.4.3"
|
||||
const val springDependencyManagement = "1.1.7"
|
||||
const val kotlinJvm = "1.9.25"
|
||||
const val kotlinPluginSpring = "1.9.25"
|
||||
}
|
||||
|
||||
plugins {
|
||||
kotlin("jvm") version "1.9.25"
|
||||
kotlin("plugin.spring") version "1.9.25"
|
||||
kotlin("jvm") version "2.1.20"
|
||||
kotlin("plugin.spring") version "2.1.20"
|
||||
id("io.spring.dependency-management") version "1.1.7"
|
||||
}
|
||||
|
||||
@@ -33,13 +26,14 @@ subprojects {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(platform("org.springframework.boot:spring-boot-dependencies:${Versions.springBoot}"))
|
||||
implementation(platform("org.springframework.boot:spring-boot-dependencies:3.4.4"))
|
||||
implementation("com.michael-bull.kotlin-result:kotlin-result:2.0.1")
|
||||
}
|
||||
}
|
||||
|
||||
dependencyManagement {
|
||||
imports {
|
||||
mavenBom("org.springframework.boot:spring-boot-dependencies:${Versions.springBoot}")
|
||||
mavenBom("org.springframework.boot:spring-boot-dependencies:3.4.4")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,4 +7,6 @@ dependencies {
|
||||
implementation(kotlin("stdlib"))
|
||||
implementation(project(":demo-domain"))
|
||||
implementation("org.springframework:spring-context")
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4")
|
||||
implementation("com.michael-bull.kotlin-result:kotlin-result-coroutines:2.0.1")
|
||||
}
|
||||
@@ -1,12 +1,45 @@
|
||||
package com.example.demo.application.product
|
||||
|
||||
import com.example.demo.domain.core.error.FunctionalError
|
||||
import com.example.demo.domain.product.inputport.ProductInputPort
|
||||
import com.example.demo.domain.product.model.Product
|
||||
import com.example.demo.domain.product.port.ProductPort
|
||||
import com.example.demo.domain.product.model.ProductType
|
||||
import com.example.demo.domain.product.outputport.ProductOutputPort
|
||||
import com.github.michaelbull.result.*
|
||||
import com.github.michaelbull.result.coroutines.coroutineBinding
|
||||
import org.springframework.stereotype.Service
|
||||
import java.util.*
|
||||
|
||||
@Service
|
||||
class ProductUseCases(
|
||||
private val productPort: ProductPort
|
||||
) {
|
||||
fun getAll(): List<Product> = productPort.getAll()
|
||||
private val productOutputPort: ProductOutputPort
|
||||
) : ProductInputPort {
|
||||
override suspend fun getAll(): Result<List<Product>, FunctionalError> = productOutputPort.getAll()
|
||||
.mapError { FunctionalError(it.message) }
|
||||
|
||||
// override suspend fun create(name: String, type: ProductType): Result<Product, FunctionalError> {
|
||||
// if (name.isBlank()) {
|
||||
// return Err(FunctionalError("Product name should be set."))
|
||||
// }
|
||||
//
|
||||
// val newProduct = Product(id = UUID.randomUUID(), name, type)
|
||||
// return productOutputPort.save(newProduct)
|
||||
// .mapError { FunctionalError(it.message) }
|
||||
// .map { newProduct }
|
||||
// }
|
||||
|
||||
override suspend fun create(name: String, type: ProductType): Result<Product, FunctionalError> = coroutineBinding {
|
||||
validateName(name).bind()
|
||||
|
||||
val newProduct = Product(id = UUID.randomUUID(), name, type)
|
||||
productOutputPort.save(newProduct)
|
||||
.mapError { FunctionalError(it.message) }
|
||||
.map { newProduct }
|
||||
.bind()
|
||||
}
|
||||
|
||||
private fun validateName(name: String): Result<Unit, FunctionalError> = when {
|
||||
name.isBlank() -> Err(FunctionalError("Product name should be set."))
|
||||
else -> Ok(Unit)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
package com.example.demo.domain.core.error
|
||||
|
||||
open class DomainError(val message: String)
|
||||
@@ -0,0 +1,3 @@
|
||||
package com.example.demo.domain.core.error
|
||||
|
||||
class FunctionalError(message: String) : DomainError(message)
|
||||
@@ -0,0 +1,3 @@
|
||||
package com.example.demo.domain.core.error
|
||||
|
||||
class TechnicalError(message: String) : DomainError(message)
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.example.demo.domain.product.inputport
|
||||
|
||||
import com.example.demo.domain.core.error.FunctionalError
|
||||
import com.example.demo.domain.product.model.Product
|
||||
import com.example.demo.domain.product.model.ProductType
|
||||
import com.github.michaelbull.result.Result
|
||||
|
||||
interface ProductInputPort {
|
||||
suspend fun create(name: String, type: ProductType): Result<Product, FunctionalError>
|
||||
suspend fun getAll(): Result<List<Product>, FunctionalError>
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.example.demo.domain.product.outputport
|
||||
|
||||
import com.example.demo.domain.core.error.TechnicalError
|
||||
import com.example.demo.domain.product.model.Product
|
||||
import com.github.michaelbull.result.Result
|
||||
import java.util.UUID
|
||||
|
||||
interface ProductOutputPort {
|
||||
fun getById(id: UUID): Product?
|
||||
|
||||
suspend fun getAll(): Result<List<Product>, TechnicalError>
|
||||
|
||||
fun save(product: Product): Result<Unit, TechnicalError>
|
||||
|
||||
fun deleteById(id: UUID)
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
package com.example.demo.domain.product.port
|
||||
|
||||
import com.example.demo.domain.product.model.Product
|
||||
import java.util.UUID
|
||||
|
||||
interface ProductPort {
|
||||
fun getById(id: UUID): Product?
|
||||
|
||||
fun getAll(): List<Product>
|
||||
|
||||
fun save(product: Product)
|
||||
|
||||
fun deleteById(id: UUID)
|
||||
}
|
||||
@@ -9,4 +9,7 @@ dependencies {
|
||||
implementation(project(":demo-domain"))
|
||||
implementation("org.springframework:spring-context")
|
||||
implementation("org.springframework:spring-web")
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2")
|
||||
implementation("com.michael-bull.kotlin-result:kotlin-result-coroutines:2.0.1")
|
||||
implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.18.3")
|
||||
}
|
||||
@@ -1,16 +1,28 @@
|
||||
package com.example.demo.exposition.product
|
||||
|
||||
import com.example.demo.application.product.ProductUseCases
|
||||
import com.example.demo.domain.core.error.FunctionalError
|
||||
import com.example.demo.domain.product.inputport.ProductInputPort
|
||||
import com.example.demo.domain.product.model.Product
|
||||
import com.example.demo.exposition.product.model.ProductCreationRequest
|
||||
import com.example.demo.exposition.product.model.ProductDto
|
||||
import com.github.michaelbull.result.Result
|
||||
import com.github.michaelbull.result.map
|
||||
import org.springframework.web.bind.annotation.GetMapping
|
||||
import org.springframework.web.bind.annotation.PostMapping
|
||||
import org.springframework.web.bind.annotation.RequestBody
|
||||
import org.springframework.web.bind.annotation.RequestMapping
|
||||
import org.springframework.web.bind.annotation.RestController
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/products")
|
||||
class ProductController(
|
||||
private val productUseCases: ProductUseCases
|
||||
private val productInputPort: ProductInputPort
|
||||
) {
|
||||
@GetMapping
|
||||
fun getAll(): List<ProductDto> = productUseCases.getAll().map(::ProductDto)
|
||||
suspend fun getAll(): Result<List<ProductDto>, FunctionalError> = productInputPort.getAll()
|
||||
.map { products -> products.map(::ProductDto) }
|
||||
|
||||
@PostMapping
|
||||
suspend fun create(@RequestBody request: ProductCreationRequest): Result<Product, FunctionalError> =
|
||||
productInputPort.create(request.name, request.type)
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.example.demo.exposition.product.core.advice
|
||||
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice
|
||||
|
||||
@RestControllerAdvice
|
||||
class ResultControllerAdvice {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.example.demo.exposition.product.model
|
||||
|
||||
import com.example.demo.domain.product.model.ProductType
|
||||
|
||||
data class ProductCreationRequest(
|
||||
val name: String,
|
||||
val type: ProductType
|
||||
)
|
||||
@@ -8,4 +8,6 @@ dependencies {
|
||||
implementation(project(":demo-application"))
|
||||
implementation(project(":demo-domain"))
|
||||
implementation("org.springframework:spring-context")
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2")
|
||||
implementation("com.michael-bull.kotlin-result:kotlin-result-coroutines:2.0.1")
|
||||
}
|
||||
@@ -1,14 +1,17 @@
|
||||
package com.example.demo.infrastructure.product
|
||||
|
||||
import com.example.demo.domain.core.error.TechnicalError
|
||||
import com.example.demo.domain.product.model.Product
|
||||
import com.example.demo.domain.product.model.ProductType.LIQUID
|
||||
import com.example.demo.domain.product.model.ProductType.SOLID
|
||||
import com.example.demo.domain.product.port.ProductPort
|
||||
import com.example.demo.domain.product.outputport.ProductOutputPort
|
||||
import com.github.michaelbull.result.Ok
|
||||
import com.github.michaelbull.result.Result
|
||||
import org.springframework.stereotype.Component
|
||||
import java.util.*
|
||||
|
||||
@Component
|
||||
class ProductInMemoryAdapter : ProductPort {
|
||||
class ProductInMemoryAdapter : ProductOutputPort {
|
||||
private val products = mutableListOf(
|
||||
Product(
|
||||
id = UUID.randomUUID(),
|
||||
@@ -24,15 +27,11 @@ class ProductInMemoryAdapter : ProductPort {
|
||||
|
||||
override fun getById(id: UUID): Product? = products.find { product -> product.id == id }
|
||||
|
||||
override fun getAll(): List<Product> = products
|
||||
override suspend fun getAll(): Result<List<Product>, TechnicalError> = Ok(products)
|
||||
|
||||
override fun save(product: Product) {
|
||||
if (getById(product.id) == null) {
|
||||
products.add(product)
|
||||
} else {
|
||||
deleteById(product.id)
|
||||
save(product)
|
||||
}
|
||||
override fun save(product: Product): Result<Unit, TechnicalError> {
|
||||
products += product
|
||||
return Ok(Unit)
|
||||
}
|
||||
|
||||
override fun deleteById(id: UUID) {
|
||||
|
||||
@@ -6,13 +6,17 @@ plugins {
|
||||
|
||||
dependencies {
|
||||
implementation(kotlin("stdlib"))
|
||||
implementation(kotlin("reflect"))
|
||||
implementation(project(":demo-domain"))
|
||||
implementation(project(":demo-application"))
|
||||
implementation(project(":demo-infrastructure"))
|
||||
implementation(project(":demo-exposition"))
|
||||
implementation("org.springframework.boot:spring-boot-starter-web")
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core")
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-reactor")
|
||||
implementation("org.springframework.boot:spring-boot-starter-webflux")
|
||||
}
|
||||
|
||||
springBoot {
|
||||
mainClass = "com.example.demo.launcher.ApplicationLauncherKt"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user