iT邦幫忙

2022 iThome 鐵人賽

DAY 6
0

https://ithelp.ithome.com.tw/upload/images/20220912/201357013mGOqE7Nfz.png

RESTful Endpoint 變成 100 分吧

在第 4 天的文章,有提到了 Quarkus 提供了 Dev UI. 其中自帶的 sample hello service 是 66 分。我們可以直上 Kotlin coroutines 的魔力。讓 blocking function 直接變成 Non-blocking function。 只要加上那個 suspend keyword

    suspend fun hello() = "Hello from RESTEasy Reactive"  // Made service non-blocking

這裡加上 suspend 就可以把 request 轉到 Vert.x 的 worker thread

關於 Endpoint 的評分點

Writer

Writer 有得分表示在 build time 時有明確決定要用哪個 Serializer。這裡我們可看到是 io.quarkus.kotlin.serialization.KotlinSerializationMessageBodyWriter。用的是 Kotlinx Serialization。這是因為我們一開始選用了 quarkus-resteasy-reactive-kotlin-serialization。
RESYEasy 在 serialization 這塊還有 Jackson, JsonB 的實現,在 project 中要擇一引入。這次我們要貫徹用 Kotlin 的意志,選用當然是 kotlinx 的 Serialization.

Resource

表示我們用一個 instance 服務所有的 request。這塊也是 Day8 or Day9 會討論 Quarkus Reactive

RESTEasy Reactive

RESTEasy Reactive 為 JAX-RS 的新的實現。背後利用了 Vert.x 這個 reactive 的 framework 並與 Quarkus 強整合,所以也是會把很多工作在 build time 作掉。

不改變本來 JAX-RS 的使用習慣

JAX-RS 是 RESTful 公版標準,所以在這裡的實作上跟 Spring Boot 使用上幾乎是無痛轉移 @GET, @POST, @DELETE ....,而且會有很好的 performance (Non-Blocking)。

Film RESTful Service

接下來用 Quarkus 實作一個簡易 Film 的 RESTful Service. 我們會作一個電影資訊查詢的 Service。

1. 建立 filmSerivceQK Project

在 project folder 輸入

quarkus create app tw.brandy.ironman:filmServiceQK --extension=kotlin,quarkus-resteasy-reactive-kotlin-serialization

2. 使用 IntelliJ 開啟專案

用 mobaxterm 打開 IntelliJ, 並且打開剛剛建立的專案

3. pom.xml 增加 Kotlin Serialization Support

雖然 Quarkus 對於 Kotlin 的支援不錯,有些眉角還是要注意一下。Kotlin Serialization 是在build 會作事。所以要加上支援。

kotlinx-datetime-jvm

找到 quarkus-resteasy-reactive-kotlin-serialization

    <dependency>
      <groupId>io.quarkus</groupId>
      <artifactId>quarkus-resteasy-reactive-kotlin-serialization</artifactId>
    </dependency>
    <!-- 在其後面加上 -->
    <dependency>
      <groupId>org.jetbrains.kotlinx</groupId>
      <artifactId>kotlinx-datetime-jvm</artifactId>
      <version>0.4.0</version>
    </dependency>

kotlin-serialization compiler

找到 kotlin-maven-allopen 在其後加上

          <dependency>
            <groupId>org.jetbrains.kotlin</groupId>
            <artifactId>kotlin-maven-serialization</artifactId>
            <version>${kotlin.version}</version>
          </dependency>

compilerPulgins 修改

          <compilerPlugins>
            <plugin>all-open</plugin>
            <plugin>kotlinx-serialization</plugin>
          </compilerPlugins>

4. 建立 Film Data Class

這裡要開始新增一些 class。總共有三個kt如圖

https://ithelp.ithome.com.tw/upload/images/20220912/20135701WB7fBFyxbp.png

@Serializable
data class Film(
    val title: String,
    val episodeID: Int,
    val director: String,
    @Serializable(LocalDateComponentSerializer::class)
    val releaseDate: LocalDate
)

5. 建立 FilmService

這裡是拿 Quarkus Java Sample 來改。可以看到兩相比較簡單很多。 Film 的新增也演示的 Kotlin 的三種作法。


@ApplicationScoped // Quarkus 裡 bean 的宣告方法
class FilmService {

    private val films: MutableList<Film> = ArrayList<Film>()

    init {
        films.apply {
            add(
                Film(
                    episodeID = 4,
                    title = "A New Hope",
                    director = "George Lucas",
                    releaseDate = LocalDate.parse("1977-05-25")
                )
            )

            Film(
                episodeID = 5,
                title = "The Empire Strikes Back",
                director = "George Lucas",
                releaseDate = LocalDate.parse("1980-05-21")
            ).let { add(it) }

            Film(
                episodeID = 5,
                title = "Return Of The Jedi",
                director = "George Lucas",
                releaseDate = LocalDate.parse("1983-05-25")
            ).let(::add)
        }
    }

    fun getAllFilms() = films.toList()

    fun getFilm(id: Int) = films.first { id == it.episodeID }
}

6. 建立 FilmResource (REST Endpoint)


@Path("/films")
class FilmResource(val filmService: FilmService) {

    @GET
    @Produces(MediaType.APPLICATION_JSON)
    @Consumes(MediaType.APPLICATION_JSON)
    suspend fun getAllFilms() = filmService.getAllFilms()

    @GET
    @Path("/{id}")
    @Produces(MediaType.APPLICATION_JSON)
    @Consumes(MediaType.APPLICATION_JSON)
    suspend fun getFilmById(id: Int) = filmService.getFilm(id)
}

7. 啟動並測試

在 IntelliJ 中我們可以在右上加入 quarkus:dev 的 maven 啟動。

https://ithelp.ithome.com.tw/upload/images/20220912/20135701ARzYUxaaIa.png

加入後,以後就可以按那個綠色的 play 啟動。打開 http://localhost:8080/q/dev/io.quarkus.quarkus-resteasy-reactive/scores 可以看到我們三個 Endpoint 都是 100 分

https://ithelp.ithome.com.tw/upload/images/20220912/20135701sRzOvJAMVq.png

測試 film Endpoints

http://localhost:8080/films
http://localhost:8080/films/5

可以看到RESTful Service 已順利運作

https://ithelp.ithome.com.tw/upload/images/20220912/20135701TBJup563Wk.png


目前我們作到的是 Endpoint 端的 non-blocking。然而不只是 Endpoint, 在後端接 DB 或是其他 Service 也是要這種 non-blocking 的機制來減少 Resource 的使用。所以明天我們來接上 Mongodb 吧 (順利的話)


上一篇
安裝 local container - Podman 與 IntelliJ in WSL 環境 - Day5
下一篇
增加 Panache Kotlin, Quarkus 幫你起 MongoDB - Day7
系列文
Quarkus, Kotlin, Reactive 雲原生服務開發32
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言