代码之家  ›  专栏  ›  技术社区  ›  Paul-Sebastian Manole

对于典型的REST实现,嵌套Ktor路由匹配器和处理程序的正确方法是什么?

  •  3
  • Paul-Sebastian Manole  · 技术社区  · 7 年前

    我在理解使用Ktor的DSL进行 request routing . 问题是,当我测试我的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)
                    }
                }
            }
        }
    }
    
    1 回复  |  直到 7 年前
        1
  •  3
  •   avolkmann    7 年前

    原因是您没有为指定任何处理程序 GET /nomenclature/articles/categories .

    你设置了一条路线 /articles ,然后 /categories ,但内部没有处理程序。 get("{categoryId?}") ,这不匹配,因为没有尾卡。

    获取的原因 /nomenclature/articles/{articleId} /文章 ,但因为它无法匹配 /类别 (没有处理程序),它继续查找并最终找到最后一个路由,其中包含一个通配符参数和匹配项。

    如果要为该特定路由设置处理程序,请执行以下操作:

    route("articles") {
        route("categories") {
            get("{categoryId?}") {
                ...
            }
            get {
                ... your code ...
            }
        }
    }