API(Application Programming Interface)는 한 프로그램에서 다른 프로그램으로 데이터를 주고받기 위한 방법을 말한다.
- 웹 애플리케이션을 개발하기 위한 아키텍쳐 스타일 중 하나로 클라이언트와 서버 간의 '통신 방식'을 규정한 것
- 해당 통신 방식은 'HTTP 프로토콜'을 기반으로 하며 자원, 행위, 표현 세 가지 요소로 구성 됨
REST 아키텍쳐 스타일에 따라 구성한 API를 의미
- HTTP를 위한 아키텍쳐 스타일 중 하나로 REST의 원칙을 따르는 웹 서비스를 '구현하는 방식'이며 웹 서비스를 개발하는 방식
- 클라이언트와 서버 간 자원을 주고받을 때 '일괄적인 방식' 을 제공하며 이를 통해 서버와 클라이언트의 역할을 '명확하게 분리'하고 서로 '독립적'으로 개발할 수 있게 된다.
- REST API는 REST 아키텍쳐 스타일을 따르는 API이며 RESTful API는 REST API를 제공하는 웹 서비스를 의미
- 결론적으로는 RESTful API는 REST API의 원칙을 따르기 때문에 REST API보다 조금 더 RESTful 하다고 볼 수 있다.
REST API의 원칙을 따라 구성한 웹 서비스를 의미한다. 자원을 URL로 표현하고 HTTP Method를 이용해 해당 자원에 대해 CRUD 작업을 수행하며 리소스와 행위를 명시적으로 분리하여 사용함으로써 URL만 보고도 어떤 동작을 수행하는지 알 수 있도록 구성한 것을 의미
- 웹 상에 존재하는 데이터나 정보와 같은 모든 것을 의미 ex) 사용자,댓글,이미지 등
- 자원의 이름 구성은 동사가 아닌 '명사' 를 사용하는것이 권장됨
- HTTP Method를 이용한 자원에 대한 행위(조회,생성,수정,삭제)를 의미
| HTTP Method | 행위 | 예시 |
|---|---|---|
| GET | 자원을 조회 | 사용자 정보 조회: GET/users/{user_id} |
| POST | 자원을 생성 | 사용자 정보 생성: POST/users |
| PUT | 자원을 수정 | 사용자 정보 수정: PUT/users/{user_id} |
| PATCH | 자원 일부를 수정 | 사용자 정보 일부 수정 : PATCH/users/{user_id} |
| DELETE | 자원을 삭제 | 사용자 정보 삭제: DELETE/users/{user_id} |
- RESTful에서 클라이언트와 서버 간의 데이터 통신을 주고받는 '데이터 형식(JSON,XML,HTML)' 을 의미
| 분류 | JSON | XML | HTML |
|---|---|---|---|
| 문법 | 가볍고 간결하며 쉽게 읽고 쓸 수 있음 | JSON과 비교해 더 많은 데이터를 필요로하며 상세함 | 데이터 교환을 위한 것이 아니라 웹 페이지 렌더링을 위해 설계됨 |
| 가독성 | 읽고 구문 분석하기 쉽고 복잡한 데이터 구조와 배열을 지원함 | 읽고 구문 분석하기 쉽고 복잡한 데이터 구조와 스키마 유효성 검사를 지원함 | 읽고 구문 분석하기 쉽고 기본 데이터 구조와 링크를 지원함 |
| 유연성 | 쉽게 확장하고 사용자 정의할 수 있으며 대부분의 프로그래밍 언어를 지원함 | 이름 공간과 사용자 정의 태그를 지원하지만 확장하는 데 더 많은 노력이 필요함 | 제한된 유연성으로 복잡한 데이터 교환에는 적합하지 않음 |
| 인기도 | 웹 개발, 모바일 앱 및 API에서 널리 사용됨 | 기업 응용 프로그램 및 레거시 시스템에서 널리 사용됨 | 웹 개발에서 널리 사용됨, 그러나 API에는 권장하지 않음 |
- RESTful API 에서는 HTTP 상태 코드를 사용하여 클라이언트에게 요청의 성공 또는 실패를 알려줌
- 상태코드는 3자리 숫자로 표현되며 각각의 숫자는 특정한 의미를 가지고 있음
| 상태코드 | 상태 정보 | 의미 |
|---|---|---|
| 1xx | Informational | 요청이 수신되었으며 처리가 계속됨을 의미 |
| 2xx | Success | 요청이 성공적으로 처리되었음을 의미 |
| 3xx | Redirection | 요청이 완료되기 위해 추가 작업이 필요함을 의미 |
| 4xx | Client Error | 클라이언트 오류로 인해 요청이 실패함을 의미 |
| 5xx | Server Error | 서버 오류로 인해 요청이 실패함을 의미 |
| 상태코드 | 상태 정보 | 의미 |
|---|---|---|
| 200 | OK | 요청이 성공적으로 처리되었음을 의미, 클라이언트에게 요청한 데이터를 반환함 |
| 201 | Created | 새로운 리소스가 성공적으로 생성되었음을 의미 |
| 204 | No Content | 요청이 성공적으로 처리되었지만, 반환할 데이터가 없음을 의미 |
| 400 | Bad Request | 클라이언트 요청이 잘못되었음을 의미 |
| 401 | Unauthorized | 클라이언트가 인증되지 않았음을 의미 |
| 403 | Forbidden | 클라이언트가 요청한 리소스에 접근할 권한이 없음을 의미 |
| 404 | Not Found | 요청한 리소스를 찾을 수 없음을 의미 |
| 500 | Internal Server Error | 서버에서 오류가 발생하여 요청을 처리할 수 없음을 의미 |
| Annotation | 설명 | 비고 |
|---|---|---|
| @Controller | HTTP 요청을 처리하는 컨트롤러 클래스를 정의하는 어노테이션 | Spring MVC View를 반환하는데 사용됨 |
| @RestController | RESTful 웹 서비스를 위한 컨트롤러 클래스를 정의하는 어노테이션 | RESTful 웹 서비스의 JSON,XML 등의 응답을 반환하는데 사용됨 |
| 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을 사용해야 한다.
| 구분 | GET 방식 | POST 방식 |
|---|---|---|
| 전송 데이터 | URL 끝에 파라미터를 붙여서 서버에 요청을 보내는 방식 | HTTP Body에 담아서 요청을 보내는 방식 |
| 전송 데이터 크기 제한 | 데이터의 양에 제한 있음 | 데이터의 양에 제한 없음 |
| 캐싱 가능 여부 | 가능 | 불가능 |
| 보안 | 데이터 노출 가능성 있음 | 데이터 노출 가능성 낮음 |
| 사용 예시 | 검색어 전송, 페이지 요청 | 로그인,회원가입,게시글 작성 |
💡 캐싱이란?
- 이전에 요청한 데이터를 저장해 두었다가 다음 요청 시에 바로 제공하는 것, 네트워크 대역폭을 절약하고, 서버의 부하를 줄일 수 있다.
@PathVariable : 'URL 경로의 일부'를 매개변수로 전달받는 어노테이션
@GetMapping("/user/{name}")
public String findByName(@PathVariable("name") String name){
return "Name: "+name;
}
http://localhost:8080/user/user1 로 접속시

