如何使用 Ktor 在 Kotlin 中建立 RESTful API
程式碼範例: tutorial-server-restful-api
使用的外掛程式:
在本教學課程中,我們將說明如何使用 Kotlin 和 Ktor 建立後端服務,其中包含一個生成 JSON 檔案的 RESTful API 範例。
在
您將學習如何執行以下操作:
- 建立使用 JSON 序列化的 RESTful 服務。
- 了解內容協商 (Content Negotiation)的過程。ContentNegotiation 外掛程式主要有兩個用途:協商用戶端與伺服器之間的媒體類型,以及以特定格式序列化/反序列化內容。
- 在 Ktor 中定義 REST API 的路由。
先決條件
您可以獨立執行本教學課程, 但是,我們強烈建議您完成上一個教學課程,以了解如何
我們建議您安裝IntelliJ IDEA,但您可以使用您選擇的其他 IDE。
您好,RESTful 任務管理器
在本教學課程中,您將把現有的任務管理器重寫為 RESTful 服務。為此,您將使用多個 Ktor
雖然您可以手動將其新增到您現有的專案,但更簡單的方法是生成一個新專案,然後逐步新增上一個教學課程的程式碼。您將在執行過程中重複所有程式碼,因此您不需要手邊有上一個專案。
導航至 Ktor Project Generator 。
在 專案 artifact 欄位中,輸入 com.example.ktor-rest-task-app 作為您的專案 artifact 名稱。
在外掛程式區段中,透過點擊 新增 按鈕,搜尋並新增以下外掛程式:
- Routing
- Content Negotiation
- Kotlinx.serialization
- Static Content
新增外掛程式後,您將在專案設定下方看到所有四個外掛程式。
點擊 下載 按鈕以產生並下載您的 Ktor 專案。
在 IntelliJ IDEA 中開啟您的專案,如在 IntelliJ IDEA 中開啟、探索並執行您的 Ktor 專案教學課程中先前所述。
導航至 src/main/kotlin/com/example 並建立一個名為 model 的子套件。
在 model 套件中,建立一個新的 Task.kt 檔案。
開啟 Task.kt 檔案並新增一個
enum
來表示優先順序,以及一個class
來表示任務:kotlin在上一個教學課程中,您使用擴充功能將
Task
轉換為 HTML。在此情況下,Task
類別使用來自kotlinx.serialization
程式庫的Serializable
類型進行註解。開啟 Routing.kt 檔案並將現有程式碼替換為以下實作:
kotlin與上一個教學課程類似,您為對 URL
/tasks
的 GET 請求建立了路由。 這次,您不再手動轉換任務列表,而是直接回傳列表。在 IntelliJ IDEA 中,點擊執行按鈕 (
) 以啟動應用程式。
在瀏覽器中導航至http://0.0.0.0:8080/tasks。您應該會看到任務列表的 JSON 版本,如下所示:

