반응형
해당 글에서는 Restful API의 제약 조건과 설계 방법에 대해 이해한 것을 바탕으로 실제 RESTful API를 구성하는 목적으로 작성하였습니다.
💡 [참고] 이전에 작성한 Restful API 설계방법의 이론의 글에서 이어지는 내용입니다.
1) 테스트 개발 환경
💡 해당 개발 환경에서는 'Spring Boot Starter Web' 라이브러리를 통해서 Restful API를 구현합니다.
개발환경 | 버전 |
java | 11 |
Spring Boot | 2.7.5 |
Spring Framework | 5.7.4 |
Spring Boot Starter Web | 2.7.5 |
SpringFox Swagger2 | 1.6.11 |
Gradle | 7.5 |
개발툴 : IntelliJ | IntelliJ IDEA 2022.3 |
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springdoc:springdoc-openapi-ui:1.6.11' // Swagger springdoc-ui
}
[참고] API 설계 과정을 정의한 글입니다
2) RESTful API Annotaion
💡 구성하기 이전에 RESTful API에서 주요 Annotation에 대해서 이해합니다.
1. 설정 관련 Annotation
💡 Spring Boot 내에서 설정과 관련된 Annotation 입니다.
Annotation | 설명 | 비고 |
@SpringBootApplication | - 스프링 부트 애플리케이션의 시작점을 나타내는 어노테이션입니다. | |
@Controller | - HTTP 요청을 처리하는 컨트롤러 클래스를 정의하는 어노테이션입니다. | Spring MVC 뷰를 반환하는데 사용됩니다. |
@RestController | - RESTful 웹 서비스를 위한 컨트롤러를 정의하는 어노테이션입니다. | RESTful 웹 서비스의 JSON, XML 등의 응답을 반환하는 데 사용됩니다. |
[ 더 알아보기 ]
💡 @Controller과 @RestController의 차이는 무엇일까?
- @Controller는 일반적으로 HTTP 요청을 처리하고 '뷰'를 반환하는 데 사용이 됩니다.
- @RestController는 HTTP 요청에 대한 RESTful 웹 서비스의 JSON, XML 등의 응답을 반환하는 데 사용이 됩니다.
2. RESTful API의 행위(Verb) Annotation
💡 행위(Verb) 란?
- Restful API의 행위는 HTTP Method를 이용한 자원에 대한 행위(조회, 생성, 수정, 삭제)를 의미합니다.
Annotation | HTTP | Method 역할 | 비고(예시) |
@GetMapping | GET | 클라이언트가 리소스를 조회할 때 사용 | @GetMapping(value="/users") |
@PostMapping | POST | 클라이언트가 리소스를 생성할 때 사용 | @PostMapping(value="/users") |
@PutMapping | PUT | 클라이언트가 리소스를 갱신할 때 사용 | @PutMapping(value="/users") |
@PatchMapping | PATCH | 클라이언트가 리소스 일부를 갱신할 때 사용 | @PatchMapping(value="/users") |
@DeleteMapping | DELETE | 클라이언트가 리소스를 삭제할 때 사용 | @DeleteMapping(value="/users") |
@RequestMapping | ALL | 요청 메서드(GET, POST, PUT, DELETE 등)와 URL 매핑을 함께 지정할 수 있다. | @RequestMapping(value="/users", method=RequestMethod.GET) |
[ 더 알아보기 ]
💡 @RequestMapping과 @XXMapping 중 무엇을 사용해야 할까?
- 간단한 HTTP 요청에 대해서는 @XXMapping을 사용하는 것이 코드 가독성과 유지보수성을 높일 수 있습니다. 하지만 여러 개의 HTTP 요청 메서드에 대해 하나의 메서드로 처리해야 하는 경우는 @RequestMapping을 사용해야 합니다.
3. RESTful API의 표현(Representation) Annotation
💡 표현(Representation) 이란?
- RESTful에서 클라이언트와 서버 간의 데이터 통신을 위해 주고받는 데이터 형식(JSON, XML, HTML)을 의미합니다.
1. JSON 데이터 형식의 전송 방식
💡 클라이언트에서 API로 데이터를 전송 방식으로는 ‘GET 방식’과 ‘POST 방식’을 이용하는 전송 방식이 있습니다.
구분 | GET 방식 | POST 방식 |
전송 데이터 | URL 끝에 파라미터를 붙여서 서버에 요청을 보내는 방식 | HTTP Body에 담아서 서버에 요청을 보내는 방식 |
전송 데이터 크기 제한 | 데이터의 양에 제한 있음 | 데이터의 양에 제한 없음 |
캐싱 가능 여부 | 가능 | 불가능 |
보안 | 데이터 노출 가능성 있음 | 데이터 노출 가능성 낮음 |
사용 예시 | 검색어 전송, 페이지 요청 | 로그인, 회원가입, 게시글 작성 |
[ 더 알아보기 ]
💡 캐싱이란?
- 이전에 요청한 데이터를 저장해 두었다가 다음 요청 시에 바로 제공하는 것을 말합니다. 이를 통해 네트워크 대역폭을 절약하고, 서버의 부하를 줄일 수 있습니다.
2. 데이터 형식 주요 어노테이션
Annotation | 설명 | 예시 |
@PathVariable | ‘URL 경로의 일부’를 매개변수로 전달받는 어노테이션 | @GetMapping("/users/{id}") public ResponseEntity getUserById(@PathVariable Long id) {} |
@RequestParam | ‘HTTP 요청 파라미터’를 매개변수로 전달받는 어노테이션 | @GetMapping("/users") public ResponseEntity<list> getAllUsers(@RequestParam("age") int age) {}</list |
@RequestBody | HTTP 요청의 ‘본문(body)’을 매개변수로 전달받는 어노테이션 | @PostMapping("/user") public ResponseEntity createUser(@RequestBody User user) { } |
@ResponseBody | HTTP 응답의 본문(body)을 생성하는 메소드에 적용하는 어노테이션 | @GetMapping("/data") public @ResponseBody Map<string, object=""> getData() { }</string,> |
@ResponseStatus | HTTP 응답의 상태 코드를 지정하는 어노테이션 | @GetMapping("/users/{id}") @ResponseStatus(HttpStatus.NOT_FOUND) public void getUserById(@PathVariable Long id) { } |
3) RESTful API 구성하기
💡 이전에 이해한 RESTful API의 주요한 Annotation을 기반으로 실제 RESTful API를 구성합니다.
💡 RESTful API를 설계 과정
1. 자원(Resource)을 정의합니다.
2. 행위(HTTP Method)를 정의합니다.
3. 표현(Representation)을 정의를 합니다.
4. 상태 코드(Status Code)를 정의를 합니다.
5. API 문서화를 정의합니다.
0. 사전 환경 구성
💡 RESTful API를 구성하기 위한 기본 사전 환경을 구성합니다
💡 TestController.java 파일을 생성하고 @RestController로 RESTful API를 사용하는 Controller로 구성하였습니다.
package com.adjh.multiflexapi.controller;
import org.springframework.web.bind.annotation.RestController;
/**
* Please explain the class!!
*
* @author : lee
* @fileName : TestController
* @since : 2023/03/25
*/
@RestController
public class TestController {
//
}
1. 자원(Resource)을 정의합니다.
💡 사전 환경에서 정의한 사용자 조회, 등록, 수정, 삭제에 대한 RESTful API에 대해서 자원을 ‘user’라고 정의를 하였습니다.
자원 : Endpoint | 설명 | 구성 예시 |
user | 사용자를 조회하는 API입니다. | /user/{userId} |
user | 사용자를 등록하는 API입니다. | /user |
user | 사용자를 수정하는 API입니다 | /user |
user | 사용자를 삭제하는 API입니다 | /user |
2. 행위(HTTP Method)를 정의합니다.
💡 이전에 단계 ‘자원’에서 정의한 ‘user’에 대해서 각각 사용처에 따라 행위(GET, POST, PUT, DELETE)를 지정합니다.
자원 : Endpoint | 행위 : HTTP Method | 설명 | 구성 예시 |
user | GET | 사용자를 조회하는 API입니다. | GET /user/{userId} |
user | POST | 사용자를 등록하는 API입니다. | POST /user |
user | PUT | 사용자를 수정하는 API입니다 | PUT /user |
user | DELETE | 사용자를 삭제하는 API입니다 | DELETE /user |
3. 표현(Representation)을 정의합니다.
💡 이전에 단계 행위에서 정의한 ‘행위’에 대해서 클라이언트에서 서버로 전송하는 전송 방식(GET, POST)과 전송 데이터 형식(JSON, XML, HTML 등)을 지정합니다.
자원 : Endpoint | 행위 : HTTP Method | 표현 : 데이터 전송 방식 | 설명 | 구성 예시 |
user | GET | - GET 전송방식 - parameter or URL 경로 |
사용자를 조회하는 API입니다. | GET /user/{userId} |
user | POST | - POST 전송방식 - JSON 데이터 전송 |
사용자를 등록하는 API입니다. | POST /user |
user | PUT | - POST 전송방식 - JSON 데이터 전송 |
사용자를 수정하는 API입니다 | PUT /user |
user | DELETE | - POST 전송방식 - JSON 데이터 전송 |
사용자를 삭제하는 API입니다 | DELETE /user |
// @RequestParam를 이용한 파라미터 바인딩
@RequestMapping(value = "/user")
public String example(@RequestParam("userId") String userId) {
// 메소드 구현
}
// @PathVariable를 이용한 URL 경로 바인딩
@RequestMapping(value = "/user/{userId}")
public String example(@PathVariable("id") String userId) {
// 메소드 구현
}
[ 더 알아보기 ]
💡 @RequestParam와 @PathVariable의 차이점
- @RequestParam 어노테이션은 HTTP 요청 '파라미터'를 메소드의 매개변수와 바인딩합니다.
- @PathVariable 어노테이션은 'URL 경로 변수'를 메소드 매개변수와 바인딩합니다.
4. 상태 코드(Status Code)를 정의합니다
💡 이전 단계에서 정의한 ‘전송 방식’과 ‘전송 데이터 형식’을 기반으로 클라이언트의 데이터 전송이 완료/실패 처리 되었을 때 서버에서 클라이언트로 전달하는 ‘상태 코드’를 정의합니다.
[참고] 상태코드의 종류
상태코드 | 상태 정보 | 의미 |
200 | OK | 요청이 성공적으로 처리되었음을 의미합니다. 클라이언트에게 요청한 데이터를 반환합니다. |
201 | Created | 새로운 리소스가 성공적으로 생성되었음을 의미합니다. |
204 | No Content | 요청이 성공적으로 처리되었지만, 반환할 데이터가 없음을 의미합니다. |
400 | Bad Request | 클라이언트 요청이 잘못되었음을 의미합니다. 요청이 잘못된 경우에는 이 상태코드를 반환합니다. |
401 | Unauthorized | 클라이언트가 인증되지 않았음을 의미합니다. |
403 | Forbidden | 클라이언트가 요청한 리소스에 접근할 권한이 없음을 의미합니다. |
404 | Not Found | 요청한 리소스를 찾을 수 없음을 의미합니다. |
500 | Internal Server Error | 서버에서 오류가 발생하여 요청을 처리할 수 없음을 의미합니다. |
자원 : Endpoint | 행위 : HTTP Method | 표현 : 데이터 전송 방식 | 상태 코드 | 설명 | 구성 예시 |
user | GET | GET 전송방식, parameter or URL 경로 | 성공 시 HttpStatus.OK 반환 | 사용자를 조회하는 API입니다. | GET /user/{userId} |
user | POST | POST 전송방식, JSON 데이터 전송 | 성공 시 HttpStatus.OK 반환 | 사용자를 등록하는 API입니다. | POST /user |
user | PUT | POST 전송방식, JSON 데이터 전송 | 성공 시 HttpStatus.OK 반환 | 사용자를 수정하는 API입니다 | PUT /user |
user | DELETE | POST 전송방식, JSON 데이터 전송 | 성공 시 HttpStatus.OK 반환 | 사용자를 삭제하는 API입니다 | DELETE /user |
/**
* RESTful API의 GET을 이용한 방식
*
* @return
*/
@GetMapping("/user")
public ResponseEntity<ApiResponse<Object>> restfulGet(@RequestParam String userId) {
String result = "";
log.debug("userId :: " + userId);
ApiResponse ar = ApiResponse.builder()
.result(result)
.resultCode(SuccessCode.SELECT.getStatus())
.resultMsg(SuccessCode.SELECT.getMessage())
.build();
return new ResponseEntity<>(ar, HttpStatus.OK);
}
💡[참고] ApiResponse에 대해서 궁금하시다면 이전에 작성한 글을 참고하시면 됩니다.
[ 더 알아보기 ]
💡ResponseEntity 란?
- RESTful API를 개발할 때, HTTP Response 메시지를 감싸는 클래스입니다. ResponseEntity는 HTTP 상태 코드, 응답 헤더, 응답 본문 데이터 등을 포함할 수 있습니다.
5. API 문서화를 정의합니다.
💡 이전 단계에서 정의한 최종 ‘상태 코드’를 기반으로 API 문서화는 SpringFox Swagger2를 이용하여서 문서화를 진행합니다.
[참고] SpringFox Swagger2에 대한 어노테이션
Annotation | 설명 |
@Tag | - Swagger UI에서 API를 그룹화할 수 있습니다. |
@Operation | - 어노테이션을 사용하면 Swagger UI에서 API 작업에 대한 정보를 제공할 수 있습니다. - summary 속성은 API 작업의 간략한 설명을, description 속성은 API 작업의 상세한 설명을 작성합니다. |
💡 해당 글에서는 Restful이라는 @Tag 어노테이션을 통해서 API를 그룹화하였으며 @Operation 어노테이션을 통해서 API 각각에 대한 정의를 하였습니다.
@RestController
@RequestMapping(value = "/api/v1/rest")
@Tag(name = "Restful", description = "restful API 구성")
public class RestfulController {
/**
* RESTful API의 GET을 이용한 방식
*
* @return
*/
@GetMapping("/user")
@Operation(summary = "사용자 조회", description = "사용자 아이디를 기반으로 사용자 정보를 조회합니다.")
public ResponseEntity<ApiResponse<Object>> restfulGet(@RequestParam String userId) {
String result = "";
log.debug("userId :: " + userId);
ApiResponse ar = ApiResponse.builder()
.result(result)
.resultCode(SuccessCode.SELECT.getStatus())
.resultMsg(SuccessCode.SELECT.getMessage())
.build();
return new ResponseEntity<>(ar, HttpStatus.OK);
}
}
[참고] 이전에 작성한 Swagger를 이용한 API 문서화 환경을 구성하는 방법입니다.
4) RESTful API 결과 확인하기
package com.adjh.multiflexapi.controller;
import com.adjh.multiflexapi.common.codes.SuccessCode;
import com.adjh.multiflexapi.common.response.ApiResponse;
import com.adjh.multiflexapi.model.UserDto;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
/**
* RESTful API를 구성하는 Controller입니다.
*
* @author : lee
* @fileName : RestfulController
* @since : 2023/03/25
*/
@Slf4j
@RestController
@RequestMapping(value = "/api/v1/rest")
@Tag(name = "Restful", description = "restful API 구성")
public class RestfulController {
/**
* RESTful API의 GET을 이용한 방식
*
* @return
*/
@GetMapping("/user")
@Operation(summary = "사용자 조회", description = "사용자 아이디를 기반으로 사용자 정보를 조회합니다.")
public ResponseEntity<ApiResponse<Object>> restfulGet(@RequestParam String userId) {
String result = "";
log.debug("userId :: " + userId);
ApiResponse ar = ApiResponse.builder()
.result(result)
.resultCode(SuccessCode.SELECT.getStatus())
.resultMsg(SuccessCode.SELECT.getMessage())
.build();
return new ResponseEntity<>(ar, HttpStatus.OK);
}
/**
* RESTful API의 POST 이용한 방식
*
* @return
*/
@PostMapping("/user")
@Operation(summary = "사용자 추가", description = "사용자 정보를 기반으로 사용자를 추가합니다.")
public ResponseEntity<ApiResponse<Object>> restfulPost(@RequestBody UserDto userDto) {
String result = "";
log.debug("userDto :: " + userDto.toString());
ApiResponse ar = ApiResponse.builder()
.result(result)
.resultCode(SuccessCode.SELECT.getStatus())
.resultMsg(SuccessCode.SELECT.getMessage())
.build();
return new ResponseEntity<>(ar, HttpStatus.OK);
}
/**
* RESTful API의 PUT 이용한 방식
*
* @return
*/
@PutMapping("/user")
@Operation(summary = "사용자 수정", description = "전달 받은 사용자 아이디를 기반으로 변경된 사용자 수정 정보를 변경합니다.")
public ResponseEntity<ApiResponse<Object>> restfulPut(@RequestBody UserDto userDto) {
String result = "";
log.debug("userDto :: " + userDto.toString());
ApiResponse ar = ApiResponse.builder()
.result(result)
.resultCode(SuccessCode.SELECT.getStatus())
.resultMsg(SuccessCode.SELECT.getMessage())
.build();
return new ResponseEntity<>(ar, HttpStatus.OK);
}
/**
* RESTful API의 DELETE 이용한 방식
*
* @return
*/
@DeleteMapping("/user")
@Operation(summary = "사용자 삭제", description = "전달 받은 사용자 아이디를 기반으로 사용자를 삭제합니다.")
public ResponseEntity<ApiResponse<Object>> restfulDelete(@RequestBody UserDto userDto) {
String result = "";
log.debug("userDto :: " + userDto.toString());
ApiResponse ar = ApiResponse.builder()
.result(result)
.resultCode(SuccessCode.SELECT.getStatus())
.resultMsg(SuccessCode.SELECT.getMessage())
.build();
return new ResponseEntity<>(ar, HttpStatus.OK);
}
}
💡 Swagger를 이용한 Controller에서 지정한 RESTful 형태의 API 문서 확인
오늘도 감사합니다. 😀
반응형
'Java > 아키텍처 & 디자인 패턴' 카테고리의 다른 글
[Java] 스레드(Thread) 이해하기 -1 : 구조, 상태, 예시 (0) | 2023.04.17 |
---|---|
[Java/Library] Lombok 이해하고 적용하기 -2 : 심화 및 적용 (0) | 2023.03.27 |
[Java] RESTful API 설계 방법 -1 : 이해하기 (0) | 2023.03.22 |
[Java] 계층화된 아키텍처(Layered Architecture) : N Tier Architecture (0) | 2023.01.25 |
[Java] 프로그래밍 패러다임 이해하기 (0) | 2023.01.07 |