3

我在理解使用 Ktor 的 DSL 进行请求路由的正确方法时遇到了一些麻烦。问题是,当我测试我的 API 并尝试GET /nomenclature/articles/categories返回所有文章类别的列表时,我得到的是当参数无效时我为路由Invalid article specified返回的消息。/nomenclature/articles/{articleId}articleId

这是我的代码:

route("/nomenclature") {
    method(HttpMethod.Get) {
        handle { call.respondText("The resource you accessed is not a valid REST resource, but a parent node. Children nodes include articles, categories, subcategories and so on.") }
    }
    route("articles") {
        route("categories") {
            get("{categoryId?}") {
                val categoryIdParam = call.parameters["categoryId"]
                if (categoryIdParam != null) {
                    val categoryId = categoryIdParam.toIntOrNull()
                    if (categoryId != null) {
                        val category = articlesDAO.findCategoryById(categoryId)
                        if (category != null) call.respond(category)
                        else call.respondText("Category not found", status = HttpStatusCode.NotFound)
                    } else call.respondText("Invalid category ID specified", status = HttpStatusCode.BadRequest)
                } else {
                    val categories = articlesDAO.getCategories()
                    if (categories != null) call.respond(categories)
                    else call.respondText("No categories found", status = HttpStatusCode.NotFound)
                }
            }
        }
        route("subcategories") {
            get("{subcategoryId?}") {
                val subcategoryIdParam = call.parameters["subcategoryId"]
                if (subcategoryIdParam != null) {
                    val subcategoryId = subcategoryIdParam.toIntOrNull()
                    if (subcategoryId != null) {
                        val subcategory = articlesDAO.findSubcategoryById(subcategoryId)
                        if (subcategory != null) call.respond(subcategory)
                        else call.respondText("Subcategory not found", status = HttpStatusCode.NotFound)
                    } else call.respondText("Invalid subcategory ID specified", status = HttpStatusCode.BadRequest)
                } else {
                    val subcategories = articlesDAO.getCategories()
                    if (subcategories != null) call.respond(subcategories)
                    else call.respondText("No subcategories found", status = HttpStatusCode.NotFound)
                }
            }
        }
        get("types") {
            val articleTypes = articlesDAO.getArticleTypes()
            if (articleTypes != null) call.respond(articleTypes)
            else call.respondText("No article types found", status = HttpStatusCode.NotFound)
        }
        get("wholePackagings") {
            val wholePackagings = articlesDAO.getWholePackagings()
            if (wholePackagings != null) call.respond(wholePackagings)
            else call.respondText("No whole packagings found", status = HttpStatusCode.NotFound)
        }
        get("fractionsPackagings") {
            val fractionsPackagings = articlesDAO.getFractionPackagings()
            if (fractionsPackagings != null) call.respond(fractionsPackagings)
            else call.respondText("No fractions packagings found", status = HttpStatusCode.NotFound)
        }
        get("{articleId?}") {
            val articleIdParam = call.parameters["articleId"]
            if (articleIdParam != null) {
                val articleId = articleIdParam.toIntOrNull()
                if (articleId != null) {
                    val article = articlesDAO.findArticleById(articleId)
                    if (article != null) call.respond(article) else call.respondText("No article found", status = HttpStatusCode.NotFound)
                } else call.respondText("Invalid article ID specified", status = HttpStatusCode.BadRequest)
            } else {
                val articles = articlesDAO.getArticles()
                if (articles != null) call.respond(articles) else call.respondText("No articles found", status = HttpStatusCode.NotFound)
            }
        }
    }
}

如果有人可以通过提供一个基本但比较全面的示例来帮助我,说明如何使用所有 Ktor 路由匹配器和处理程序(包括以嵌套资源方式),那将是非常棒的。

编辑:我已经使用不同的方法重写了路由,但我仍然想知道为什么我以前的版本没有按预期工作。这是我的第二种方法,似乎可以按预期工作(我已经测试过了):

