为互斥请求参数设计API的更好方法是什么?

Soe*_*ark 7 java spring api-design spring-mvc

当请求参数互斥时,在@Controller方法上设计API的更好方法是什么?

假设有一个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);
}
Run Code Online (Sandbox Code Playgroud)

这是重点:

用户无法使用多个请求参数进行查询.只有一个请求参数或没有请求参数是有效的(仅一个userId,agetype在一个请求必须存在).

我不确定为这种情况设计API的更好方法是什么.你能给我一些建议吗?

And*_*lko 3

我喜欢评论中的人建议的方法:

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

// similarly, define two more
Run Code Online (Sandbox Code Playgroud)

在您开始管理每个端点的限制之前,它看起来很稳健且可行。它看起来很乏味并且难以维护。此外,我不确定不带参数的端点会如何反应。它会被其他方法调用或隐藏吗?

我建议不要编写限制,而是引入条件 - 每个端点的要求。它可能是Map<String, Function<String, List<User>>>以下格式:

<param name> -> <action to get a list>
Run Code Online (Sandbox Code Playgroud)

我还建议您将所有传入的请求参数收集到一个中,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) { ... }

}
Run Code Online (Sandbox Code Playgroud)