顯然,我們代表執行了大量工作。究竟發生了什麼事?
了解內容協商
透過瀏覽器進行內容協商
當您建立專案時,您包含了
在 HTTP 中,用戶端透過 Accept
標頭發出它可以呈現的內容類型訊號。此標頭的值是一個或多個內容類型。在上面的情況下,您可以使用瀏覽器內建的開發工具檢查此標頭的值。
考慮以下範例:
請注意 /
的包含。此標頭表示它接受 HTML、XML 或影像——但它也將接受任何其他內容 類型。
Content Negotiation 外掛程式需要找到一種格式將資料傳回瀏覽器。如果您查看專案中生成的程式碼,您會發現 src/main/kotlin/com/example 中包含一個名為 Serialization.kt 的檔案,其中包含以下內容:
此程式碼安裝了 ContentNegotiation
外掛程式,同時也配置了 kotlinx.serialization
外掛程式。有了這個,當用戶端發送請求時,伺服器可以回傳序列化為 JSON 的物件。
在來自瀏覽器的請求情況下,ContentNegotiation
外掛程式知道它只能回傳 JSON,並且瀏覽器將嘗試顯示它收到的任何內容。因此請求成功。
為了模擬這一點,開啟 src/main/resources/static 中的 index.html 頁面,並將預設內容替換為以下內容:
html此頁面包含一個 HTML 表單和一個空表。提交表單後,一個 JavaScript 事件處理常式 會向
/tasks
端點發送請求,並將Accept
標頭設定為application/json
。返回的資料隨後會被反序列化並新增到 HTML 表格中。在 IntelliJ IDEA 中,點擊重新執行按鈕 (
) 以重新啟動應用程式。
導航至 URL http://0.0.0.0:8080/static/index.html。 您應該能夠透過點擊 檢視任務 按鈕來擷取資料:
在生產環境中,您不會希望直接在瀏覽器中顯示 JSON。相反,瀏覽器中會執行 JavaScript 程式碼,該程式碼將發出請求,然後將返回的資料作為單頁應用程式 (SPA) 的一部分顯示。通常,這種應用程式會使用 React、 Angular 或 Vue.js 等框架來編寫。
新增 GET 路由
既然您已熟悉內容協商的過程,請繼續將
重複使用任務儲存庫
您可以重複使用任務儲存庫,無需任何修改,所以讓我們首先這樣做。
在 model 套件中,建立一個新的 TaskRepository.kt 檔案。
開啟 TaskRepository.kt 並新增以下程式碼:
kotlin
重複使用 GET 請求的路由
現在您已經建立了儲存庫,您可以實作 GET 請求的路由。由於您不再需要擔心將任務轉換為 HTML,因此之前的 程式碼可以簡化:
導航至 src/main/kotlin/com/example 中的 Routing.kt 檔案。
使用以下實作更新
Application.configureRouting()
函式中/tasks
路由的程式碼:kotlin有了這個,您的伺服器可以回應以下 GET 請求:
/tasks
返回儲存庫中的所有任務。/tasks/byName/{taskName}
返回按指定taskName
過濾的任務。/tasks/byPriority/{priority}
返回按指定priority
過濾的任務。
在 IntelliJ IDEA 中,點擊重新執行按鈕 (
) 以重新啟動應用程式。
測試功能
您可以在瀏覽器中測試這些路由。例如,導航至 http://0.0.0.0:8080/tasks/byPriority/Medium 以 JSON 格式顯示所有 Medium
優先順序的任務:

鑑於這類請求通常來自 JavaScript,因此更 細粒度的測試是更受歡迎的。為此,您可以使用專用工具,例如 Postman。
在 Postman 中,建立一個新的 GET 請求,URL 為
http://0.0.0.0:8080/tasks/byPriority/Medium
。在 標頭 窗格中,將 Accept 標頭的值設定為
application/json
。點擊 傳送 以傳送請求並在回應檢視器中查看回應。
在專案根目錄中,建立一個新的 REST Task Manager.http 檔案。
開啟 REST Task Manager.http 檔案並新增以下 GET 請求:
http要在 IntelliJ IDE 中傳送請求,請點擊其旁邊的側邊欄圖示 (
)。
這將在 Services 工具視窗中開啟並執行:
在 IntelliJ IDEA Ultimate 中,您可以在 HTTP 請求檔案中執行相同的步驟。
NOTE
測試路由的另一種方法是使用 Kotlin Notebook 中的 khttp 程式庫。新增 POST 請求的路由
在之前的教學課程中,任務是透過 HTML 表單建立的。然而,由於您現在正在建立 RESTful 服務,您不再需要這樣做。相反,您將利用 kotlinx.serialization
框架,它將完成大部分繁重的工作。
開啟 src/main/kotlin/com/example 中的 Routing.kt 檔案。
新增一個新的 POST 路由到
Application.configureRouting()
函式,如下所示:kotlin新增以下新引入:
kotlin當 POST 請求傳送到
/tasks
時,kotlinx.serialization
框架 用於將請求主體轉換為Task
物件。如果成功,任務將被新增到儲存庫。如果反序列化過程失敗,伺服器將需要 處理SerializationException
,而如果任務重複,則需要處理IllegalStateException
。重新啟動應用程式。
為了在 Postman 中測試此功能,建立一個新的 POST 請求到 URL
http://0.0.0.0:8080/tasks
。在 主體 窗格中,新增以下 JSON 文件以表示一個新任務:
json點擊 傳送 以傳送請求。
您可以透過向 http://0.0.0.0:8080/tasks 傳送 GET 請求來驗證任務是否已新增。
在 IntelliJ IDEA Ultimate 中,您可以透過將以下內容新增到您的 HTTP 請求檔案來執行相同的步驟:
http
新增刪除支援
您幾乎已經完成了為您的服務新增基本操作。這些操作通常被總結為 CRUD 操作——即建立 (Create)、讀取 (Read)、更新 (Update) 和刪除 (Delete) 的縮寫。現在您將實作刪除操作。
在 TaskRepository.kt 檔案中,在
TaskRepository
物件中新增以下方法,以根據任務名稱移除任務:kotlin開啟 Routing.kt 檔案並在
routing()
函式中新增一個端點來處理 DELETE 請求:kotlin重新啟動應用程式。
將以下 DELETE 請求新增到您的 HTTP 請求檔案中:
http要在 IntelliJ IDE 中傳送 DELETE 請求,請點擊其旁邊的側邊欄圖示 (
)。
您將在 Services 工具視窗中看到回應:
使用 Ktor 用戶端建立單元測試
到目前為止,您已經手動測試了您的應用程式,但是,正如您已經注意到的,這種方法耗時且無法擴展。相反,您可以實作
client
物件來擷取和反序列化 JSON。 開啟 src/test/kotlin/com/example 中的 ApplicationTest.kt 檔案。
將 ApplicationTest.kt 檔案的內容替換為以下內容:
kotlin請注意,您需要在 外掛程式中安裝
ContentNegotiation
和kotlinx.serialization
外掛程式,就像您在 伺服器端所做的一樣。將以下依賴項新增到您位於 gradle/libs.versions.toml 的版本目錄中:
yaml將新依賴項新增到您的 build.gradle.kts 檔案中:
kotlin
使用 JsonPath 建立單元測試
使用 Ktor 用戶端或類似的程式庫測試您的服務很方便,但從品質保證 (QA) 的角度來看,它有一個缺點。伺服器不直接處理 JSON,因此無法確定其對 JSON 結構的假設是否正確。
例如,假設以下情況:
- 值以
array
形式儲存,而實際上使用的是object
。 - 屬性以
numbers
形式儲存,而實際上是strings
。 - 成員在宣告時按照順序序列化,但實際並非如此。
如果您的服務 intended for use by multiple clients, it's crucial to have confidence in the JSON structure. To achieve this, use the Ktor Client to retrieve text from the server and then analyze this content using the JSONPath 程式庫。
在您的 build.gradle.kts 檔案中,將 JSONPath 程式庫新增到
dependencies
區塊:kotlin導航至 src/test/kotlin/com/example 資料夾並建立一個新的 ApplicationJsonPathTest.kt 檔案。
開啟 ApplicationJsonPathTest.kt 檔案並將以下內容新增到其中:
kotlinJsonPath 查詢的工作方式如下:
$[*].name
表示「將文件視為陣列,並返回每個條目的name
屬性值」。$[?(@.priority == '$priority')].name
表示「返回陣列中所有priority
等於提供值的條目的name
屬性值」。
您可以使用這些查詢來確認您對返回 JSON 的理解。當您進行程式碼重構和服務重新部署時,序列化中的任何修改都將被識別,即使它們不會破壞目前框架的反序列化。這使您可以自信地重新發布公開可用的 API。
下一步
恭喜!您現在已經完成了為您的任務管理器應用程式建立 RESTful API 服務,並學習了使用 Ktor Client 和 JsonPath 進行單元測試的細節。
繼續閱讀