Skip to content

建立 RESTful API

如何在 Kotlin 中使用 Ktor 建立 RESTful API

程式碼範例: tutorial-server-restful-api

使用的外掛程式:

Routing
Routing 是伺服器應用程式中處理傳入請求的核心外掛程式。
,
Static Content
了解如何提供靜態內容,例如樣式表、指令碼、圖片等。
,
Content Negotiation
ContentNegotiation 外掛程式有兩個主要目的:協商用戶端與伺服器之間的媒體類型,以及將內容序列化/反序列化為特定格式。
, kotlinx.serialization

在本教學中,我們將解釋如何使用 Kotlin 和 Ktor 建置後端服務,其中包含一個會產生 JSON 檔案的 RESTful API 範例。

前一個教學
透過建置工作管理員應用程式,學習使用 Ktor 處理 Kotlin 路由、請求處理和參數的基礎知識。
中,我們向您介紹了驗證、錯誤處理和單元測試的基礎。本教學將透過建立一個用於管理任務的 RESTful 服務來擴充這些主題。

您將學習如何執行以下操作:

  • 建立使用 JSON 序列化的 RESTful 服務。
  • 了解
    Content Negotiation
    ContentNegotiation 外掛程式有兩個主要目的:協商用戶端與伺服器之間的媒體類型,以及將內容序列化/反序列化為特定格式。
    的過程。
  • 在 Ktor 中定義 REST API 的路由。

先決條件

您可以獨立進行本教學, 但我們強烈建議您先完成之前的教學,以學習如何

處理請求並產生回應
透過建置工作管理員應用程式,學習使用 Ktor 處理 Kotlin 路由、請求處理和參數的基礎知識。

我們建議您安裝 IntelliJ IDEA,但您也可以使用其他您偏好的 IDE。

哈囉,RESTful 工作管理員

在本教學中,您將把現有的工作管理員重寫為 RESTful 服務。為此,您將使用多個 Ktor

外掛程式
外掛程式提供常用功能,例如序列化、內容編碼、壓縮等。

雖然您可以手動將其新增到現有專案中,但產生一個新專案,然後逐步加入前一個教學的程式碼會更簡單。您將在過程中重新審視所有程式碼,因此不需要手邊備有前一個專案。

  1. 前往 Ktor Project Generator

  2. Project artifact 欄位中,輸入 com.example.ktor-rest-task-app 作為您的專案構件名稱。 在 Ktor Project Generator 中命名專案構件

  3. 在外掛程式區段中,搜尋並點擊 Add 按鈕來新增以下外掛程式:

    1. Content Negotiation
    2. kotlinx.serialization
    3. Static Content

    在 Ktor Project Generator 中新增外掛程式 新增外掛程式後,您將看到專案設定下方列出的所有外掛程式。 Ktor Project Generator 中的外掛程式清單

  4. 點擊 Download 按鈕來產生並下載您的 Ktor 專案。

  1. 在 IntelliJ IDEA 中開啟您的專案,如之前的 在 IntelliJ IDEA 中開啟、探索並執行您的 Ktor 專案 教學所述。

  2. 導覽至 src/main/kotlin 並建立一個名為 model 的子套件。

  3. model 套件中,建立一個新的 Task.kt 檔案。

  4. 開啟 Task.kt 檔案並新增一個 enum 來表示優先級,以及一個 class 來表示任務:

    kotlin

    在前一個教學中,您使用擴充函式將 Task 轉換為 HTML。而在這裡, Task 類別標註了來自 kotlinx.serialization 程式庫的 Serializable 型別。

  5. 開啟 Routing.kt 檔案,並將現有程式碼替換為下方的實作:

    kotlin

    與之前的教學類似,您為指向 URL /tasks 的 GET 請求建立了一個路由。 這一次,您不再需要手動轉換任務清單,而是直接回傳該清單。

  6. 在 IntelliJ IDEA 中,點擊執行按鈕 (intelliJ IDEA 執行圖示) 來啟動應用程式。

  7. 在瀏覽器中導覽至 http://0.0.0.0:8080/tasks。您應該會看到任務清單的 JSON 版本,如下所示:

  8. 在瀏覽器畫面中顯示的 JSON 資料

    顯然,背後已經為我們完成了很多工作。究竟發生了什麼事?

了解內容協商

透過瀏覽器進行內容協商

當您建立專案時,您包含了

Content Negotiation
ContentNegotiation 外掛程式有兩個主要目的:協商用戶端與伺服器之間的媒體類型,以及將內容序列化/反序列化為特定格式。
外掛程式。此外掛程式會查看用戶端可以呈現的內容類型,並將其與當前服務可以提供的內容類型進行比對。因此,這個術語被稱為 內容協商 (Content Negotiation)

在 HTTP 中,用戶端透過 Accept 標頭發出它可以呈現哪些內容類型的訊號。此標頭的值是一個或多個內容類型。在上述情況下,您可以透過使用瀏覽器內建的開發人員工具來檢查此標頭的值。

考慮以下範例:

