REST(Representational State Transfer : 자원의 상태 전달)
네트워크 아키텍처 원칙
자원을 이름으로 구분하여 해당 자원의 상태를 주고 받는 것
Client,Server: 클라이언트와 서버는 서로 독립적으로 분리 되어 있어야 함.
Stateless: 요청에 대해서 클라이언트의 상태를 서버에 저장하지 않음.
Cache: 클라이언트는 서버의 응답을 Cache(임시 저장)할 수 있어야 함.
계층화 : 서버와 클라이언트 사이에, 방화벽, 게이트웨이,Proxy등 다양한 계층 형태로 구성이 가능해야 하며, 이를 확장할 수 있어야 함.
인터페이스 일관성 : 인터페이스의 일관성을 지키고, 아키텍처를 단순화시켜 클라이언트와 서버가 독립적으로 개선될 수 있어야 한다.
http://localohost/user/100
Resource : user
식별자 : 100
Web에서는 다양한 방식으로 데이터를 전달할 수 있다.
ex) HTML, XML, JSON, TEXT...
HTTP 헤더에 어떤 타입의 데이터인지 지정할 수 있음.
리소스 조작을 위해, 데이터 전체를 보내는게 아닌, 메세지로 전달
요청하는 데이터가 어떻게 처리되어야 하는지 충분한 데이터를 포함할 수 있어야 함.
HTTP 기반의 REST에서는 HTTP Method와 Header 정보, 그리고 URI가 포함되는 정보로 표현할 수 있음.
GET: https://foo.co.kr/user/100, 사용자의 정보 요청
POST: https://foo.co.kr/user , 사용자의 정보 생성
PUT: https://foo.co.kr/user , 사용자 정보 생성 및 수정
DELETE: https://foo.co.kr/user/100 사용자 정보 삭제
REST API를 개발할 때, 단순히 Client 요청에 대한 데이터만 응답해주는 것이 아닌, 관련 리소스에 대한 Link 정보까지 같이 포함되어야 함.
이러한 조건들을 잘 갖춘 경우 REST Ful하다고 표현, 이를 REST API라고 부름.
@RestController
@RequestMapping("/api/get")
public class GetApiController {
@GetMapping(path="/hello") //http://localhost:8081/api/get/hello
public String hello(){
return "get Hello";
}
@RequestMapping(path = "/hi",method = RequestMethod.GET)
public String hi(){
return "hi";
}
}
여러 방법으로 Mapping을 할 수 있음.
// http://localhost:8081/api/get/path-variable/{name}
// GetMapping 이름과 매개변수 이름 같아야 함 ->
@GetMapping(path = "/path-variable/{name}")
public String pathVariable(@PathVariable(name = "name") String pathName){
System.out.println("path variable : " + pathName );
return pathName;
}
url에는 고정되어 변하지 않는 값과 변하는 값이 있다.
변하는 부분은 { }로 묶어서 선언함.
http://localhost:8081/api/get/path-variable/{name}
위 url는 사용자에 따라 name에 해당하는 값이 변화하는 경우다.
@PathVaribale을 사용하여 매개변수로 받을 수 있다.
선언한 url과 같은 이름으로 매개변수 이름을 설정해야 하는데, default name을 url과 같게 선언하면, 다른 이름으로 매개변수를 사용할 수 있다.
@PathVariable(name = "name")
query-param은 url에서 ?key1=value1 & key2=value2 & key3 = value3의 형태로 전달된다.
Map형태로
//http://localhost:8081/api/get/query-param?user=steve&email=steve@gmail.com&age=30
@GetMapping(path = "/query-param")
public String queryParam(@RequestParam Map<String,String> queryParam){
StringBuilder sb = new StringBuilder();
queryParam.entrySet().forEach( entry -> {
System.out.println(entry.getKey());
System.out.println(entry.getValue());
System.out.println("\n");
sb.append(entry.getKey()+" = "+entry.getValue() +"\n");
});
return sb.toString();
}
일반형 매개변수로
// 넘겨 받는 매개변수 제한 가능, 수정할 때, 귀찮음
@GetMapping(path = "/query-param02")
public String queryParam02(
@RequestParam String name,
@RequestParam String email,
@RequestParam int age
){
return name + " " + email + " " + age;
}
dto 클래스를 생성하여, 참조형으로
// 참조형 매개변수로 선언, 깔끔함. dto
@GetMapping(path = "/query-param03")
public String queryParam03(UserRequest userRequest){
System.out.println(userRequest.getName());
System.out.println(userRequest.getEmail());
System.out.println(userRequest.getAge());
return userRequest.toString();
}
DTO
DTO(Data Transfer Object) 는 계층 간 데이터 교환을 하기 위해 사용하는 객체로, DTO는 로직을 가지지 않는 순수한 데이터 객체(getter & setter만 가진 클래스)
@RestController
@RequestMapping("/api")
public class PostApiController {
// post일 때는 RequestBody get일 때는 RequestParam
@PostMapping("/post")
public void post(@RequestBody Map<String,Object> requestData){
requestData.forEach((key, value) -> {
System.out.println("key : " + key);
System.out.println("value : " + value);
});
}
request를 받기 위해서는 @RequestBody 필요함.
Map의 형태로 request를 받으면 어떤 값이 오더라도 받을 수 있지만, 그러한 점이 불안전하다.
@PostMapping("/post02")
public void post02(@RequestBody PostRequestDto requestData){
System.out.println(requestData);
System.out.println(requestData.toString());
}
dto 클래스를 생성하여 받는 것이 안전
@RestController
@RequestMapping("/api")
public class PutApiController {
@PutMapping("/put/{userId}")
public PostRequestDto put(@RequestBody PostRequestDto requestData, @PathVariable(name = "userId") Long id){
System.out.println(requestData);
System.out.println(id);
return requestData;
}
}
Post와 똑같이 request를 받기 위해서는 RequestBody annotation이 필요함.
@RestController
@RequestMapping("/api")
public class DeleteApiController {
@DeleteMapping("/delete/{userId}")
public void delete(@PathVariable(name = "userId") Long id,@RequestParam String account){
System.out.println("id : " + id + " account : " + account);
}
}