Spring: handle ambiguous mapping with BadRequest












0














I'm developing a Spring application, and at the moment I'm implementing a search on our customers registry.



A key-pointy of our users request is that the search can be done for at most ONE of the following parameters : name OR id (can be partial) OR shop id (the shop where the customer is registered)
Searches with more parameters ("more filters" if you prefer) in combination, are not allowed.



Here i ran into the problem: I developed a RestController with 1 endpoint handled by 3 different functions like this:



@RestController()
@RequestMapping("v1/customers")
public class ExampleController {

/**
* Search for customer's name (can be partial)
* @param name
* @return
*/
@GetMapping(value="search", params="name")
public String searchByName(String name) {
return "search for name";
}


/**
* Search for the customer by id (can be partial)
* @param name
* @return
*/
@GetMapping(value="search", params="id")
public String searchById(String id) {
return "search for id";
}

/**
* search for the customer from the shop id where he is registered
* @param name
* @return
*/
@GetMapping(value="search", params="shopId")
public String searchByShopID(String shopId) {
return "search for shop";
}

}


All works fine except for a problem:



The problem is that if the application recive a request with multiple query params like this:



http://localhost:8080/v1/customers/search?name=bob&shopId=897a



Spring throw an exception of "Ambiguous Mapping" and return an HTTP 500 status code



How can i handle it? It's possible to handle the case returning an HTTP 400 (and a custom message)? Maybe with something like a "Default mapping".










share|improve this question
























  • Is this something you could do on the front end? As in prevent more than one parameter from being entered by the user?
    – Katie.Sun
    Nov 19 '18 at 15:40












  • If you can't take care of it from the front end, you could use @Nullable to make an endpoint that accepts up to all 3 params and returns a 400 error if it has more than one
    – Katie.Sun
    Nov 19 '18 at 15:57










  • I think this is not possible. You may have to create a single method and apply some logic upon some request made.
    – Bunyamin Coskuner
    Nov 19 '18 at 15:59










  • @Katie.Sun, I had already managed it on the frontend, but i was looking for a way on the backend too to prevent frontend changes or other future clients to introduce error on the logic.
    – pippo paperino
    Nov 19 '18 at 16:31










  • Ok. I think the @Nullable idea might work, but I can't try it at the moment
    – Katie.Sun
    Nov 19 '18 at 16:33
















0














I'm developing a Spring application, and at the moment I'm implementing a search on our customers registry.



A key-pointy of our users request is that the search can be done for at most ONE of the following parameters : name OR id (can be partial) OR shop id (the shop where the customer is registered)
Searches with more parameters ("more filters" if you prefer) in combination, are not allowed.



Here i ran into the problem: I developed a RestController with 1 endpoint handled by 3 different functions like this:



@RestController()
@RequestMapping("v1/customers")
public class ExampleController {

/**
* Search for customer's name (can be partial)
* @param name
* @return
*/
@GetMapping(value="search", params="name")
public String searchByName(String name) {
return "search for name";
}


/**
* Search for the customer by id (can be partial)
* @param name
* @return
*/
@GetMapping(value="search", params="id")
public String searchById(String id) {
return "search for id";
}

/**
* search for the customer from the shop id where he is registered
* @param name
* @return
*/
@GetMapping(value="search", params="shopId")
public String searchByShopID(String shopId) {
return "search for shop";
}

}


All works fine except for a problem:



The problem is that if the application recive a request with multiple query params like this:



http://localhost:8080/v1/customers/search?name=bob&shopId=897a



Spring throw an exception of "Ambiguous Mapping" and return an HTTP 500 status code



How can i handle it? It's possible to handle the case returning an HTTP 400 (and a custom message)? Maybe with something like a "Default mapping".










share|improve this question
























  • Is this something you could do on the front end? As in prevent more than one parameter from being entered by the user?
    – Katie.Sun
    Nov 19 '18 at 15:40












  • If you can't take care of it from the front end, you could use @Nullable to make an endpoint that accepts up to all 3 params and returns a 400 error if it has more than one
    – Katie.Sun
    Nov 19 '18 at 15:57










  • I think this is not possible. You may have to create a single method and apply some logic upon some request made.
    – Bunyamin Coskuner
    Nov 19 '18 at 15:59










  • @Katie.Sun, I had already managed it on the frontend, but i was looking for a way on the backend too to prevent frontend changes or other future clients to introduce error on the logic.
    – pippo paperino
    Nov 19 '18 at 16:31










  • Ok. I think the @Nullable idea might work, but I can't try it at the moment
    – Katie.Sun
    Nov 19 '18 at 16:33














