iT邦幫忙

2023 iThome 鐵人賽

DAY 5
0
Kotlin

Kotlin魔法:Spring Boot 3的fp奇幻冒險系列 第 5

[小草原] Spring Boot 3的RESTful API

  • 分享至 

  • xImage
  •  

前言

今天我們要利用Domain modeling來建構domain type,接著來實作Spring Boot的RESTful API ,就是新增,修改,刪除,查詢囉XD

GET @GetMapping

我們可以使用@GetMapping來表示收到GET的Request,

    @GetMapping("/api/v1/customers")
    fun getAllCustomers(): List<Customer> {
        val customer = Customer(Name("JW"), Phone("123"), Age(25))
        val customer2 = Customer(Name("JW"), Email("myEmail"), Age(25))
        return listOf(customer, customer2)
    }

這邊我們回傳兩個已經寫死的Customer。在瀏覽器打上local:8080/api/v1/customers 就可以看到結果囉

[{"contactInfo":{"value":"123"},"age-KEqCl0g":25,"name-c4577c4":"JW"},{"contactInfo":{"value":"myEmail"},"age-KEqCl0g":25,"name-c4577c4":"JW"}]

發現name的後面怎麼有奇怪的字呢? 明明我們沒這樣寫呀? 這是因為我們沒有做Serialize,因此我們加上kotlinx.serialization來做Serialize,就可以看到正常的結果囉。

安裝教學
https://github.com/Kotlin/kotlinx.serialization/tree/master

package model

import kotlinx.serialization.Serializable

@JvmInline
@Serializable
value class Name(val value: String)

@Serializable
sealed interface ContactInfo

@JvmInline
@Serializable
value class Email(val value: String) : ContactInfo

@JvmInline
@Serializable
value class Phone(val value: String) : ContactInfo

@JvmInline
@Serializable
value class Age(val value: Int)

@Serializable
data class Customer(
    val name: Name,
    val contactInfo: ContactInfo,
    val age: Age,
)

回傳的結果就會是正常的囉XD 不會出現剛剛的奇怪文字

[{"name":"JW","contactInfo":"123","age":25},{"name":"JW","contactInfo":"myEmail","age":25}]

POST @PostMapping

接著來做Post function!跟GetMapping一樣,把Get換成Post

    private val customerList = mutableListOf<Customer>()
    
    @Serializable
    data class CustomerVO(
        val name: String,
        val contactInfo: String,
        val age: Int,
    )
    
    @PostMapping("/api/v1/customers")
    fun createCustomer(@RequestBody newCustomer: String) {
        Json.decodeFromString<CustomerVO>(newCustomer).let {
            customerVOToCustomer(it)
        }.let { customerList.add(it) }
    }

這邊我們使用一個list來暫時當DB,儲存我們打進來的結果。並且使用CustomerVO這個物件,先將外來的Request轉成這個type,之後再轉成我們的Domain type。

隔離的作用

這樣做可以將我們的Request隔離,讓下一個function可以吃到Domain type,不會因為外部的影響,導致後續的function出錯,有點像是驗證的概念XD

PUT @PutMapping

    @PutMapping("/api/v1/customers")
    fun updateCustomer(@RequestBody newCustomer: String) {
        Json.decodeFromString<CustomerVO>(newCustomer).let {
            customerVOToCustomer(it)
        }.let { validatedCustomer ->
            customerList.indexOfFirst { it.name == validatedCustomer.name }.takeIf { it != -1 }?.let {
                customerList.set(it, validatedCustomer)
            }
        }
    }

這裡我們先搜尋list裡面是否擁有跟輸入一樣名字的元素,接著直接改變它。

Delete @DeleteMapping

    @DeleteMapping("/api/v1/customers")
    fun DeleteCustomer(@RequestBody newCustomer: String) {
        Json.decodeFromString<CustomerVO>(newCustomer).let {
            customerVOToCustomer(it)
        }.let { validatedCustomer ->
            customerList.indexOfFirst { it == validatedCustomer }.takeIf { it != -1 }?.let {
                customerList.removeAt(it)
            }
        }
    }

總結

我們今天學會了如何簡單寫出CRUD的api,但還有非常大的進步空間,比如說錯誤處理,連接真正的DB等。都是我們可以更進一步去完善的。期待明天的到來~


上一篇
[小草原] Kotlin的劍 data class、Value class
下一篇
[小草原] Spring Boot 3 的錯誤處理
系列文
Kotlin魔法:Spring Boot 3的fp奇幻冒險30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言