@RequestParam : 'HTTP 요청 파라미터'를 매개변수로 전달받는 어노테이션
@GetMapping("/user")
public User saveUser(@RequestParam("name") String name, @RequestParam("studentId") Long studentId){
User user = new User();
user.setName(name);
user.setStudentId(studentId);
return user;
}

@RequestBody : HTTP 요청의 '본문(body)'을 매개변수로 전달받는 어노테이션
@PostMapping("/user")
public User saveUser(@RequestBody User user){
// user 객체를 받아서 이름을 변경
user.setName("user2");
return user;
}

ResponseBody : HTTP 응답의 '본문(body)'을 생성하는 메소드에 적용하는 어노테이션
@ResponseBody
@GetMapping("/data")
public User getUser(){
User user = new User();
user.setName("user1");
user.setStudentId(1234L);
return user;
}

💡 RequestBody와 ResponseBody 차이?
RequestBody: HTTP요청의 body 내용을 java 객체로 변환
ResponseBody: java 객체의 내용을 HTTP 응답의 body로 변환
위 예시에는 RequestBody만 써도 응답 body에 객체가 들어오던데요??
@RestController를 사용하는 경우에는 자동으로 return 값에 ResponseBody를 붙여 body에 전달되기 때문에 @ResponseBody 생략이 가능!
ResponseStatus : HTTP 응답의 상태 코드를 지정하는 어노테이션
@ResponseStatus(HttpStatus.NOT_FOUND)
public class UserNotFoundException extends RuntimeException{
public UserNotFoundException(String msg){
super(msg);
}
}
위와 같이 응답을 설정해주고 싶을때 사용한다.
💡 RESTfulAPI 설계 과정
- 자원(Resource)을 정의한다.
- 행위(HTTP Method)를 정의한다.
- 표현(Representation)을 정의한다.
- 상태 코드(Status Code)를 정의한다.
- API 문서화를 정의한다.
| 자원 : 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 |
Spring Framework에서 제공하는 클래스 중 HttpEntity라는 클래스가 존재한다. 이것은 HTTP 요청(Request) 또는 응답(Response)에 해당하는 HttpHeader와 HttpBody를 포함하는 클래스이다.
이러한 HttpEntity 클래스를 상속받아 구현한 클래스가 RequestEntity, ResponseEntity 클래스이다. ResponseEntity는 사용자의 HttpRequest에 대한 응답 데이터를 포함하는 클래스이다. 따라서 HttpStatus,HttpHeaders,HttpBody를 포함한다.
@PostMapping("/user")
public ResponseEntity saveUser(@RequestBody User user){
// user 객체를 받아서 이름을 변경
user.setName("user2");
return new ResponseEntity(HttpStatus.OK);
}
위와 같이 코드를 짜고 POSTMAN으로 요청을 보내면 상태코드가 200으로 오는것을 확인할 수 있다.

