들어가며
개발을 하다 보면 Restful한 설계, Rest API, REST 원칙을 준수하는 ... 등등의 용어들을 한번쯤은 들어본 적이 있을거라고 생각한다. 이번 SOPT에서 키워드 과제로 Restful한 API가 무엇이라고 생각하는지에 대한 내용이 있었어서, 이번 포스팅에서는 해당 내용들을 다루어보려고 한다
본문
REST API의 의미
먼저 REST의 개념을 먼저 알아보자면, Representational State Transfer의 줄임말로 HTTP를 기반으로 클라이언트가 서버의 리소스에 접근하는 방식을 규정한 아키텍쳐를 의미한다.
REST를 준수하는 API를 REST API라고 하며, 개인적으로 생각했을때의 Restful한 설계의 의미는 REST의 기본 원칙을 성실히 지킨 서비스 디자인을 Restful하다고 한다고 생각한다. RESTful API의 설계 원칙을 준수하여 각 리소스에 대해 일관된 메소드를 사용하면 API를 이해하기 쉽고 유지보수 측면에서도 강점이 있기에, 해당 부분들을 깊게 고민하면서 코드를 설계하면 좋을거같다는 생각이 들었다
6가지 REST 설계원칙
결론적으로 개발자는 거의 모든 프로그래밍 언어를 사용하여 REST API를 개발할 수 있으며 다양한 데이터 형식을 지원하지만, 공통적인 요구 사항은 아키텍처 제약 조건이라고도 하는 다음 6가지 REST 설계 원칙을 준수해야 한다. 아래 6가지 원칙은 공식적인 문서에 나와있는 내용으로 이론적인 내용이라서, 해당 부분은 가볍게 보고 아래에서 다룰 예시 부분을 자세히 봐주면 좋을거같다
1. 균일한 인터페이스
동일한 리소스에 대한 모든 API 요청은 요청의 출처에 관계없이 동일하게 표시되어야 한다. REST API는 사용자의 이름 또는 이메일 주소와 같은 동일한 데이터가 하나의 통합 리소스 식별자(URI)에만 속하도록 해야 합니다. 리소스가 너무 커서는 안 되며 클라이언트가 필요로 할 수 있는 모든 정보를 포함해야 합니다.
2. 클라이언트-서버 분리
REST API 설계에서 클라이언트 및 서버 애플리케이션은 서로 완전히 독립적이어야 한다. 클라이언트 애플리케이션이 알아야 하는 유일한 정보는 요청된 리소스의 URI이고, 서버 애플리케이션과 다른 방법으로 통신할 수 없기때문에 서버 애플리케이션에서도 동일하게 HTTP를 통해 요청된 데이터에 클라이언트 애플리케이션을 전달하는 것 외에는 클라이언트 애플리케이션을 수정해서는 안된다
3. 무상태
REST API는 무상태성이기 때문에 각 요청에는 처리에 필요한 모든 정보가 포함되어야 한다. 다시 말해서 REST API에는 서버 측 세션이 필요하지 않다는 뜻이다. 서버 애플리케이션은 클라이언트 요청과 관련된 데이터를 저장할 수 없다는 내용이다
4. 캐시 가능성
가능한 경우 클라이언트나 서버 측에서 리소스를 캐시할 수 있어야 한다. 서버 응답에는 전달된 리소스에 대해 캐싱이 허용되는지 여부에 대한 정보도 포함되어야 하며, 그 목표는 클라이언트 측의 성능과 서버 측의 확장성 향상이다
5. 계층화된 시스템 아키텍처
REST API에서는 호출과 응답이 서로 다른 계층을 거친다. 일반적으로 클라이언트와 서버 애플리케이션이 서로 직접 연결된다고 가정하지 않고, 통신 루프에는 다양한 중개자가 있을 수 있다. REST API는 클라이언트나 서버가 최종 애플리케이션과 통신하는지 중개자와 통신하는지 알 수 없도록 설계해야 한다
6. 코드 온디맨드(선택 사항)
REST API는 일반적으로 정적 리소스를 전송하지만 경우에 따라 응답에 실행 코드(예: Java 애플릿)가 포함될 수도 있다. 이러한 경우 코드는 온디맨드 방식으로만 실행되어야 한다
REST API의 요소
REST API의 요소는 아래처럼 크게 총 세가지로 나누어지는데,
1. 자원(URI)
2. 행위(HTTP요청 메서드)
3. 표현(페이로드)
아래에서 실제 예시들을 보면서 Restful한 설계가 무엇일지 같이 고민해보는게 좋을거같다
RESTful URL Rules
http://api.test.com/users/
위 코드와 아래 코드를 비교해서 둘중에서, 상대적으로 더 RESTful한 설계는 어떤 URL 일까 ?
http://api.test.com/users
REST 원칙에 따르면, " 마지막에 / 포함하지 않는다 " 라는 내용이 있기에 두번째 코드가 더 RESTful한 설계이다
다음 내용으론 underbar와 dash 관련이다. 해당 내용도 두 코드 내용을 비교해봤을때 어떤 내용이 더 RESTful한 설계일까 ?
http://api.test.com/users/post_Commnets
http://api.test.com/users/post-commnets
둘중에서는 아래 코드가 더 RESTful한 설계가 될 수 있다. 내가 알고있는 바에 의하면 -(dash)의 사용도 최소한으로 설계한다는 원칙이 있지만, 정확한 의미나 표현을 위해 단어의 결합이 불가피한 경우 _(underbar) 대신에 -(dash) 를 사용하는 것이 좋다
다음은 아래의 두 코드를 비교해보자
http://api.test.com/users/post-commnets
http://api.test.com/users/postCommnets
카멜케이스는 주로 변수나 함수의 이름을 지을때 많이 사용되므로 URL에서도 권장된다고 생각할 수 있지만,
" 소문자를 사용한다 " 는 원칙에 따라야하므로 첫번째 코드의 URL이 더 RESTful한 설계이다
POST http://api.test.com/users/1/delete-post/1
마지막으로 위 코드와 아래 코드를 비교했을때, " 행위(method)는 URL에 포함하지 않는다 " 라는 원칙에 따라서 아래 내용으로 명사에 s를 붙인 형태가 더 좋은 URL 설계 방식이다
DELETE http://api.test.com/users/1/posts/1
단, 예외 케이스도 있을 수도 있는데 아래 형식처럼, 컨트롤 자원을 의미하는 URL 예외적으로 동사를 허용한다
http://api.test.com/posts/duplicate
RESTful HTTP methods
다음으로는 Restful HTTP 메소드에 대한 내용이다. HTTP methods를 설정할때는 아래의 원칙을 따른다고 생각해주면 될거같다
1. POST, GET, PUT, DELETE 4가지 methods는 반드시 제공한다.
기본적인 CRUD(Create, Read, Update, Delete)를 구성하는 HTTP Method 들이다.
각각의 목적이 명확해서 API를 설계할 때도 아래 4가지를 기준으로 생각하면 좋다.
• POST는 데이터를 새로 생성할 때
• GET은 데이터를 조회할 때
• PUT은 데이터를 전체 수정할 때
• DELETE는 데이터를 삭제할 때
그래서 API 명세를 설계할 때는 이 네 가지는 항상 기본으로 제공한다고 생각하는 게 좋다.
2. 자원의 일부를 수정할 때는 PATCH가 목적에 맞는 method이므로, PUT 대신 PATCH method를 사용한다.
PUT은 전체 자원을 수정하는 방식이라면, PATCH는 일부만 바꾸는 데 적합하다
예를 들어 사용자의 닉네임만 바꾸는 경우, 전체 user 정보를 수정할 필요 없이 PATCH를 사용하는 게 더 자연스럽다
그래서 부분 업데이트가 필요한 경우엔 PUT보다 PATCH가 목적에 더 잘 맞는다
3. GET, PUT 등의 요청은 idempotent 하지만, PUT을 POST처럼 쓰는 경우엔 idempotent하지 않을 수 있다.
예를 들어 GET /users/1의 경우 언제나 같은 결과로 응답한다.
idempotent 란 ?
반환되는 응답 리소스의 결과가 항상 동일하지않다는 뜻으로, 예를들어 f(f(x))=f(x)) 하지 않다
4. GET 메서드와 쿼리 파라미터로 상태를 변경하면 안된다.
GET은 “조회” 용도로만 사용해야 한다. 다시 말해서 서버의 상태나 데이터를 변경하는 작업은 절대로 GET 메서드로 수행하면 안 된다
아래 예시들은 비정상적인 설계이며, 상태 변경이 필요한 경우에는 POST, PUT, DELETE, PATCH 중 적절한 메서드를 사용해야 한다
GET /users/delete?id=1
GET /posts/1/like
HTTP 메소드를 사용한 서버 - 클라이언트 간 통신에서의 역할 부분은, 다음 포스팅에서 좀 더 자세히 다뤘으니 추가적으로 참고해주면 좋을거같다
https://huncozyboy.tistory.com/33
HTTP 통신에서 클라이언트와 서버의 역할 (Spring)
들어가며먼저 HTTP 통신에서 클라이언트와 서버와의 역할에 대해서 얘기하기 전에HTTP methods의 종류와 Rest API 원칙과 관련해서는 바로 이전 포스팅에서 다뤘어서, 아래 링크에 게시물에 Restful HTTP
huncozyboy.tistory.com
RESTful Payload
앞에서 URI와 HTTP 메서드를 통해 ‘무엇을’, ‘어떻게’ 요청하는지를 설계했다면, 이제는 요청/응답의 본문에 담기는 실제 데이터인 Payload에 대해서도 고민해봐야 한다
RESTful한 설계에서의 페이로드는 단순히 데이터를 담는 그릇이 아니라, 자원을 표현하는 중요한 수단이 된다고 생각하면 된다
1. REST에서는 대부분 JSON 형식을 기본으로 사용한다
간결하고, 구조화되어 있으며, 프론트엔드와의 호환성도 좋기 때문이다
또한 XML보다 가볍고 읽기 쉬워서, 2018년 이후부터 요즘까지 거의 모든 API가 JSON 기반으로 설계되고 있다
JSON 응답 형식 예시
{
"userId": 1,
"nickname": "huncozy",
"email": "hun@gmail.com"
}
너무 깊게 중첩된 JSON은 가독성도 떨어지고, 프론트에서도 다루기 불편할 수 있기 때문에, 가능하면 2~3 depth 안에서 끝낼 수 있도록 구성하는 게 좋다
{
"code": 200,
"message": "유저 정보를 성공적으로 조회했습니다",
"data": {
"userId": 1,
"studentNumber": "202012345"
}
}
2. 응답 형식은 일관성 있게 유지한다
아래 사진의 예시처럼
성공 응답은 2XX로 응답
실패 응답은 4XX로 응답
해당 내용처럼 통일해서 클라이언트 측에 응답해준다면, 협업시 유지보수나 소통 측면에서 굉장히 좋다
API Server측에서 모든 발생 가능한 에러를 핸들링해줘야 하므로, API Server level에선 500 에러가 나선 안된다
마치며
Reference 문서
아래 링크에 KaKao Developers에서 제공하는 KaKao API의 Rest API의 예시들을 찾아볼 수 있는데,
해당 자료들의 URL, 요청, 응답 형식 등등을 참고하면서 추가로 고민해본다면, RESTful한 설계에 대해 더 도움이 될거같다
https://developers.kakao.com/docs/latest/ko/daum-search/dev-guide#search-book
Kakao Developers
카카오 API를 활용하여 다양한 어플리케이션을 개발해보세요. 카카오 로그인, 메시지 보내기, 친구 API, 인공지능 API 등을 제공합니다.
developers.kakao.com
참고한 자료
'Spring > 개념' 카테고리의 다른 글
HTTP 통신에서 클라이언트와 서버의 역할 (Spring) (0) | 2025.04.16 |
---|---|
IoC와 DI, 그리고 Spring에서의 동작방식 (Spring) (0) | 2025.04.15 |
웹 애플리케이션의 구조와 계층형 패키지 (Spring) (1) | 2025.04.09 |