URL보다 리소스가 먼저다: AI 시대의 REST API 설계
“회원 가입 API 만들어 줘.”
Cursor나 Claude 같은 AI 에이전트에게 이렇게 말하면 곧바로 엔드포인트가 나옵니다.1
POST /api/createUserPOST /api/user/signupPOST /api/register
셋 다 동작은 합니다. 하지만 리소스를 먼저 정하지 않은 결과입니다.
URL은 결과지, 출발점이 아니다
REST에서 URL을 먼저 정하려고 하면 길을 잃습니다.
먼저 정해야 할 것은 리소스가 무엇인가입니다.
회원 가입은 동사처럼 보입니다.
그래서 createUser, register 같은 동사형 URL이 튀어나옵니다.
하지만 REST에서 리소스는 개념입니다.
URL은 리소스를 식별합니다.2
비즈니스 행위가 아무리 복잡해도,
REST는 그것을 리소스에 대한 조작으로 추상화합니다.3
리소스를 User로 잡으면
URL은 자연스럽게 따라옵니다.4
POST /users 사용자 생성
GET /users/{id} 사용자 조회
PATCH /users/{id} 사용자 수정
DELETE /users/{id} 사용자 삭제
URL은 리소스를 정하고 나면 거의 자동으로 결정됩니다.
어려운 건 URL을 짓는 일이 아니라,
무엇을 리소스로 볼 것인가를 정하는 일입니다.
리소스는 DB 테이블이 아닙니다.
Entity와 1:1로 대응하지도 않습니다.
리소스는 어떤 개념입니다.
테이블 구조가 어떻든, 도메인 객체가 어떻든,
내부에서 무엇을 하든 상관없습니다.
REST API 설계는 결국 약속을 정하는 일이다
리소스와 URL을 정하면 끝일까요?
아닙니다.
REST API를 설계한다는 건 URL만 정하는 일이 아닙니다.
시스템과 시스템 사이의 약속을 정하는 일입니다.
정해야 할 것이 많습니다.
- 같은 요청을 두 번 보내면 어떻게 되는가?5
- 실패하면 어떤 상태 코드와 에러 모델을 돌려주는가?
- 목록은 어떻게 페이지네이션하는가?
- 이 약속이 바뀌면 기존 클라이언트는 어떻게 되는가? 버저닝은 어떻게 할 것인가?
이 약속들은 AI가 추측해서 채울 수 있습니다.
실제로 잘 채웁니다.
문제는 그 추측이 우리 의도와 같다는 보장이 없다는
점입니다.
예를 들어, 결제 요청이 네트워크 오류로 재시도된다고 합시다.
같은 결제가 두 번 일어나면 안 됩니다.
그래서 요청마다 고유한 키를 붙여
중복을 막기로 정합니다.6
이건 설계 결정입니다.
AI가 알아서 정해 줄 일이 아니라,
사람이 먼저 정하고 AI에게 구현을 맡길 일입니다.
구현은 가져가도, 약속은 남는다
외부와 주고받기로 한 이 약속을 계약이라 부릅니다.
AI가 코드를 가져갈수록 이 계약은 더 중요해집니다.
구현은 바꿀 수 있습니다.
내부 로직을 다시 작성하고, 데이터베이스를 갈아끼우고,
프레임워크를 바꿔도 됩니다.
하지만 계약은 한번 외부에 공개되면
함부로 바꿀 수 없습니다.
다른 팀이, 다른 서비스가, 모바일 앱이
그 약속에 의존하기 때문입니다.
무엇을 리소스로 볼지,
무엇을 보장할지,
어떻게 진화시킬지.
이 약속을 사람이 또렷하게 정해 두어야
AI가 그 안에서 구현할 수 있습니다.
리소스가 흐릿하면 URL도 흔들리고,
약속이 흐릿하면 계약도 흔들립니다.
거꾸로 가면 AI가 아무리 빨라도
틀린 곳으로 빠르게 갈 뿐입니다.
이걸 제대로 배우고 싶다면, 와일드 백엔드로 오세요.
Footnotes
-
AI 에이전트는 사용자의 지시를 받아 코드를 작성하고 실행까지 수행하는 AI 시스템입니다. ↩
-
엄밀히는 URI라고 해야 합니다. URN도 URI의 일종이지만 실제로는 거의 쓰이지 않아, 이 글에서는 URL로 표기했습니다. ↩
-
REST는 로이 필딩이 2000년 박사 논문에서 제안한 아키텍처 스타일로, 균일한 인터페이스 제약을 통해 복잡한 비즈니스 행위를 리소스에 대한 조작으로 추상화합니다. ↩
-
이 예시는 Collection Pattern입니다. 복수형 명사로 컬렉션을 표현하고
{id}로 개별 리소스를 식별하는 방식은 널리 쓰이지만, REST가 요구하는 것은 아닙니다. 중요한 건 URL 형식이 아니라 리소스를 올바르게 식별했는가입니다. ↩ -
멱등(idempotent)은 같은 요청을 여러 번 보내도 결과가 달라지지 않는 성질입니다.
GET,PUT,DELETE는 멱등하지만POST는 기본적으로 멱등하지 않습니다. ↩ -
이 패턴을 Idempotency Key라고 부릅니다. Stripe 등의 결제 API에서 널리 사용합니다. ↩