본문 바로가기
공부

[REST] API 요청, 응답

by 꾸돼지 2025. 6. 12.
320x100

클라이언트에게 받은 요청을 수신해서, 검증하고, 작업을 수행하고, 응답하는 일련의 메커니즘을 API라고 한다.

 

나는 다음의 문서를 참고했다.

https://spec.openapis.org/oas/v3.1.0

 

OpenAPI Specification v3.1.0

Each Media Type Object provides schema and examples for the media type identified by its key. It is common to use multipart/form-data as a Content-Type when transferring request bodies to operations. In contrast to 2.0, a schema is REQUIRED to define the i

spec.openapis.org

 

RFC7231 스펙 문서

https://datatracker.ietf.org/doc/html/rfc7231#section-4.3.1

 

RFC 7231: Hypertext Transfer Protocol (HTTP/1.1): Semantics and Content

The Hypertext Transfer Protocol (HTTP) is a stateless \%application- level protocol for distributed, collaborative, hypertext information systems. This document defines the semantics of HTTP/1.1 messages, as expressed by request methods, request header fie

datatracker.ietf.org

 

 

아래의 내용은 구글에서 제공하는 API  설계 가이드

https://cloud.google.com/apis/design?hl=ko

 

API 디자인 가이드  |  Cloud API Design Guide  |  Google Cloud

Google AIP와 일치하는 API를 설계하기 위한 가이드라인 모음입니다.

cloud.google.com

 


1. 리소스 이름

대부분의 API는 사용자가 생성, 검색, 및 조작할 수 있는 리소스(주요 명사)를 노출한다.

 - 여기서 리소스는 RDB 기준으로 테이블과 유사하다. 다만 파일이나 다른 요청일 수도 있으니 장담할 수는 없다.

API에서 정의한 모든 리소스 이름은 해당 API 내에서 고유해야 한다.

 - 동일한 API 요청 주소는 리소스의 변경이 없는 한 동일한 값을 제공해야 한다.

리소스의 이름은 컬렉션(사용자, 이벤트)과 식별자(회원번호, 이벤트번호) 등이 번갈아가며 등장한다.

users/goo/userEvents/birthday-dinner-226

참조되는 하위 요소에선 상위 요소의 이름을 제거해서  사용한다.

users/goo/events/birthday-dinner-226

 

 

2. 표준 메서드 

RFC 7231 스펙의 4.3절부터 메서드 정의가 존재한다.

주로 아래의 5가지를 많이 쓰는 것 같다.

 

4.3.1 GET

 -  대상 자원을 서버에 제공 요청

4.3.3 POST

 - 리소스의 의미에 따라 리소스를 처리

 - 주로 리소스의 생성에 많이 사용했었다.

 - 보안과 관련된 이슈로 로그인 등에도 사용한다.

4.3.4 PUT

 - 대상 리소스의 상태가 요청의 요구대로 변화하거나 생성

4.3.5 DELETE

 - 요청한 리소스에 대해 서버에 삭제를 요청

4.3.7 OPTIONS

 - 서버 또는 중개자에서 대상 리소스에 사용 가능한 통신 옵션에 대한 정보 요청, 서버의 기능 테스트

 

3. 응답 코드

https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml

 

Hypertext Transfer Protocol (HTTP) Status Code Registry

 

www.iana.org

 

대표적인 응답 코드는 다음과 같다.

2xx: 성공

200: OK

201: Created

202: Accepted

204: NoContent

 

304: Not Modified

 

4xx: 요청 문제

400: Bad Request

401: Unauthorized

403: Forbidden

404: Not Found

 

5xx: 서버 문제

500: Internal Server Error

 


    @GetMapping("/push-message/{message}")
    public ResponseEntity<String> pushMessage(@PathVariable(name = "message") String message) {
        log.info("{}", message);
        notificationService.sendNotification(1L, message, "push-message");
        return ResponseEntity.ok(message);
    }

 

Spring-Web은 위와 같은 어노테이션으로 REST Method를 제공한다.

@GetMapping, @PostMapping, @PutMapping, @DeleteMapping ...

 

위의 리소스 설계는 이상하긴한데, 위와 같이 사용된다.

응답은 ResponseEntity를 통해 제공할 수 있다.

위의 코드와 내용에 따라 .ok 대신 위의 영어 단어를 입력해서 사용한다.

    @GetMapping("/{id}")
    public ResponseEntity<UserDto> getUserById(@PathVariable Long id) {
        UserDto user = // ... 사용자 조회 로직 ...
        if (user != null) {
            return ResponseEntity.ok(user); // 200 OK
        } else {
            return ResponseEntity.notFound().build(); // .notFound().build()는 404(Not Found) 응답을 생성합니다.
        }
    }

 

Axios를 사용하는 FE에서는 2xx응답이 아닌 경우 Error를 통해 수신할 수 있다.

위의 명세를 잘 이해하는 개발자끼리라면 서로 응답코드만 보고도 어떤 문제가 있는지 확인할 수 있다.

function handleApiError(error) {
    if (error.response) {
        // 서버가 상태 코드를 포함한 응답을 반환한 경우
        const status = error.response.status;
        const data = error.response.data; // 서버가 보낸 에러 메시지

        switch (status) {
            case 400: // Bad Request
                alert(`잘못된 요청입니다: ${data.message || '입력값을 확인해주세요.'}`);
                break;
            case 401: // Unauthorized
                alert('로그인이 필요합니다.');
                // (예: 로그인 페이지로 리다이렉트)
                window.location.href = '/login';
                break;
            case 403: // Forbidden
                alert('접근 권한이 없습니다.');
                break;
            case 404: // Not Found
                alert('요청한 리소스를 찾을 수 없습니다.');
                // (예: "사용자를 찾을 수 없습니다"와 같은 UI 메시지 표시)
                break;
            case 500: // Internal Server Error
            default:
                alert('서버에 문제가 발생했습니다. 잠시 후 다시 시도해주세요.');
                break;
        }
    } else if (error.request) {
        // 요청은 이루어졌으나 응답을 받지 못한 경우 (네트워크 에러 등)
        alert('서버에 연결할 수 없습니다. 네트워크 상태를 확인해주세요.');
    } else {
        // 요청을 설정하는 중에 에러가 발생한 경우
        console.error('Error:', error.message);
        alert('요청 중 에러가 발생했습니다.');
    }
}

 

난 풀스택 개발을 했다보니까 응답코드까지 세세하게 신경쓰진 않았었다.

커스텀 메시지를 통해 FE에서는 바로 알림을 보여주는 방식을 선호하고...

 

앞으론 이런 표준 명세를 지켜가며 코딩하는 습관을 들여야겠다.

320x100