이 포스팅은 신선영 저, 『스프링 부트 3 백엔드 개발자 되기』(골든래빗, 2023)를 공부하면서 핵심 개념들을 정리하기 위해 작성하였습니다.
클라이언트와 서버가 서로 데이터를 주고받을 수 있는 이유는 API를 통해서 서로 통신하고 있기 때문이다. 마찬가지로 서로 다른 프로그램끼리 데이터를 주고받을때에도 API가 사용된다. 이처럼 API는 서비스를 제공하기 위해서 반드시 필요하다.
□ API (Application Programming Interface)
API는 서로 다른 어플리케이션들끼리 데이터를 주고 받을 수 있게 해주는 통신 규칙을 의미한다. 클라이언트가 서버에 데이터를 요청하는 것, 그리고 서버에서 클라이언트에 데이터를 제공하는 것, 그리고 서로 다른 프로그램끼리 데이터를 주고 받는 것 모두 API를 통해서 이루어진다.
□ RESTful API
RESTful API는 REST 원칙에 따라서 설계된 API를 의미한다. REST는 Representational State Transfer의 약자로, 자원을 이름으로 구분하여 주고받는 스타일을 의미한다.
REST의 핵심 원칙은 다음과 같다.
○ 자원(Resource) 기반 설계
API는 각각의 자원(데이터)이 어디에 저장되어있는지 나타내는 URL(Uniform Resource Locator)을 중심으로 통신을 한다. REST한 URL은 데이터를 나타내는 경로 또는 자원의 이름만으로 구성되어야 한다. 예를 들면 다음과 같다.
자원 기반 설계를 했을 때의 장점은 다음과 같다.
1. 경로와 메서드만 보고도 API의 역할을 유추할 수 있다. 가독성이 높아진다.
2. 일관성 있게 개발을 할 수 있다. 동사를 허용하게 되면 같은 역할을 하는 API라도 개발자마다 서로 다른 이름을 붙여 혼동을 주는 상황이 발생한다.
3. 확장성과 재사용성이 높다. 나중에 기능이 추가되거나 변경되었을 때 URL을 크게 바꾸지 않아도 된다.
4. 문서 자동화 도구를 사용할 때에 용이하다. Swagger, OpenAPI 등 API의 기능을 문서로 정리해주는 프로그램들은 REST한 API들을 더 잘 분석해주고 정리해준다.
○ HTTP 메서드(Method) 활용
자원에 접근할 때에는 HTTP 메서드를 사용하여 접근하여야 한다. 자주 사용되는 HTTP 메서드의 종류는 다음과 같다.
1. GET
자원을 조회할 때에 주로 사용되는 메서드이다. 바디 없이 쿼리 파라미터 또는 경로를 통해서만 요청한다. 캐시 기능이 담겨있기 때문에 GET 메서드로 자원을 조회하는 것이 성능면으로 유리하다.
GET 메서드로도 데이터를 전송할 수 있지만 이는 금기시된다. 대부분의 프로그램은 GET 메서드가 요청될 경우 서버에 아무런 변화가 발생하지 않는다고 전제하고 있기 때문이다. 한번의 클릭 만으로도 서버에 변화가 생긴다면 이는 안전한 요청이라고 볼 수 없다.
2. POST
서버에 새로운 자원을 생성하기 위해서 주로 사용되는 메서드이다. 생성할 자원을 바디(body)에 담아서 JSON 형식으로 요청한다. 생성된 자원에 대해서는 식별자(ID)가 발급된다. 주로 /users, /articles와 같은 컬렉션 자원에 대해서 요청된다.
POST 메서드로도 데이터를 조회할 수 있지만 이 역시 금기시된다. 무슨 데이터를 조회했는지 URL로 확인할 수 없기 때문에 불편함이 생긴다. POST 메서드의 바디에 담긴 데이터가 서버에 변화를 줄지도 모른다는 위험도 있다. 무엇보다도 POST 메서드에는 캐시 기능이 없기 때문에 조회 목적으로 POST 메서드를 사용할 경우에 성능이 저하된다.
3. PUT
리소스를 통째로 변경하기 위해서 사용되는 메서드이다. 변경하고자 하는 자원의 모든 필드가 바디(body)에 JSON 형식으로 담겨있어야 한다. 그렇지 않으면 누락된 필드의 내용이 PUT 메서드를 실행할 시에 사라질 수 있기에 주의해야 한다. 한편 PUT 메서드는 같은 요청을 여러번 보내도 결과가 같은 멱등성이라는 특징을 지니고 있다. 사용자 정보를 전체 수정하거나 설정 초기화를 할 때에 주로 사용된다.
4. PATCH
리소스를 일부분만 변경하기 위해서 사용되는 메서드이다. 변경하고자 하는 자원의 일부분의 필드만 변경하고자 할 때 주로 사용된다. PATCH 메서드 역시 멱등성을 지니고 있지만 서버마다 다를 수 있다. 비밀번호만 변경한다거나 프로필 이미지만 수정할 때에 주로 사용된다.
5. DELETE
리소스를 삭제할 때에 사용되는 메서드이다. 역시 멱등성을 지니고 있다. 응답으로 보통 204 No Content나 200 OK를 반환한다.
○ 무상태성 (Stateless)
무상태성이란 1)서버는 클라이언트의 상태를 저장하지 않고, 2) 각 요청은 이전 요청에 의존하지 않고 독립적이어야 한다는 규칙이다. 권한이 있는 유저만 게시글을 작성할 수 있거나 이전에 어떤 상품을 구매한 사람에게만 혜택을 주는 것 같이 클라이언트의 상태와 과거 행적을 알아야하는 경우도 존재한다. 이럴때는 JWT 토큰 발급 등의 방법으로 클라이언트의 상태를 클라이언트가 기억하도록 만든다.
서버는 들어온 요청에 대해 이 요청을 보낸 클라이언트가 어떤 사람인지 전혀 기억하지 않는다. 서버는 같은 요청이 들어오면 같은 응답을 반환할 뿐이다. 서버가 클라이언트의 상태를 저장하지 않았을 때의 장점은 여러가지가 있다.
1. 서버 확장과 서버 분산이 쉬워진다.
서버는 클라이언트의 상태를 기억하지 않기 때문에, 클라이언트는 아무 서버에 가서도 동일한 결과값을 얻을 수 있다. 그래서 서버를 확장하거나 요청들을 분산시켜 처리하는 작업이 용이해진다.
2. 장애 복구가 쉽다.
서버가 클라이언트의 상태를 저장하고 있을 경우, 해당 서버가 다운되면 저장되어있던 클라이언트의 상태도 같이 다운된다. 하지만 그렇지 않은 경우, 서버가 다운되어도 상태는 클라이언트에게 있기 때문에 문제가 되지 않는다.
3. 캐시(Cache) 기능을 사용할 수 있다.
무상태성을 유지함으로써 캐시(Cache) 기능을 사용하여 성능을 올릴 수 있다. 어떤 클라이언트가 요청하든지 간에 같은 요청에 대해서는 같은 결과가 늘 보장되기 때문에, 자주 오는 요청에 대해서는 캐시를 하여 더 빠르게 응답할 수 있다.
4. 유지 보수에 용이하다.
이 API는 언제나 같은 역할만을 수행하니까 코드도 간단해지고 API 문서화도 명확하게 할 수 있다.
○ 계층화(Layered System)
계층화란 API의 구조를 여러가지 계층으로 나누어서 설계하는 것을 의미한다. RESTful API는 역할 별로 계층이 나뉘어있고, 각 계층은 자신이 맡은 역할만 수행한다. 계층들은 서로가 무슨 역할을 하는지 알 필요가 없고, 서로의 역할에 얽매여있지 않다.
서로 독립적인 계층으로 나누어서 API를 설계했을 때의 장점은 다음과 같다.
1. 보안이 향상된다.
인증, 인가와 같이 보안이 중요한 로직을 별도의 계층으로 따로 분리하여, 외부에 노출되는 계층과 별개로 관리할 수 있다.
2. 확장성이 용이하다.
트래픽이 몰릴 경우, 트래픽이 몰리는 계층만 확장시키면 된다.
3. 유지 보수가 용이하다.
수정이 필요한 계층만 수정하면 된다. 서로의 계층은 독립적이므로 한 계층이 수정된다고 해서 다른 계층에 큰 영향이 가지 않는다.
4. 캐시 기능을 사용할 수 있다.
각 계층에서 캐시 기능을 사용할 수 있어서 성능이 향상된다.