[스프링 부트 핵심가이드] 책을 참고하여 작성하였습니다.
GET API
GET API는 웹 애플리케이션 서버에서 값을 가져올 때 사용하는 API이다. GET API를 작성하는 방법은 다양하다. 그 방법의 대해 알아보자.
@RequestMapping으로 구현하기
@RequestMapping 어노테이션을 별다른 설정 없이 선언하면 HTTP의 모든 요청을 받는다. 그렇기 때문에 GET형식의 요청만 받기 위해선 어노테이션에 별도 설정이 필요하다.
아래의 코드와 같이 @RequestMapping 어노테이션의 method 요소의 값을 RequestMethod.GET으로 설정하면 GET으로만 설정할 수 있다.
package com.core.testproject.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api/v1/get-api")
public class GetController {
@RequestMapping(value = "/hello", method = RequestMethod.GET)
public String getHello(){
return "Hello World";
}
}
물론 스프링 4.3 버전 이후에는 새로 나온 아래의 어노테이션을 사용하기 때문에 @RequestMapping 어노테이션은 더 이상 사용되지 않는다.
- @GetMapping
- @PostMapping
- @PutMapping
- @DeleteMapping
매개 변수가 없는 GET 메서드 구현
@GetMapping을 이용하여 별도의 매개변수 없이 GET API 구현하는 코드이다.
@GetMapping(value = "/name")
public String getName(){
return "Flature";
}
매개 변수가 없는 요청은 @GetMapping value의 매핑된 URL을 그대로 입력하면 스프링부트 애플리케이션이 정해진 응답을 반환한다.
@PathVariable을 활용한 GET 메서드 구현
실무 환경에서는 매개변수를 받지 않는 메서드는 거의 활용되지 않는고 대부분은 매개변수를 받는 메서드를 작성하게 된다. 이 방법은 매개변수를 받을 때 자주 쓰이는 방법 중 하나이며 URL 자체에 값을 담아 요청하는 방식이다.
@GetMapping(value = "/variable1/{variable}")
public String getVariable1(@PathVariable String variable){
return variable;
}
위 코드의 @GetMapping에서 사용된 중괄호({ })로 표기된 위치의 값을 받아 요청한다(실제 요청 시 중괄호는 들어가지 않고 값만 들어간다.). 값을 URI의 일부를 파라미터 값으로 사용하여 간단히 전달할 때 주로 사용하며, GET 요청에서 많이 사용된다.
이러한 방식을 이용할 때는 지켜야 할 규칙이 몇가지 존재한다.
- @GetMapping 어노테이션의 값으로 URL을 입력할 때 중괄호를 사용해 어느 위치에서 값을 받을 지 지정해야 한다.
- 메서드의 매개변수와 그 중괄호의 값을 연결하기 위해 @PathVariable 어노테이션을 명시해야 하며, 중괄호 안에 변수명과 매개변수의 변수명이 동일하여야 한다.
만약 @GetMapping 어노테이션의 지정한 변수와 메서드 매개변수 이름을 동일하게 맞추기 어렵다면 아래의 방식을 사용하여야 한다.
@GetMapping(value = "/variable2/{variable}")
public String getVariable2(@PathVariable("variable") String var){
return var;
}
@PathVariable 어노테이션 뒤에 괄호를 열어 @GetMapping 어노테이션의 변수명을 지정한다. (value를 사용해도 된다.)
유지보수 관점에서 다른 변수, 메서드에서 사용되는 네이밍을 동일하게 진행해야 하기 때문에 @GetMapping에서 사용하는 변수의 이름을 매개변수에서 하나하나 다 일치시킬 수 없는 경우가 발생한다. 이런 경우에 위와 같은 방식으로 사용하면 된다.
주의할 점은 @PathVariable을 사용할 경우 Parameter가 생략될 경우 Exception이 발생한다. 그렇기 때문에 메서드의 매개변수를 Optional 과 @GetMapping의 URL를 아래 코드와 같이 처리하기도 한다.
@GetMapping(value = {"/variable1/{variable}", "/variable1/"})
public String getVariable1(@PathVariable Optional<String> variable){
if (variable.isPresent()) {
return "variable: " + variable.get();
} else {
return "variable missing";
}
}
@RequestParam을 활용한 GET 메서드 구현
GET 요청을 구현할 때 앞에서 살펴본 방법처럼 URL 경로에 값을 담아 요청을 보내는 방법 외에도 쿼리 형식으로 값을 전달할 수도 있다. 즉, URI에서 '?'를 기준으로 우측에 '{키}={값}' 형태로 구성된 요청을 전송하는 방법이다.
이와 같은 형식을 처리하려면 @RequestParam을 활용하면 된다.
// http://localhost:8080/api/v1/get-api/request1?name=value1&email=value2&organization=value3
@GetMapping(value = "/request1")
public String getRequestParam1(
@RequestParam String name,
@RequestParam String email,
@RequestParam String organization
) {
return name + " " + email + " " + organization;
}
위 예제와 같이 @RequestParam 어노테이션을 명시해 쿼리 값과 매핑하면 된다. 1번 줄의 주석을 보면 '?' 오른쪽에 쿼리스트링이 명시되어 있다. 쿼리스트링에는 키(변수의 이름)가 적혀 있기 때문에 이 값을 기준으로 메서드의 매개변수에 이름을 매핑하면 된다.
만약 위와 같은 이유로 동일한 이름으로 매핑이 어렵다면 @PathVariable 에서 사용한 방법처럼 value 요소로 매핑처리 한다.
만약 쿼리스트링에 어떤 값이 들어올지 모른다면 어떻게 작성해야 할까?
// http://localhost:8080/api/v1/get-api/request2?key1=value1&key2=value2
@GetMapping(value = "/request2")
public String getRequestParam2(@RequestParam Map<String, String> param) {
StringBuilder sb = new StringBuilder();
param.entrySet().forEach(map -> {
sb.append(map.getKey() + " : " + map.getValue() + "\n");
});
return sb.toString();
}
예제와 같이 Map 객체를 활용할 수 있다. Map을 활용하면 작성하는 값에 상관없이 요청을 받을 수 있다. 예를 들어 회원가입 관련 API 가 있다고 가정하면 필수 항목도 있지만 선택 항목도 존재한다. 이런 경우 매개변수의 항목이 일정하지 않을 수 있어 Map 객체를 활용하기도 한다.
@PathVariable 와 @RequestParam 사용 기준
둘 중 어떤 애노테이션 사용할지 결정하는 것은 해당 상황과 개발자의 선호에 따라 달라지겠지만, 일반적인 사용기준은 다음과 같다.
@PathVariable은 ' /users/{userId} ' 와 같은 방법으로 사용하고 URL의 일부를 파라미터를 포함시켜 계층적이고 의미 있는 경로로 표현한다. 그렇기 때문에 자원의 식별이나 특정 자원에 대한 연산을 표현하는 데 적합하다. 반면에 URL의 구조를 변경해야 할 때 유연성이 떨어진다.
@RequestParam은 ' /users?name=John '와 같은 쿼리스트링 표기할 때 사용한다. 장점으로는 다양한 조합의 파라미터를 유연하게 처리할 수 있고 선택적인 필터, 정렬, 페이징 등의 연산의 유리하다. 단점으로는 URL이 복잡해질 수 있고, 자원의 식별에는 적합하지 않다.
이제 사용기준에 대해 알아보자.
- 자원의 식별: 특정 자원을 식별하는 경우에는 @PathVariable을 사용하는 것이 일반적이다.
예: /users/{userId} - 필터링, 정렬, 페이징: 쿼리 스트링을 사용하여 선택적인 파라미터를 처리하는 것이 유용하다.
예: /products?category=electronics&sort=price-asc - 자원의 계층 구조: 계층적인 자원 관계를 나타낼 때는 @PathVariable이 적합하다.
예: /departments/{departmentId}/employees - 명확성: 사용자나 개발자에게 API의 의도를 명확하게 전달하는 것이 중요하다. URL의 의미와 구조를 명확하게 표현할 수 있는 방식을 선택해야 한다.
- 유연성: 미래의 요구사항 변경에 대응하기 위해 얼마나 유연한지 고려해야 한다.
DTO 객체를 활용한 GET 메서드 구현
해당 방법을 테스트 하기 위해 간단히 DTO를 구성하자.
DTO 클래스에는 전달하고자 하는 필드 객체를 선언하고 gettter/setter 메서드를 구현하면 된다.
package com.core.testproject.dto;
public class MemberDto {
private String name;
private String email;
private String organization;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getOrganization() {
return organization;
}
public void setOrganization(String organization) {
this.organization = organization;
}
@Override
public String toString() {
return "MemberDTO{" +
"name='" + name + '\'' +
", email='" + email + '\'' +
", organization='" + organization + '\'' +
'}';
}
}
DTO 클래스의 선언된 필드는 컨트롤러의 메서드에서 쿼리 파라미터의 키와 매핑된다. 즉, 쿼리스트링의 키가 정해져 있지만 받아야 할 파라미터가 많은 경우 사용되며 DTO 객체 하나만을 사용함으로써 코드의 가독성을 높일 수 있다.
// http://localhost:8080/api/v1/get-api/request3?name=value1&email=value2&organization=value3
@GetMapping(value = "/request3")
public String getRequestParam3(MemberDto memberDTO) {
return memberDTO.toString();
}
'Framework > Spring' 카테고리의 다른 글
[Spring] REST API를 명세하는 방법 - Swagger (1) | 2023.10.11 |
---|---|
[Spring] POST, PUT, DELETE API (0) | 2023.10.11 |
[Spring] REST API 란? (0) | 2023.10.05 |
[Spring] 레이어드 아키텍처와 스프링의 레이어드 아키텍처 (0) | 2023.10.05 |
[Spring] 스프링 부트의 동작 방식 (0) | 2023.10.05 |