2017-10-17 200 views
0

我在理解使用Ktor的DSL request routing的正确方法时遇到了一些麻烦。 问题是,当我测试我的API并尝试GET /nomenclature/articles/categories应该返回所有文章类别的列表时,我得到Invalid article specified,当articleId参数无效时,我返回/nomenclature/articles/{articleId}路由的消息。为典型的REST实现嵌套Ktor路由匹配器和处理程序的正确方法是什么?

这里是我的代码:

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

的原因是,你还没有指定任何处理程序GET /nomenclature/articles/categories

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

原因让/nomenclature/articles/{articleId}是,它首先试图匹配/articles,但因为它无法比拟/categories(没有处理),它继续寻找,终于找到了最后的路线,其中包含通配符参数和火柴。

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

route("articles") { 
    route("categories") { 
     get("{categoryId?}") { 
      ... 
     } 
     get { 
      ... your code ... 
     } 
    } 
} 
相关问题