routing {
    route("/v1") {
        route("stock") {
            get {
                val stock = stockDAO.getAllStock()
                if (stock != null) call.respond(stock) else call.respondText("No stock found", status = HttpStatusCode.NotFound)
            }
            get("{locationId}") {
                val locationIdParam = call.parameters["locationId"]
                if (locationIdParam != null) {
                    val locationId = locationIdParam.toIntOrNull()
                    if (locationId != null) {
                        val stock = stockDAO.getStockByLocationId(locationId)
                        if (stock != null) call.respond(stock) else call.respondText("No stock found", status = HttpStatusCode.NotFound)
                    } else call.respondText("ERROR: Invalid location ID specified.", status = HttpStatusCode.BadRequest)
                }
            }
        }

        route("nomenclature") {
            get {
                call.respondText("The resource you accessed is not a valid REST resource, but a parent node. Children nodes include articles, categories, subcategories and so on.")
            }

            route("articles") {
                get {
                    val articles = articlesDAO.getArticles()
                    if (articles != null) call.respond(articles) else call.respondText("No articles found", status = HttpStatusCode.NotFound)
                }
                get("{articleId}") {
                    val articleIdParam = call.parameters["articleId"]
                    if (articleIdParam != null) {
                        val articleId = articleIdParam.toIntOrNull()
                        if (articleId != null) {
                            val article = articlesDAO.findArticleById(articleId)
                            if (article != null) call.respond(article) else call.respondText("No article found", status = HttpStatusCode.NotFound)
                        } else call.respondText("Invalid article ID specified", status = HttpStatusCode.BadRequest)
                    }
                }

                route("categories") {
                    get {
                        val categories = articlesDAO.getCategories()
                        if (categories != null) call.respond(categories)
                        else call.respondText("No categories found", status = HttpStatusCode.NotFound)
                    }
                    get("{categoryId}") {
                        val categoryIdParam = call.parameters["categoryId"]
                        if (categoryIdParam != null) {
                            val categoryId = categoryIdParam.toIntOrNull()
                            if (categoryId != null) {
                                val category = articlesDAO.findCategoryById(categoryId)
                                if (category != null) call.respond(category)
                                else call.respondText("Category not found", status = HttpStatusCode.NotFound)
                            } else call.respondText("Invalid category ID specified", status = HttpStatusCode.BadRequest)
                        }
                    }
                }

                route("subcategories") {
                    get {
                        val subcategories = articlesDAO.getSubcategories()
                        if (subcategories != null) call.respond(subcategories)
                        else call.respondText("No subcategories found", status = HttpStatusCode.NotFound)
                    }
                    get("{subcategoryId}") {
                        val subcategoryIdParam = call.parameters["subcategoryId"]
                        if (subcategoryIdParam != null) {
                            val subcategoryId = subcategoryIdParam.toIntOrNull()
                            if (subcategoryId != null) {
                                val subcategory = articlesDAO.findSubcategoryById(subcategoryId)
                                if (subcategory != null) call.respond(subcategory)
                                else call.respondText("Subcategory not found", status = HttpStatusCode.NotFound)
                            } else call.respondText("Invalid subcategory ID specified", status = HttpStatusCode.BadRequest)
                        }
                    }
                }

                get("types") {
                    val articleTypes = articlesDAO.getArticleTypes()
                    if (articleTypes != null) call.respond(articleTypes)
                    else call.respondText("No article types found", status = HttpStatusCode.NotFound)
                }
                get("wholePackagings") {
                    val wholePackagings = articlesDAO.getWholePackagings()
                    if (wholePackagings != null) call.respond(wholePackagings)
                    else call.respondText("No whole packagings found", status = HttpStatusCode.NotFound)
                }
                get("fractionsPackagings") {
                    val fractionsPackagings = articlesDAO.getFractionPackagings()
                    if (fractionsPackagings != null) call.respond(fractionsPackagings)
                    else call.respondText("No fractions packagings found", status = HttpStatusCode.NotFound)
                }
            }
        }
    }
}
4

1 回答 1

3

原因是您没有为GET /nomenclature/articles/categories.

您为 设置了路线/articles,然后为设置了路线/categories,但内部没有处理程序。里面唯一的东西是get("{categoryId?}"),不匹配,因为没有尾卡。

获取的原因/nomenclature/articles/{articleId}是,它首先尝试匹配/articles,但由于无法匹配/categories(没有处理程序),它继续查找并最终找到包含通配符参数并匹配的最后一条路由。

如果您想为该特定路由设置处理程序,方法如下:

route("articles") {
    route("categories") {
        get("{categoryId?}") {
            ...
        }
        get {
            ... your code ...
        }
    }
}
于 2018-01-08T13:15:59.600 回答