REST API
REST(Representational State Transfer)는 웹의 기본 구조인 HTTP 위에서 API를 설계하는 아키텍처 스타일입니다. 각 자원을 고유한 URI로 식별하고, GET·POST·PUT·DELETE 같은 HTTP 메서드로 그 자원에 대해 수행할 동작을 표현합니다. 서버는 요청 사이에 클라이언트 상태를 기억하지 않는 무상태 원칙을 따르며, 응답에는 관련 리소스로의 링크를 포함할 수 있습니다. JSON이 사실상 표준 응답 형식으로 자리잡았고, HTTP 상태 코드로 성공과 실패를 구분합니다. 별도의 프로토콜이나 도구 없이 브라우저, curl, 모바일 앱 어디서든 접근할 수 있다는 점이 REST가 널리 퍼진 배경입니다.
▶아키텍처 다이어그램
🔗 관계 다이어그램점선 애니메이션은 데이터 또는 요청의 흐름 방향을 나타냅니다
서버에 데이터를 요청하거나 변경할 방법이 필요할 때, 팀마다 URL 구조와 요청 형식을 제각기 정하면 금세 혼란이 옵니다. 어떤 API는 /getUser?id=1로 조회하고, 어떤 API는 /user/fetch에 POST로 ID를 보내고, 또 다른 API는 /api/v2/user-info라는 전혀 다른 경로를 씁니다. 팀이 늘거나 외부 개발자에게 API를 열 때마다 '이 URL에 어떤 메서드를 보내야 하는지', '응답 형식이 뭔지'를 일일이 설명해야 하고, 문서가 조금만 오래되면 실제 동작과 어긋납니다. 클라이언트가 웹 브라우저 하나였을 때는 어떻게든 맞춰 쓸 수 있었지만, 모바일 앱과 서드파티 연동까지 붙으면 일관된 규칙 없이는 API 유지보수가 급격히 어려워집니다.
2000년 Roy Fielding이 박사 논문에서 REST를 제안했을 때, 웹 API의 주류는 SOAP이었습니다. SOAP는 XML 기반의 엄격한 메시지 봉투 규격과 WSDL 정의 파일을 요구했고, 단순한 데이터 조회에도 수백 줄짜리 XML 왕복이 필요했습니다. 엔터프라이즈 시스템 간 연동에서는 이 엄격함이 장점이었지만, 웹과 모바일이 폭발적으로 성장하면서 '빠르게 만들고 빠르게 연동한다'는 요구가 커졌습니다. REST는 이미 웹이 쓰고 있는 HTTP의 메서드, URI, 상태 코드를 그대로 활용하자는 접근이었기에 별도의 명세 언어나 도구 없이도 curl 한 줄로 API를 시험할 수 있었습니다. 2000년대 후반 Twitter, GitHub, Stripe 등이 REST API를 공개하면서 웹 API의 사실상 기본이 됐고, JSON이 XML을 대체하면서 가벼움은 더 두드러졌습니다.
REST API를 읽을 때 먼저 보는 축은 자원, 메서드, 상태 코드입니다. 자원을 먼저 정하면 URL은 동사가 아니라 명사가 됩니다. /users는 사용자 컬렉션, /users/123은 특정 사용자처럼 대상을 가리키고, GET·POST·PATCH·DELETE가 그 대상에 어떤 변화를 요구하는지 표현합니다. 그래서 경로만 봐도 무엇을 다루는지, 메서드만 봐도 조회인지 생성인지 수정인지 짐작할 수 있습니다. 클라이언트가 요청을 보내면 서버는 그 자원의 현재 표현(representation)을 JSON 같은 형식으로 돌려주고, HTTP 상태 코드로 처리 결과를 요약합니다. 200은 성공, 201은 생성 완료, 404는 대상을 찾지 못함, 422는 형식은 맞지만 내용이 유효하지 않음을 뜻합니다. 이런 공통 신호 덕분에 클라이언트는 응답 본문을 읽기 전에도 어떤 종류의 결과인지 빠르게 분기할 수 있습니다. 또 REST는 서버가 이전 요청을 기억하지 않는 무상태 원칙을 전제로 합니다. 그래서 인증 토큰, 페이지네이션 커서, 필터 조건처럼 다음 처리에 필요한 맥락은 매 요청에 함께 실어 보내야 하고, 그 덕분에 서버를 여러 대로 늘릴 때도 특정 연결 상태를 맞추는 부담이 줄어듭니다.
리소스별로 메서드 역할 나누기
app.get("/users/:id", (req, res) => {
res.json({ id: req.params.id });
});
app.post("/users", (req, res) => {
res.status(201).json({ id: "123" });
});같은 /users 경로라도 GET은 조회, POST는 생성처럼 메서드가 의도를 나타낸다는 점을 읽으면 REST의 자원 중심 구조가 보입니다.
상태 코드는 결과를 짧게 전달한다
if (!user) {
return res.status(404).json({ message: "not found" });
}
return res.status(200).json(user);응답 본문을 읽기 전에 404와 200만 봐도 요청이 실패했는지, 성공했는지, 어떤 자원 상태인지 빠르게 분기할 수 있습니다.
REST와 GraphQL은 둘 다 클라이언트가 서버 데이터를 가져오는 API 계층이라는 공통점이 있습니다. 하지만 접근 방식이 다릅니다. REST는 리소스마다 엔드포인트를 나누고 서버가 응답 구조를 결정합니다. GraphQL은 단일 엔드포인트에서 클라이언트가 필요한 필드를 쿼리로 명시합니다. REST는 리소스 구조가 안정적이고 클라이언트 종류가 비교적 균일할 때 강합니다. URL과 HTTP 메서드만으로 API 의도가 드러나고, 캐싱도 HTTP 레벨에서 자연스럽게 동작합니다. 반면 화면마다 필요한 데이터 조합이 크게 다르거나, 한 화면에 여러 리소스를 한번에 가져와야 하는 상황이 잦다면 REST에서는 요청 횟수가 늘거나 필요 없는 필드까지 받게 됩니다. 공개 API를 운영하거나 표준 HTTP 인프라(CDN 캐싱, 로드 밸런서 등)를 최대한 활용해야 한다면 REST가 유리하고, 복잡한 프론트엔드 요구사항에 데이터 페칭을 맞춰야 한다면 GraphQL 쪽을 살펴볼 필요가 있습니다.
REST API는 백엔드가 관리하는 리소스를 여러 클라이언트에 노출하는 가장 보편적인 방식입니다. 사용자 관리, 상품 카탈로그, 주문 처리 같은 CRUD 패턴이 중심인 서비스에서는 리소스와 엔드포인트가 일대일로 대응되어 설계가 직관적입니다. 외부 개발자에게 API를 공개할 때도 REST는 자연스러운 선택입니다. HTTP를 지원하는 어떤 언어·플랫폼에서든 호출할 수 있고, URL 구조만 봐도 어떤 리소스를 다루는지 알 수 있어 진입 장벽이 낮습니다. OpenAPI(Swagger) 명세를 작성하면 문서 생성과 클라이언트 코드 생성까지 자동화할 수 있습니다. 마이크로서비스 환경에서 서비스 간 HTTP 통신이 필요할 때도 REST가 자주 쓰입니다. 다만 서비스 수가 많아지고 호출 체인이 길어지면 API 게이트웨이를 앞에 두고 인증, 속도 제한, 라우팅을 중앙에서 관리하는 패턴이 일반적입니다. 주의할 점도 있습니다. 한 화면에서 여러 리소스를 조합해야 하는 복잡한 프론트엔드에서는 REST 호출이 여러 번 오가면서 지연이 누적될 수 있습니다. 리소스 경계가 UI 요구와 잘 맞지 않을 때는 BFF(Backend For Frontend) 패턴을 도입하거나 API 설계를 다시 점검해야 할 수 있습니다.