0












0








0


3





I'm developing a Spring application, and at the moment I'm implementing a search on our customers registry.



A key-pointy of our users request is that the search can be done for at most ONE of the following parameters : name OR id (can be partial) OR shop id (the shop where the customer is registered)
Searches with more parameters ("more filters" if you prefer) in combination, are not allowed.



Here i ran into the problem: I developed a RestController with 1 endpoint handled by 3 different functions like this:



@RestController()
@RequestMapping("v1/customers")
public class ExampleController {

/**
* Search for customer's name (can be partial)
* @param name
* @return
*/
@GetMapping(value="search", params="name")
public String searchByName(String name) {
return "search for name";
}


/**
* Search for the customer by id (can be partial)
* @param name
* @return
*/
@GetMapping(value="search", params="id")
public String searchById(String id) {
return "search for id";
}

/**
* search for the customer from the shop id where he is registered
* @param name
* @return
*/
@GetMapping(value="search", params="shopId")
public String searchByShopID(String shopId) {
return "search for shop";
}

}


All works fine except for a problem:



The problem is that if the application recive a request with multiple query params like this:



http://localhost:8080/v1/customers/search?name=bob&shopId=897a



Spring throw an exception of "Ambiguous Mapping" and return an HTTP 500 status code



How can i handle it? It's possible to handle the case returning an HTTP 400 (and a custom message)? Maybe with something like a "Default mapping".










share|improve this question















I'm developing a Spring application, and at the moment I'm implementing a search on our customers registry.



A key-pointy of our users request is that the search can be done for at most ONE of the following parameters : name OR id (can be partial) OR shop id (the shop where the customer is registered)
Searches with more parameters ("more filters" if you prefer) in combination, are not allowed.



Here i ran into the problem: I developed a RestController with 1 endpoint handled by 3 different functions like this:



@RestController()
@RequestMapping("v1/customers")
public class ExampleController {

/**
* Search for customer's name (can be partial)
* @param name
* @return
*/
@GetMapping(value="search", params="name")
public String searchByName(String name) {
return "search for name";
}


/**
* Search for the customer by id (can be partial)
* @param name
* @return
*/
@GetMapping(value="search", params="id")
public String searchById(String id) {
return "search for id";
}

/**
* search for the customer from the shop id where he is registered
* @param name
* @return
*/
@GetMapping(value="search", params="shopId")
public String searchByShopID(String shopId) {
return "search for shop";
}

}


All works fine except for a problem:



The problem is that if the application recive a request with multiple query params like this:



http://localhost:8080/v1/customers/search?name=bob&shopId=897a



Spring throw an exception of "Ambiguous Mapping" and return an HTTP 500 status code



How can i handle it? It's possible to handle the case returning an HTTP 400 (and a custom message)? Maybe with something like a "Default mapping".







java spring rest






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 19 '18 at 15:41

























asked Nov 19 '18 at 15:35









pippo paperino

185




185












  • Is this something you could do on the front end? As in prevent more than one parameter from being entered by the user?
    – Katie.Sun
    Nov 19 '18 at 15:40












  • If you can't take care of it from the front end, you could use @Nullable to make an endpoint that accepts up to all 3 params and returns a 400 error if it has more than one
    – Katie.Sun
    Nov 19 '18 at 15:57










  • I think this is not possible. You may have to create a single method and apply some logic upon some request made.
    – Bunyamin Coskuner
    Nov 19 '18 at 15:59










  • @Katie.Sun, I had already managed it on the frontend, but i was looking for a way on the backend too to prevent frontend changes or other future clients to introduce error on the logic.
    – pippo paperino
    Nov 19 '18 at 16:31










  • Ok. I think the @Nullable idea might work, but I can't try it at the moment
    – Katie.Sun
    Nov 19 '18 at 16:33


















  • Is this something you could do on the front end? As in prevent more than one parameter from being entered by the user?
    – Katie.Sun
    Nov 19 '18 at 15:40












  • If you can't take care of it from the front end, you could use @Nullable to make an endpoint that accepts up to all 3 params and returns a 400 error if it has more than one
    – Katie.Sun
    Nov 19 '18 at 15:57










  • I think this is not possible. You may have to create a single method and apply some logic upon some request made.
    – Bunyamin Coskuner
    Nov 19 '18 at 15:59










  • @Katie.Sun, I had already managed it on the frontend, but i was looking for a way on the backend too to prevent frontend changes or other future clients to introduce error on the logic.
    – pippo paperino
    Nov 19 '18 at 16:31










  • Ok. I think the @Nullable idea might work, but I can't try it at the moment
    – Katie.Sun
    Nov 19 '18 at 16:33
















