【问题标题】:What is the best practice for multiple REST API calls with the same parameters具有相同参数的多个 REST API 调用的最佳实践是什么
【发布时间】:2021-01-29 20:16:17
【问题描述】:

我有一个接收各种参数的 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 处理这些常用参数,这样我们就不需要修改每个 Controller 并添加新添加的请求参数?

控制器看起来像这样:

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

}

【问题讨论】:

  • 能否分享控制器定义
  • @silentsudo,我已将控制器添加到帖子中。
  • 我已经添加了我的回复。

标签: java spring spring-boot rest spring-restcontroller


【解决方案1】:

如果您不知道请求中有多少参数,您可以使用 @RequestParam 作为 Map,如下所示 -

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

你可以传递这些参数如下 -

/api1?key1=value1&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_value&y=y_value&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>

【讨论】:

  • 这将导致大量的空检查,并且控制器中将出现容易出错的代码,最好确保控制器消耗的是什么,将它留给客户端,尽可能多的可能是开着门窗的房子。
  • @silentsudo 同意。
  • @silentsudo 我已经用多个选项更新了答案,谢谢。
【解决方案2】:

如果路径不一样,则不需要在@GetMapping注解中设置params字段,只需这样做:

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

如果路径相同,也可以这样做,但需要在 RequestParam 注解中添加“required=false”,并手动处理某些字段存在或不存在时的操作

【讨论】:

  • 感谢@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=a&age=1&location=test
http://localhost:8080/test?alphabets=a,b,c&age=1&location=test

现在您可以根据字母表中的值创建联结。

谢谢。

【讨论】:

    猜你喜欢
    • 2019-10-21
    • 1970-01-01
    • 2013-07-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-07-22
    • 1970-01-01
    相关资源
    最近更新 更多