2017-10-17 14 views
0

J'ai un peu de mal à comprendre la bonne façon d'utiliser le DSL de Ktor pour request routing. Le problème est que lorsque je teste mon API et essaie de GET /nomenclature/articles/categories qui devrait retourner une liste de toutes les catégories d'articles, je reçois à la place Invalid article specified un message que je renvoie pour la route /nomenclature/articles/{articleId} lorsque le paramètre articleId n'est pas valide.Quelle est la bonne façon d'imbriquer les routeurs et les routeurs Ktor pour une implémentation REST typique?

Voici mon code:

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) 
      } 
     } 
    } 
} 

Ce serait vraiment génial si quelqu'un pouvait me aider en fournissant un exemple de base mais un peu complet de la façon d'utiliser tous matchers itinéraire Ktor et gestionnaires, y compris dans une ressource imbriquée manière.

EDIT: J'ai réécrit le routage en utilisant une approche différente, mais j'aimerais quand même savoir pourquoi ma version précédente ne fonctionnait pas comme prévu. Voilà ma deuxième approche qui semble fonctionner comme prévu (je l'ai testé):

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) 
       } 
      } 
     } 
    } 
} 

Répondre

1

La raison est que vous avez spécifié aucun gestionnaire pour GET /nomenclature/articles/categories.

Vous configurez un itinéraire pour /articles, puis pour /categories, mais il n'y a aucun gestionnaire à l'intérieur. La seule chose à l'intérieur est get("{categoryId?}"), ce qui ne correspond pas, puisqu'il n'y a pas de tailcard.

La raison pour obtenir /nomenclature/articles/{articleId} est, qu'il essaie d'abord de faire correspondre /articles, mais comme il ne peut pas correspondre /categories (il n'y a pas de gestionnaire), il se poursuit à la recherche et trouve enfin la dernière route, qui contient un paramètre générique et matchs .

Si vous souhaitez configurer un gestionnaire pour cet itinéraire spécifique, voici comment:

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