Notice
Recent Posts
Recent Comments
Link
«   2024/10   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
Archives
Today
Total
관리 메뉴

JustDoEat

Spring 에서 ResponseEntity와 RestApiResponse로 RESTful API 응답 구조 이해하기 1탄 본문

WishTree/Backend

Spring 에서 ResponseEntity와 RestApiResponse로 RESTful API 응답 구조 이해하기 1탄

kingmusung 2024. 9. 5. 23:57

개요.

헤커톤 프로젝트로 진짜 남들이 보면 비웃을 수도 있는 Spring Boot로 기본적인 CRUD 구현을 했다,

헤커톤이 끝난 후 다른 사람들이 spring boot로 만든 프로젝트를 보면서 이건 왜 이렇게 했지 등을 연구하면서 공부를 하고 있었다!

 

공부를 하면서 이해하기 어려웠던 부분이나, 나의 회로구조로 이해한 경험을 적어보고 싶었다. 비록 미흡할수는 있지만 추후 추가적인 공부가 필요하거나, 비슷한 내용에 관해서 새로운 지식을 얻는다면 이어서 써보고 싶다.

 

컨트롤러에서 프론트엔드로 API응답을 넘겨줄 때

ResponseEntity 객체를 사용해서 넘겨주는 방법에 대해 적어보겠다.

 

RestApiResponse는 사용자가 정의하는 클래스 이므로, 2편에서 이어서 설명하겠다!!


ResponseEntity

 

ResponseEntity

 

HTTP 응답 시 1. 상태코드 2. 헤더 3. 본문( 바디 )을 포함할 수 있는 객체이다.

 

써야 하는 이유는 RESTful API를 구현하기 위해서 사용한다.

    @GetMapping("/{id}")
    public Wish getWish(@PathVariable("id") Long id) {
        Wish wish = wishService.getWish(id);
        return wish;
    }

 

위 코드는 컨트롤러에서 소원의 id를 넣으면 id값과 대응하는 소원을 리턴을 해주는

 

기초적인 CRUD 메서드 중 하나이다!

 

반환값을 보면 소원 객체를 통으로 리턴해준다.

 

PostMan을 사용해서

 

api 요청을 해보면 반환의 형태는 소원 객체인 Wish 객체를 반환해 준다.

 

본문(body)상에 어떠한 상태코드, 상태, 메시지는 보이지 않는다, 반환형을 바꿔보자 Wish(객체) => ResponseEntity <>

 

 

Wish(객체) => ResponseEntity <RestApiResponse>

  	@GetMapping("/{id}")
    public ResponseEntity<RestApiResponse> getWish(@PathVariable("id") Long id) {
        Wish wish = wishService.getWish(id);
        RestApiResponse response = new RestApiResponse(SuccessCode.FIND_WISH, wish);
				return ResponseEntity.status(HttpStatus.OK).body(response);

				
			//return ResponseEntity
            //.status(HttpStatus.OK)
            //.headers(headers)
            //.body(response);
            
            //이게 원형이지만, 헤더부분은 따로 건드릴게 없어서 빼고 한것이다. 필요하면 쓰면 됌
    }

 

차이점을 보면 반환형이 Wish ⇒ ReponseEntity <> 형태로 반환형이 바뀐 것에 주목을 해보자.

 

기존 wish 객체 내부에 있는 정보에 이어서 상태, 상태 코드 메시지가 출력이 되는 것을 볼 수 있다.

 

객체 내부 정보 및 상태, 상태코드, 메시지가 추가로 출력되는 부분은 ResponseEntity 때문에 되는 건 아니니 글을 끝까지 봐보자!

(정확히는 꺽쇠 안에 있는 RestApiResponse 때문에 그러는 거다.)

 

아 참고로 위 사진은 HTTP 응답 본문( 바디 )만 을 보여주고 있다


이어서 ResponseEntity가 무엇이냐,

 

RestAPI의 원칙을 따르기 위해 사용하는 객체이다.

 

RESTful 한 API와 무슨 상관인지는 연관 지어서 정리해 보았다.(접은 글) 

더보기

1. 상태 (State):

무상태성 (Statelessness): 각 요청은 독립적이며, 서버는 클라이언트의 상태를 유지하지 않고, 상태는 클라이언트와 서버 간의 요청/응답 사이에서 정보를 주고받는 방법 중 하나로, 응답 본문에 포함될 수 있다.

 

2. 상태 코드 (Status Code):

HTTP 메서드: HTTP 상태 코드는 요청의 결과를 나타냄. 각 HTTP 메서드(GET, POST, PUT, DELETE 등)에 대한 처리가 성공했는지, 실패했는지 등을 상태 코드로 알려주는데 이 부분은 표현에 매칭된다.

표현 (Representation): 상태 코드는 자원에 대한 요청 결과를 나타내며, 응답의 일부로 클라이언트에게 제공됩니다.

 

3. 메시지 (Message):

 

HTTP 메서드: 요청에 대한 결과를 설명하기 위한 메시지가 포함된다.

예를 들어, 요청이 성공했을 때 “회원 가입 성공”이라는 메시지를 포함할 수 있음.

 