Is this something you could do on the front end? As in prevent more than one parameter from being entered by the user?
– Katie.Sun
Nov 19 '18 at 15:40






Is this something you could do on the front end? As in prevent more than one parameter from being entered by the user?
– Katie.Sun
Nov 19 '18 at 15:40














If you can't take care of it from the front end, you could use @Nullable to make an endpoint that accepts up to all 3 params and returns a 400 error if it has more than one
– Katie.Sun
Nov 19 '18 at 15:57




If you can't take care of it from the front end, you could use @Nullable to make an endpoint that accepts up to all 3 params and returns a 400 error if it has more than one
– Katie.Sun
Nov 19 '18 at 15:57












I think this is not possible. You may have to create a single method and apply some logic upon some request made.
– Bunyamin Coskuner
Nov 19 '18 at 15:59




I think this is not possible. You may have to create a single method and apply some logic upon some request made.
– Bunyamin Coskuner
Nov 19 '18 at 15:59












@Katie.Sun, I had already managed it on the frontend, but i was looking for a way on the backend too to prevent frontend changes or other future clients to introduce error on the logic.
– pippo paperino
Nov 19 '18 at 16:31




@Katie.Sun, I had already managed it on the frontend, but i was looking for a way on the backend too to prevent frontend changes or other future clients to introduce error on the logic.
– pippo paperino
Nov 19 '18 at 16:31












Ok. I think the @Nullable idea might work, but I can't try it at the moment
– Katie.Sun
Nov 19 '18 at 16:33




Ok. I think the @Nullable idea might work, but I can't try it at the moment
– Katie.Sun
Nov 19 '18 at 16:33












2 Answers
2






active

oldest

votes


















1














You can use https://docs.spring.io/spring/docs/5.0.8.RELEASE/javadoc-api/org/springframework/web/bind/annotation/RequestMapping.html#params-- parameter to filter by HTTP parameters. In your case it would be something like:



 @GetMapping(value="search",params = "name")
public String searchByName(@RequestParam("name") String name) {
return "search for name";
}

@GetMapping(value="search",params = "shopId")
public String searchByShopID(@RequestParam("shopId") String shopId) {
return "search for shop";
}





share|improve this answer





















  • Hi thank for your suggestion but as i wrote in the question (the code part) I already use the "params" parameter (and it works fine) my problem is to handle requests that do not match with any of allowed cases and return an HTTP status 400 (Bad Request)
    – pippo paperino
    Nov 19 '18 at 16:53



















0














Thank to @GauravRai1512 i read another time the Spring's documentation, and i noticed that with "params" i can filter for "absent" paramenters too! (i didn't notice at first time) this way params="!myParam"



So i tried to do it this way an it works:



(Let me know your opionion :) )



@RestController()
@RequestMapping("v1/customers")
public class ExampleController {

/**
* Search for customer's name (can be partial)
* @param name
* @return
*/
@GetMapping(value="search", params={"name", "!id", "!shopId"})
public String searchByName(String name) {
return "search for name";
}


/**
* Search for the customer by id (can be partial)
* @param name
* @return
*/
@GetMapping(value="search", params={"!name", "id", "!shopId"})
public String searchById(String id) {
return "search for id";
}

/**
* search for the customer from the shop id where he is registered
* @param name
* @return
*/
@GetMapping(value="search", params={"!name", "!id", "shopId"})
public String searchByShopID(String shopId) {
return "search for shop";
}

/**
* Handle invalid reqest
* @param name
* @return
*/
@GetMapping(value="search")
public String searchByShopID() {
return "Invalid!";
}

}





