Как лучше разработать API для взаимоисключающих параметров запроса? - PullRequest
0 голосов
/ 03 ноября 2018

Как лучше разработать API для метода @Controller, когда параметры запроса являются взаимоисключающими?

Допустим, существует API для предоставления списка пользователей, который соответствует параметрам запроса.

Код:

public ResponseEntity getList(@RequestParam(required = false) Integer userId,
                              @RequestParam(required = false) User.Type userType,
                              @RequestParam(required = false) Integer age) {
        List<User> userList = null;
        if (userId != null) {
            //logic
            userList = getUserByUserId()
        } else if (userType != null) {
            //logic
            userList = getUserByType()
        } else if (age != null) {
            //logic
            userList = getListByAge()
        } else {
            userList = getAllWithoutCondition();
        }
        return ResponseEntity.ok(userList);
}

Вот точка:

Пользователь не может запрашивать более одного параметра запроса. Только один параметр запроса или параметр запроса не действителен (в запросе должен существовать только один из userId, age или type).

Я не уверен, как лучше разработать API для этой ситуации. Можете дать мне совет?

1 Ответ

0 голосов
/ 03 ноября 2018

Мне нравится подход, предложенный ребятами в комментариях:

@RequestMapping(value = "...", params = {"!userType", "!userAge"})
public ResponseEntity<List<User>> getListByUserId(@RequestParam Integer userId) { ... }

// similarly, define two more

Это выглядит надежным и выполнимым, пока вы не начнете управлять ограничениями для каждой конечной точки. Это выглядит утомительно и трудно поддерживать. Кроме того, я не уверен, как отреагирует конечная точка, которая не принимает никаких параметров. Будет ли он вызван или будет скрыт другими методами?

Вместо написания ограничений я предлагаю ввести условия - требования для каждой конечной точки. Это может быть Map<String, Function<String, List<User>>> в следующем формате:

<param name> -> <action to get a list>

Я также советую вам собрать все входящие параметры запроса в один Map<String, String>, чтобы проверить его по размеру.

public class Controller {

    private Map<String, Function<String, List<User>>> handlers = new HashMap<>();

    {
        handlers.put("userId", id -> getUsersById(Integer.valueOf(id)));
        handlers.put("userType", type -> getUsersByType(User.Type.valueOf(type)));
        handlers.put("userAge", age -> getUsersByAge(Integer.valueOf(age)));
    }

    @RequestMapping("...")
    public ResponseEntity<List<User>> getList(@RequestParam Map<String, String> params) {
        if (params.size() > 1) {
            return ResponseEntity.unprocessableEntity().build();
        }

        if (params.size() == 0) {
            return ResponseEntity.ok(getAllWithoutCondition());
        }

        Map.Entry<String, String> paramEntry = params.entrySet().iterator().next();

        return ResponseEntity.ok(handlers.get(paramEntry.getKey()).apply(paramEntry.getValue()));
    }

    private List<User> getAllWithoutCondition() { ... }

    private List<User> getUsersById(Integer id) { ... }
    private List<User> getUsersByType(User.Type type) { ... }
    private List<User> getUsersByAge(Integer age) { ... }

}
...