請注意 */* 的包含。此標頭發出它接受 HTML、XML 或圖片的訊號,但也接受任何其他內容類型。

Content Negotiation 外掛程式需要找到一種格式來將資料傳回瀏覽器。如果您查看專案中產生的程式碼,您會在 src/main/kotlin 內找到一個名為 Serialization.kt 的檔案,其中包含以下內容:

kotlin

這段程式碼安裝了 ContentNegotiation 外掛程式,同時也配置了 kotlinx.serialization 外掛程式。有了這個,當用戶端發送請求時,伺服器可以回傳序列化為 JSON 的物件。

在瀏覽器請求的情況下,ContentNegotiation 外掛程式知道它只能回傳 JSON,而瀏覽器會嘗試顯示發送給它的任何內容。所以請求成功了。

    在生產環境中,您通常不會直接在瀏覽器中顯示 JSON。相反地,在瀏覽器中執行的 JavaScript 程式碼會發出請求,然後將回傳的資料作為單頁應用程式 (SPA) 的一部分進行顯示。通常,這種應用程式是使用像 ReactAngularVue.js 這樣的架構編寫的。

  1. 為了模擬這種情況,請開啟 src/main/resources/static 內的 index.html 頁面,並將預設內容替換為以下內容:

    html

    此頁面包含一個 HTML 表單和一個空表格。在提交表單時,JavaScript 事件處理常式會向 /tasks 端點發送請求,並將 Accept 標頭設置為 application/json。回傳的資料隨後被反序列化並新增到 HTML 表格中。

  2. 在 IntelliJ IDEA 中,點擊重新執行按鈕 (intelliJ IDEA 重新執行圖示) 以重啟應用程式。

  3. 導覽至 URL http://0.0.0.0:8080/static/index.html。您應該能夠透過點擊 View The Tasks 按鈕來獲取資料:

    瀏覽器視窗顯示按鈕和以 HTML 表格顯示的任務

新增 GET 路由

既然您已經熟悉了內容協商的過程,請繼續將

前一個教學
透過建置工作管理員應用程式,學習使用 Ktor 處理 Kotlin 路由、請求處理和參數的基礎知識。
中的功能轉移到本教學中。

重複使用任務存儲庫

您可以無需任何修改地重複使用任務存儲庫,所以讓我們首先執行此操作。

  1. model 套件中建立一個新的 TaskRepository.kt 檔案。

  2. 開啟 TaskRepository.kt 並新增以下程式碼:

    kotlin

重複使用 GET 請求的路由

既然您已經建立了存儲庫,就可以實作 GET 請求的路由。之前的程式碼可以簡化,因為您不再需要擔心將任務轉換為 HTML:

  1. 導覽至 src/main/kotlin 中的 Routing.kt 檔案。

  2. 使用以下實作更新 Application.configureRouting() 函式內的 /tasks 路由程式碼:

    kotlin

    有了這個,您的伺服器可以回應以下 GET 請求:

    • /tasks 回傳存儲庫中的所有任務。
    • /tasks/byName/{taskName} 回傳按指定的 taskName 過濾的任務。
    • /tasks/byPriority/{priority} 回傳按指定的 priority 過濾的任務。
  3. 在 IntelliJ IDEA 中,點擊重新執行按鈕 (intelliJ IDEA 重新執行圖示) 以重啟應用程式。

測試功能

    您可以在瀏覽器中測試這些路由。例如,導覽至 http://0.0.0.0:8080/tasks/byPriority/Medium 以 JSON 格式查看所有優先級為 Medium 的任務:

    瀏覽器視窗顯示以 JSON 格式呈現的中等優先級任務

    鑑於這些類型的請求通常來自 JavaScript,更精細的測試更為理想。對此,您可以使用專門的工具,例如 Postman

  1. 在 Postman 中,使用 URL 建立一個新的 GET 請求 http://0.0.0.0:8080/tasks/byPriority/Medium

  2. Headers 面板中,將 Accept 標頭的值設置為 application/json

  3. 點擊 Send 發送請求,並在回應檢視器中查看回應。

    Postman 中的 GET 請求,顯示以 JSON 格式呈現的中等優先級任務

    在 IntelliJ IDEA Ultimate 中,您可以在 HTTP 請求檔案中執行相同的步驟。

  1. 在專案根目錄中,建立一個新的 REST Task Manager.http 檔案。

  2. 開啟 REST Task Manager.http 檔案並新增以下 GET 請求:

    http
  3. 要在 IntelliJ IDEA 中發送請求,請點擊其旁邊的裝訂邊圖示 (intelliJ IDEA 裝訂邊圖示)。

  4. 這將在 Services 工具視窗中開啟並執行:

    HTTP 檔案中的 GET 請求,顯示以 JSON 格式呈現的中等優先級任務

NOTE

另一種測試路由的方法是在 Kotlin Notebook 中使用 khttp 程式庫。

新增 POST 請求的路由

在前一個教學中,任務是透過 HTML 表單建立的。然而,由於您現在正在建置 RESTful 服務,您不再需要那樣做。相反地,您將利用 kotlinx.serialization 架構,它將承擔大部分繁重的工作。

  1. 開啟 src/main/kotlin 內的 Routing.kt 檔案。

  2. Application.configureRouting() 函式新增一個新的 POST 路由,如下所示:

    kotlin

    新增以下新匯入:

    kotlin

    當向 /tasks 發送 POST 請求時,會使用 kotlinx.serialization 架構將請求的主體轉換為 Task 物件。如果成功,任務將新增到存儲庫中。如果反序列化過程失敗,伺服器會處理 SerializationException,而如果任務名稱重複,則會處理 IllegalStateException

  3. 重啟應用程式。

  4. 要在 Postman 中測試此功能,請向 URL http://0.0.0.0:8080/tasks 建立一個新的 POST 請求。

  5. Body 面板中,新增以下 JSON 文件以表示新任務:

    json
    Postman 中用於新增任務的 POST 請求
  6. 點擊 Send 發送請求。

  7. 您可以透過向 http://0.0.0.0:8080/tasks 發送 GET 請求來驗證任務是否已新增。

  8. 在 IntelliJ IDEA Ultimate 中,您可以透過將以下內容新增到您的 HTTP 請求檔案來執行相同的步驟:

    http

新增移除支援

您即將完成向服務新增基本操作。這些操作通常被總結為 CRUD(建立 Create、讀取 Read、更新 Update 和刪除 Delete)操作。現在您將實作刪除操作。

  1. TaskRepository.kt 檔案中,在 TaskRepository 物件內新增以下方法以根據名稱移除任務:

    kotlin
  2. 開啟 Routing.kt 檔案,並在 routing() 函式中新增一個端點以處理 DELETE 請求:

    kotlin
  3. 重啟應用程式。

  4. 將以下 DELETE 請求新增到您的 HTTP 請求檔案中:

    http
  5. 要在 IntelliJ IDEA 中發送 DELETE 請求,請點擊其旁邊的裝訂邊圖示 (intelliJ IDEA 裝訂邊圖示)。

  6. 您將在 Services 工具視窗中看到回應:

    HTTP 請求檔案中的 DELETE 請求

使用 Ktor Client 建立單元測試

到目前為止,您一直手動測試應用程式,但正如您已經注意到的,這種方法耗時且無法擴充。相反地,您可以實作

JUnit 測試
了解如何使用特殊測試引擎來測試您的伺服器應用程式。
,使用內建的 client 物件來獲取並反序列化 JSON。

  1. 開啟 src/test/kotlin 內的 ServerTest.kt 檔案。

  2. ServerTest.kt 檔案的內容替換為以下內容:

    kotlin

    請注意,您需要將 ContentNegotiationkotlinx.serialization 外掛程式安裝到 Plugins 中,就像在伺服器端所做的一樣。

  3. 將以下相依性新增到您的 build.gradle.kts 檔案中:

    kotlin

使用 JsonPath 建立單元測試

使用 Ktor client 或類似的程式庫測試服務固然方便,但從品質保證 (QA) 的角度來看,它有一個缺點。伺服器不直接處理 JSON,因此無法確定其對 JSON 結構的假設。

例如,諸如以下的假設:

  • 當實際上使用 object 時,值正被儲存在 array 中。
  • 屬性正以 numbers 儲存,而它們實際上是 strings
  • 成員正按照宣告的順序進行序列化,而實際上並非如此。

如果您的服務旨在供多個用戶端使用,那麼對 JSON 結構有信心至關重要。為了實現這一點,請使用 Ktor Client 從伺服器檢索文本,然後使用 JSONPath 程式庫分析此內容。

  1. 在您的 build.gradle.kts 檔案中,將 JSONPath 程式庫新增到 dependencies 區塊:

    kotlin
  2. 導覽至 src/test/kotlin 資料夾並建立一個新的 ApplicationJsonPathTest.kt 檔案。

  3. 開啟 ApplicationJsonPathTest.kt 檔案並向其中新增以下內容:

    kotlin

    JsonPath 查詢的工作原理如下:

    • $[*].name 表示「將文件視為陣列,並回傳每個項目的 name 屬性值」。
    • $[?(@.priority == '$priority')].name 表示「回傳陣列中優先級等於提供值的所有項目的 name 屬性值」。

    您可以使用類似這樣的查詢來確認您對回傳 JSON 的理解。當您進行程式碼重構和服務重新部署時,序列化中的任何修改都會被識別出來,即使它們沒有破壞當前架構的反序列化。這使您能夠充滿信心地重新發布公開可用的 API。

後續步驟

恭喜!您現在已經完成了為工作管理員應用程式建立 RESTful API 服務,並學習了使用 Ktor Client 和 JsonPath 進行單元測試的細節。

繼續閱讀

下一個教學
了解如何使用 Ktor 和 Thymeleaf 範本在 Kotlin 中建置網站。
,學習如何重複使用您的 API 服務來建置 Web 應用程式。