share|improve this answer





















    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53377958%2fspring-handle-ambiguous-mapping-with-badrequest%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    2 Answers
    2






    active

    oldest

    votes








    2 Answers
    2






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    1














    You can use https://docs.spring.io/spring/docs/5.0.8.RELEASE/javadoc-api/org/springframework/web/bind/annotation/RequestMapping.html#params-- parameter to filter by HTTP parameters. In your case it would be something like:



     @GetMapping(value="search",params = "name")
    public String searchByName(@RequestParam("name") String name) {
    return "search for name";
    }

    @GetMapping(value="search",params = "shopId")
    public String searchByShopID(@RequestParam("shopId") String shopId) {
    return "search for shop";
    }





    share|improve this answer





















    • Hi thank for your suggestion but as i wrote in the question (the code part) I already use the "params" parameter (and it works fine) my problem is to handle requests that do not match with any of allowed cases and return an HTTP status 400 (Bad Request)
      – pippo paperino
      Nov 19 '18 at 16:53
















    1














    You can use https://docs.spring.io/spring/docs/5.0.8.RELEASE/javadoc-api/org/springframework/web/bind/annotation/RequestMapping.html#params-- parameter to filter by HTTP parameters. In your case it would be something like:



     @GetMapping(value="search",params = "name")
    public String searchByName(@RequestParam("name") String name) {
    return "search for name";
    }

    @GetMapping(value="search",params = "shopId")
    public String searchByShopID(@RequestParam("shopId") String shopId) {
    return "search for shop";
    }





    share|improve this answer





















    • Hi thank for your suggestion but as i wrote in the question (the code part) I already use the "params" parameter (and it works fine) my problem is to handle requests that do not match with any of allowed cases and return an HTTP status 400 (Bad Request)
      – pippo paperino
      Nov 19 '18 at 16:53














    1












    1








    1






    You can use https://docs.spring.io/spring/docs/5.0.8.RELEASE/javadoc-api/org/springframework/web/bind/annotation/RequestMapping.html#params-- parameter to filter by HTTP parameters. In your case it would be something like:



     @GetMapping(value="search",params = "name")
    public String searchByName(@RequestParam("name") String name) {
    return "search for name";
    }

    @GetMapping(value="search",params = "shopId")
    public String searchByShopID(@RequestParam("shopId") String shopId) {
    return "search for shop";
    }





    share|improve this answer












    You can use https://docs.spring.io/spring/docs/5.0.8.RELEASE/javadoc-api/org/springframework/web/bind/annotation/RequestMapping.html#params-- parameter to filter by HTTP parameters. In your case it would be something like:



     @GetMapping(value="search",params = "name")
    public String searchByName(@RequestParam("name") String name) {
    return "search for name";
    }

    @GetMapping(value="search",params = "shopId")
    public String searchByShopID(@RequestParam("shopId") String shopId) {
    return "search for shop";
    }






    share|improve this answer












    share|improve this answer



    share|improve this answer










    answered Nov 19 '18 at 16:30









    GauravRai1512

    58811




    58811












    • Hi thank for your suggestion but as i wrote in the question (the code part) I already use the "params" parameter (and it works fine) my problem is to handle requests that do not match with any of allowed cases and return an HTTP status 400 (Bad Request)
      – pippo paperino
      Nov 19 '18 at 16:53


















    • Hi thank for your suggestion but as i wrote in the question (the code part) I already use the "params" parameter (and it works fine) my problem is to handle requests that do not match with any of allowed cases and return an HTTP status 400 (Bad Request)
      – pippo paperino
      Nov 19 '18 at 16:53
















    Hi thank for your suggestion but as i wrote in the question (the code part) I already use the "params" parameter (and it works fine) my problem is to handle requests that do not match with any of allowed cases and return an HTTP status 400 (Bad Request)
    – pippo paperino
    Nov 19 '18 at 16:53




    Hi thank for your suggestion but as i wrote in the question (the code part) I already use the "params" parameter (and it works fine) my problem is to handle requests that do not match with any of allowed cases and return an HTTP status 400 (Bad Request)
    – pippo paperino
    Nov 19 '18 at 16:53













    0














    Thank to @GauravRai1512 i read another time the Spring's documentation, and i noticed that with "params" i can filter for "absent" paramenters too! (i didn't notice at first time) this way params="!myParam"



    So i tried to do it this way an it works:



    (Let me know your opionion :) )



    @RestController()
    @RequestMapping("v1/customers")
    public class ExampleController {

    /**
    * Search for customer's name (can be partial)
    * @param name
    * @return
    */
    @GetMapping(value="search", params={"name", "!id", "!shopId"})
    public String searchByName(String name) {
    return "search for name";
    }


    /**
    * Search for the customer by id (can be partial)
    * @param name
    * @return
    */
    @GetMapping(value="search", params={"!name", "id", "!shopId"})
    public String searchById(String id) {
    return "search for id";
    }

    /**
    * search for the customer from the shop id where he is registered
    * @param name
    * @return
    */
    @GetMapping(value="search", params={"!name", "!id", "shopId"})
    public String searchByShopID(String shopId) {
    return "search for shop";
    }

    /**
    * Handle invalid reqest
    * @param name
    * @return
    */
    @GetMapping(value="search")
    public String searchByShopID() {
    return "Invalid!";
    }

    }





    share|improve this answer


























      0














      Thank to @GauravRai1512 i read another time the Spring's documentation, and i noticed that with "params" i can filter for "absent" paramenters too! (i didn't notice at first time) this way params="!myParam"



      So i tried to do it this way an it works:



      (Let me know your opionion :) )



      @RestController()
      @RequestMapping("v1/customers")
      public class ExampleController {

      /**
      * Search for customer's name (can be partial)
      * @param name
      * @return
      */
      @GetMapping(value="search", params={"name", "!id", "!shopId"})
      public String searchByName(String name) {
      return "search for name";
      }


      /**
      * Search for the customer by id (can be partial)
      * @param name
      * @return
      */
      @GetMapping(value="search", params={"!name", "id", "!shopId"})
      public String searchById(String id) {
      return "search for id";
      }

      /**
      * search for the customer from the shop id where he is registered
      * @param name
      * @return
      */
      @GetMapping(value="search", params={"!name", "!id", "shopId"})
      public String searchByShopID(String shopId) {
      return "search for shop";
      }

      /**
      * Handle invalid reqest
      * @param name
      * @return
      */
      @GetMapping(value="search")
      public String searchByShopID() {
      return "Invalid!";
      }

      }





      share|improve this answer
























        0












        0








        0






        Thank to @GauravRai1512 i read another time the Spring's documentation, and i noticed that with "params" i can filter for "absent" paramenters too! (i didn't notice at first time) this way params="!myParam"



        So i tried to do it this way an it works:



        (Let me know your opionion :) )



        @RestController()
        @RequestMapping("v1/customers")
        public class ExampleController {

        /**
        * Search for customer's name (can be partial)
        * @param name
        * @return
        */
        @GetMapping(value="search", params={"name", "!id", "!shopId"})
        public String searchByName(String name) {
        return "search for name";
        }


        /**
        * Search for the customer by id (can be partial)
        * @param name
        * @return
        */
        @GetMapping(value="search", params={"!name", "id", "!shopId"})
        public String searchById(String id) {
        return "search for id";
        }

        /**
        * search for the customer from the shop id where he is registered
        * @param name
        * @return
        */
        @GetMapping(value="search", params={"!name", "!id", "shopId"})
        public String searchByShopID(String shopId) {
        return "search for shop";
        }

        /**
        * Handle invalid reqest
        * @param name
        * @return
        */
        @GetMapping(value="search")
        public String searchByShopID() {
        return "Invalid!";
        }

        }





        share|improve this answer












        Thank to @GauravRai1512 i read another time the Spring's documentation, and i noticed that with "params" i can filter for "absent" paramenters too! (i didn't notice at first time) this way params="!myParam"



        So i tried to do it this way an it works:



        (Let me know your opionion :) )



        @RestController()
        @RequestMapping("v1/customers")
        public class ExampleController {

        /**
        * Search for customer's name (can be partial)
        * @param name
        * @return
        */
        @GetMapping(value="search", params={"name", "!id", "!shopId"})
        public String searchByName(String name) {
        return "search for name";
        }


        /**
        * Search for the customer by id (can be partial)
        * @param name
        * @return
        */
        @GetMapping(value="search", params={"!name", "id", "!shopId"})
        public String searchById(String id) {
        return "search for id";
        }

        /**
        * search for the customer from the shop id where he is registered
        * @param name
        * @return
        */
        @GetMapping(value="search", params={"!name", "!id", "shopId"})
        public String searchByShopID(String shopId) {
        return "search for shop";
        }

        /**
        * Handle invalid reqest
        * @param name
        * @return
        */
        @GetMapping(value="search")
        public String searchByShopID() {
        return "Invalid!";
        }

        }






        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Nov 19 '18 at 17:30









        pippo paperino

        185




        185






























            draft saved

            draft discarded




















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.





            Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


            Please pay close attention to the following guidance:


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53377958%2fspring-handle-ambiguous-mapping-with-badrequest%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            MongoDB - Not Authorized To Execute Command

            How to fix TextFormField cause rebuild widget in Flutter

            in spring boot 2.1 many test slices are not allowed anymore due to multiple @BootstrapWith