또한 상태코드(Status),헤더(Headers),응답데이터(ResponseData)를 담는 생성자도 존재한다.
public class ResponseEntity<T> extends HttpEntity<T> {
public ResponseEntity(@Nullable T body, @Nullable MultiValueMap<String, String> headers, HttpStatus status) {
super(body, headers);
Assert.notNull(status, "HttpStatus must not be null");
this.status = status;
}
}
위의 ResponseEntity를 이용해서 클라이언트에게 응답을 보내는 예제를 정리해보자.
import lombok.Data;
@Data
public class Message {
private StatusEnum status;
private String message;
private Object data;
public Message() {
this.status = StatusEnum.BAD_REQUEST;
this.data = null;
this.message = null;
}
}
Message라는 클래스를 만들어 상태코드, 메시지, 데이터를 담을 필드를 추가한다.
public enum StatusEnum {
OK(200, "OK"),
BAD_REQUEST(400, "BAD_REQUEST"),
NOT_FOUND(404, "NOT_FOUND"),
INTERNAL_SERER_ERROR(500, "INTERNAL_SERVER_ERROR");
int statusCode;
String code;
StatusEnum(int statusCode, String code) {
this.statusCode = statusCode;
this.code = code;
}
}
상태코드로 보낼 몇가지의 예시 enum
@PostMapping("/user")
public ResponseEntity<Message> saveUser(@RequestBody User user){
// user 객체를 받아서 이름을 변경
user.setName("user2");
Message message = new Message();
HttpHeaders headers= new HttpHeaders();
headers.setContentType(new MediaType("application", "json", StandardCharsets.UTF_8));
message.setStatus(StatusEnum.OK);
message.setMessage("성공 코드");
message.setData(user);
return new ResponseEntity<>(message, headers, HttpStatus.OK);
}
이전의 코드에서 Message 클래스를 통해 StatusCode, ResponseMessage, ResponseData를 담아서 클라이언트에게 응답을 보내는 코드이다.