표현 (Representation): 상태 코드와 함께 메시지를 포함시켜 응답의 의미를 더 명확히 전달함.

 

4. 데이터 (Data):

 

자원 (Resource): 응답 본문에 포함된 데이터는 자원의 표현이다.

클라이언트가 요청한 자원에 대한 정보가 이곳에 담겨 있으므로 REST 원칙 중 자원에 해당한다라고 볼 수 있겠다.

 

표현 (Representation): 자원의 데이터가 JSON, XML 등으로 포맷되어 응답 본문에 포함이 된다.

응답 본문을 보면 JSON형식이므로 이 또한 표현에 해당한다고 볼 수 있음.

 

 

응답값에 HTTP 상태, 헤더, 본문을

 

ResponseEntity객체 안에 반환 값을 넣어주게 된다면,

 

반환 요청에

 

응답의 상태를 정의하는 HTTP 상태 코드를 나타내주게 된다.

 

무슨 말인지 아직까진 이해가 되지 않아도 괜찮다

HTTP/1.1 200 OK // HTTP 상태코드 정의 / ResponseEntity가 정의해주는 부분 !!!!!

------------------------------- 1번(상태) ---------------------------------------

Content-Type: application/json // 헤더부분
Content-Length: 123 // 헤더 부분

------------------------------- 2번(헤더) ---------------------------------------

{ // 이 부분은 BODY 부분 요청 본문!
    "code": "M001", // ResponseEntity<RestApiResponse> 에
    "status": "CREATED", // RestApiResponse가 정의해주는 부분!
    "message": "회원가입 성공",
    "data": {
        "wishId": 5,
        "title": "부자 되고 싶다 !!",
        "content": "개처럼 일해서 개미처럼 사용해라!",
        "category": "망상",
        "registrationDate": "2024-09-05T13:12:30.998+00:00",
        "isConfirmed": null 
        }
}
------------------------------- 3번(본문) ---------------------------------------

 

처음에 흐름을 이해하기 위해 PostMan으로 API요청을 한 결괏값을 보여준 사진은

 

응답본문만( 바디 ) 보여줬다면.

 

위 코드는 HTTP응답 시 HTTP 응답의 전체를 보여주는 부분이다.

( 상태코드, 헤더, 본문(바디) )

 

주석을 보면 가장 첫 줄

 

1번이 HTTP의 상태를 나타내주는 부분이고,

 

2번이 HTTP의 헤더를 나타내주는 부분이고,

(현제 게시물에는 헤더를 따로 설정하진 않음, 기본적으로 포함되는 헤더임, 필요하면 내가 조작할 수 있음)

 

3번이 HTTP의 응답본문을 나타내주는 부분이다.

 

 

결론적으로! ResponseEntity는 HTTP응답을 크게 세 부분으로 바라보았을 때, 각각 1,2,3, 번에 대응하는 부분을 편하게 조작하도록 해주는 것이다.

 

3번 본문의 내부 정보, code, status, message, data 등

{"code": "M001",
    "status": "CREATED", 
    "message": "회원가입 성공",
    "data": {...} }

 

ResponseEntity <RestApiResponse>

 

<RestApiResponse> 요놈이 해주는 것이다.

 

ReponseEntity와 RestApiResponse와의 관계는 다음 편에 이어서 하겠다!


정리.

ResponseEntity 객체는 HTTP응답 본문에 크게 세 부분

1. 상태 2. 헤더 3. 본문을 조작해 준다.

return ResponseEntity.status(HttpStatus.OK).headers(headers).body(response);

 

+ 상태는 HttpStatus 객체를 이용해서 집어넣으면 된다!

+ 기본 헤더만 쓰고 있지만 필요하면 넣어서 쓰면 된다

+ body에 response는 RestApiResponse에서 정의해서 쓴다(다음 편)

 


진짜 바뀌나? 실험해 보기

 

return ResponseEntity.status(HttpStatus.OK). body(response); 로 한다면

 

위 코드처럼 첫 줄에 HTTP상태가 “HTTP/1.1 200 OK” 이렇게 나타날 것이다.

 

그러면 나는 궁금한 게 있다, 오케이 그럼 고의로 상태코드를 BAD_REQUEST, 400으로 바꾸면 되나?

 

return ResponseEntity.*status*(HttpStatus.*BAD_REQUEST*). body(response);

 

정상적으로 작동이 된다.

HTTP/1.1 400 BAD_REQUEST // HTTP 상태코드 정의 / ResponseEntity가 정의해주는 부분 !!!!!
Content-Type: application/json // 헤더부분
Content-Length: 123 // 헤더 부분

{ // 이 부분은 BODY 부분 요청 본문!
    "code": "M001", // ResponseEntity<RestApiResponse> 에
    "status": "CREATED", // RestApiResponse가 정의해주는 부분!
    "message": "회원가입 성공",
    "data": {
        "wishId": 5,
        "title": "부자 되고 싶다 !!",
        "content": "개처럼 일해서 개미처럼 사용해라!",
        "category": "망상",
        "registrationDate": "2024-09-05T13:12:30.998+00:00",
        "isConfirmed": null 
        }
}

 

위 코드와 맨 첫 줄 상태 부분만 바뀌고 아래는 동일한 것을 볼 수 있다.