Какова наилучшая практика для нескольких вызовов REST API с одинаковыми параметрами

#java #spring #spring-boot #rest #spring-restcontroller

#java #весна #spring-boot #rest #spring-restcontroller

Вопрос:

У меня есть список REST API, которые получают различные параметры, предназначенные для поиска, фильтрации и возврата данных обратно во внешний интерфейс.

 @GetMapping(value = "/api1", params = {"x,y,z,age,location"})
@GetMapping(value = "/api2", params = {"a,b,c,d,age,location"})
@GetMapping(value = "/api3", params = {"p,q,r,s,,age,location"})
@GetMapping(value = "/api4", params = {"p,q,r,s,,age,location"})
@GetMapping(value = "/api5", params = {"p,q,r,s,,age,location"})
  

Как вы можете заметить, проблема в том, что есть несколько параметров (возраст, местоположение), которые являются общими для всех этих конечных точек.

План состоит в том, что нам может потребоваться ввести новый параметр, такой как «пол», для всех этих конечных точек. Существует ли наилучшая практика для обработки этих общих параметров во всех API, чтобы нам не нужно было изменять каждый контроллер и добавлять вновь добавленный параметр запроса?

Контроллер будет выглядеть примерно так:

 @RestController
public class UserFilterController {


    @GetMapping(path = "/api1")
    public ResponseEntity filterUserWithApi1(String x, String y, String z, String age, String location) {

        return new ResponseEntity(HttpStatus.OK);
    }

    @GetMapping(path = "/api2")
    public ResponseEntity filterUserWithApi2(String a, String b, String c, String age, String location) {

        return new ResponseEntity(HttpStatus.OK);
    }

    @GetMapping(path = "/api3")
    public ResponseEntity filterUserWithApi3(String d, String e, String f, String age, String location) {

        return new ResponseEntity(HttpStatus.OK);
    }

    @GetMapping(path = "/api4")
    public ResponseEntity filterUserWithApi4(String g, String s, String h, String age, String location) {

        return new ResponseEntity(HttpStatus.OK);
    }

    @GetMapping(path = "/api5")
    public ResponseEntity filterUserWithApi5(String j, String k, String l, String age, String location) {

        return new ResponseEntity(HttpStatus.OK);
    }

}
  

Комментарии:

1. не могли бы вы поделиться определением контроллера

2. @silentsudo, я добавил контроллер в сообщение.

3. я добавил свой ответ.

Ответ №1:

Если вы не знаете, сколько параметров будет в запросе, вы можете использовать @RequestParam в качестве карты, как показано ниже —

 @GetMapping(path = "/api1")
public void test(@RequestParam Map<String, String> parameters) {
    //TODO
    String value1 = parameters.get("key1");
    ........
}
  

И вы можете передать эти параметры, как показано ниже —

 /api1?key1=value1amp;key2=value2...
  

или —

 @GetMapping(path = "/api1/{age}/{location}")
public ResponseEntity filterUserWithApi1(@PathVariable("age") String age,
                                         @PathVariable("location") String location,
                                         @RequestParam("x") String x,
                                         @RequestParam("y") String y,
                                         @RequestParam("z") String z) {
    return new ResponseEntity(HttpStatus.OK);
}
  

Запрос —

 /api1/24/earth?x=x_valueamp;y=y_valueamp;z=z_value
  

или-

 @GetMapping(path = "/api1/{age}/{location}/{x}/{y}/{z}")
public ResponseEntity filterUserWithApi1(@PathVariable("age") String age,
                                         @PathVariable("location") String location,
                                         @PathVariable("x") String x,
                                         @PathVariable("y") String y,
                                         @PathVariable("z") String z) 
{
    return new ResponseEntity(HttpStatus.OK);
}
  

ЗАПРОС —

 /api1/<age_value>/<location_value>/<x_value>/<y_value>/<z_value>
  

Комментарии:

1. это приведет к многочисленным проверкам null, и в контроллере будет присутствовать код, подверженный ошибкам, всегда лучше убедиться, что потребляет контроллер, оставляя его для клиента с таким количеством, и это может быть дом с открытой дверью и окном.

2. @silentsudo согласен.

3. @silentsudo Я обновил ответ несколькими вариантами, спасибо.

Ответ №2:

Если путь не совпадает, вам не нужно устанавливать params поле в @GetMapping аннотации, вы можете просто сделать :

 @GetMapping(path = "/api1")
public void myFunction( @RequestParam("age") String age, @RequestParam("location") String location, ... ) {
...
}
  

Если это один и тот же путь, вы также можете это сделать, но вам нужно будет добавить «required= false» в аннотацию RequestParam и вручную решить, что делать, если некоторые поля присутствуют или нет

Комментарии:

1. Спасибо @Prim, я использовал поле param только для удобства чтения в этом сообщении. В своем коде я использую предложенную вами структуру.

Ответ №3:

Я считаю, что ваш параметр запроса — это один атрибут, который имеет количество значений, а возраст / местоположение — это еще один обязательный параметр запроса, который присутствует в конце. Вот как я напишу контроллер, который знает заданные параметры

          @GetMapping(path = "/test")
        public Map<String, String> test(@RequestParam("alphabets") Set<String> alphabets,
                                        @RequestParam("age") int age,
                                        @RequestParam("location") String location) {
            final Map<String, String> responseMap = new HashMap<>();
            responseMap.put("alphabets", alphabets.toString());
            responseMap.put("age", Integer.toString(age));
            responseMap.put("location", location);
            return responseMap;
        }
  

Вызов этого контроллера выглядит следующим образом

 http://localhost:8080/test?alphabets=aamp;age=1amp;location=test
http://localhost:8080/test?alphabets=a,b,camp;age=1amp;location=test
  

Теперь вы можете создать соединение на основе значений, присутствующих в алфавитах.

Спасибо.