지난 포스팅에서는 우리가 매일 사용하는 URL의 6가지 기본 구조(Protocol부터 Fragment까지)에 대해 알아보았습니다.
🔗 지난 글 보기: 매일 쓰는 주소창의 비밀, URL 구조 완벽 정리
지난 글의 예시 주소 중에 /blog/posts/88 기억하시나요? 왜 하필 주소가 이렇게 설계되었을까요?
오늘은 실무에서 백엔드와 프론트엔드 개발자들이 가장 많이 고민하고, 기술 면접에서도 단골로 출제되는 'RESTful한 API 주소(URI) 설계 규칙'을 깔끔하게 정리해 보겠습니다.
이 규칙만 지켜도 누구나 한눈에 알아볼 수 있는 "클린 코드" 같은 주소를 만들 수 있습니다.
💡 REST API 주소 설계의 핵심 철학
REST(Representational State Transfer) API 주소를 설계할 때 가장 핵심이 되는 철학은 딱 하나입니다.
"URL(URI)은 자원(Resource)의 '위치'만 나타내고, 행위는 담지 않는다."
즉, 주소창만 보고도 "아, 이 주소는 어떤 데이터가 있는 곳이구나!"를 직관적으로 알 수 있게 만드는 것이 목적입니다. 이를 위한 5가지 황금 규칙을 살펴보겠습니다.
📌 REST API 설계 5가지 황금 규칙
1. 자원(Resource)은 동사가 아닌 '명사'를 사용한다.
가장 많이 하는 실수 중 하나가 주소에 get, create, delete 같은 동사를 넣는 것입니다. API 주소는 데이터(자원) 그 자체를 가리켜야 하므로 반드시 명사로만 구성해야 합니다.
- ❌ Bad: /get-posts, /create-post/88, /deleteUser
- ⭕ Good: /posts, /posts/88, /users
2. 단수형보다는 '복수 명사(Plural)'를 권장한다.
자원의 집합을 나타낼 때는 단수형(post)보다 복수형(posts)을 사용하는 것이 업계 표준(De-facto standard)입니다. 복수형을 사용하면 자원의 컬렉션을 직관적으로 표현할 수 있고, 특정 ID를 붙였을 때 "여러 글 중 88번 글"이라는 의미가 명확해집니다.
- ❌ Bad: /post, /user/james
- ⭕ Good: /posts, /users/james
3. 행위(Action)는 'HTTP Method'로 표현한다.
"그럼 등록하고 수정하고 삭제하는 행위는 주소 없이 어떻게 구분하나요?"라는 의문이 드실 겁니다. 바로 HTTP Method(GET, POST, PUT, DELETE 등)를 활용하는 것입니다.
주소는 동일하게 유지하되, 요청을 보낼 때 행위를 따로 지정해 줍니다. 지난 글의 예시 주소였던 /blog/posts/88을 기준으로 매핑해 볼까요?
| HTTP Method | API 주소 (URI) | 실제 수행하는 행위 (의미) |
| GET | /posts | 전체 게시글 목록을 조회한다. |
| GET | /posts/88 | 88번 게시글의 상세 내용을 조회한다. (지난 글 예시!) |
| POST | /posts | 새로운 게시글을 등록(작성)한다. |
| PUT | /posts/88 | 88번 게시글의 내용을 전체 수정한다. |
| DELETE | /posts/88 | 88번 게시글을 삭제한다. |
4. 가독성을 위해 언더바(_) 대신 하이픈(-)을 사용한다.
주소가 길어져서 단어와 단어를 연결해야 할 때가 있습니다. 이때 언더바(_)를 쓰면 폰트에 따라 밑줄(하이퍼링크 기본 밑줄 등)에 가려져 안 보일 수 있습니다. 구글 검색 로봇 또한 하이픈(-)을 단어의 구분자로 인식하므로, SEO 측면에서도 하이픈(Kebab-case)을 쓰는 것이 훨씬 유리합니다.
- ❌ Bad: /user_profiles, /recommended_posts
- ⭕ Good: /user-profiles, /recommended-posts
5. 대문자 대신 '소문자'만 사용한다 .
RFC 3986 규약에 따라 URL은 대소문자를 구분하지만, 개발자 간의 혼선을 줄이고 구글 검색엔진의 중복 문서 인식을 방지하기 위해 모든 주소는 소문자로 통일하는 것이 원칙입니다.
- ❌ Bad: /UserProfiles, /BLOG/posts
- ⭕ Good: /user-profiles, /blog/posts
🧐 Path Variable vs Query Parameter, 언제 뭘 써야 할까?
REST API를 설계하다 보면 가장 머리 아픈 순간이 찾아옵니다.
"88번 글을 가져올 때 /posts/88이 맞을까, 아니면 /posts?id=88이 맞을까?"
결론부터 말씀드리면 전자가 맞습니다. 주소창에 변수를 직접 넣는 Path Variable(경로 변수)과 물음표 뒤에 붙이는 Query Parameter(쿼리 파라미터)는 사용하는 목적이 완전히 다릅니다. 딱 정해 드리는 3가지 설계 원칙만 기억하세요!
💡 원칙 1. 자원을 '식별'할 때는 Path Variable
내가 원하는 특정 데이터 하나를 콕 집어서 가져오거나 조작하고 싶을 때는 경로에 변수를 넣어야 합니다. 자원의 계층 구조를 나타내기 때문이죠. 이 정보가 빠지면 API 자체가 성립하지 않는 '필수 조건'일 때 사용합니다.
- /posts/88 ➡️ 전체 게시글(posts) 중에서 ID가 88번인 특정 글 하나를 식별함 (필수 데이터)
- /users/daniels/profile ➡️ 전체 유저 중 daniels라는 유저의 프로필을 식별함
💡 원칙 2. 자원을 '정렬, 필터링, 검색'할 때는 Query Parameter
전체 데이터 목록을 가져오되, 그 안에서 특정 조건으로 필터링하거나, 정렬하거나, 페이지를 나눌 때(Pagination) 사용합니다. 이 정보들은 없어도 전체 목록을 보여주면 되기 때문에 API의 '선택 조건'에 가깝습니다.
- /posts?sort=latest ➡️ 게시글 목록을 가져오되, 최신순으로 정렬해줘
- /posts?page=2&size=10 ➡️ 게시글 목록 중 2번째 페이지의 데이터 10개만 보여줘
- /posts?search=api ➡️ 게시글 목록 중 제목이나 본문에 'api'가 포함된 글만 검색해줘
💡 원칙 3. "그게 없어도 자원의 정체성이 유지되는가?" 자문해보기
구분이 안 갈 때는 이 질문을 던져보세요. "물음표 뒤의 데이터를 지웠을 때, 이 주소가 가리키는 본질이 남아있는가?"
- /posts/88에서 88을 지우면? ➡️ /posts(전체 글 목록)가 되어 완전히 다른 API가 됩니다. (즉, 88은 필수적인 자원의 식별자 ➡️ Path Variable)
- /posts?sort=latest에서 ?sort=latest를 지우면? ➡️ 여전히 /posts(전체 글 목록)입니다. 다만 정렬 방식만 기본값으로 바뀔 뿐이죠. (즉, 정렬 조건은 부가 정보 ➡️ Query Parameter)
📊 한눈에 비교하는 치트키 테이블
| 구분 | Path Variable (경로 변수) | Query Parameter (쿼리 파라미터) |
| 핵심 목적 | 자원의 식별 (Identification) | 자원의 정렬, 필터, 검색 (Filtering) |
| 데이터 필수성 | 필수 (Required) - 없으면 404 에러 | 선택 (Optional) - 없으면 기본값 노출 |
| 주소 예시 | /posts/88 | /posts?category=tech&page=1 |
| 한줄 요약 | "어떤 것"을 가져올 것인가? | "어떻게" 보여줄 것인가? |
⚠️ 실무 비급: 관계형 데이터(Sub-resource) 처리 팁
만약 "88번 게시글에 달린 댓글 목록"을 가져오고 싶다면 어떻게 설계해야 할까요? 이때는 두 가지를 조합하면 예술적인 주소가 탄생합니다.
⭕ /posts/88/comments?page=1
- /posts/88/comments : 88번 게시글(Path) 하위에 속한 댓글들(Sub-resource)을 식별하기 위해 Path Variable 사용
- ?page=1 : 그 댓글 목록 중 1페이지를 보기 위해 Query Parameter 사용
이 규칙만 제대로 적용해도 백엔드와 프론트엔드 개발자 간의 소통 오류가 절반 이하로 줄어드는 기적을 경험하실 수 있습니다!
🚫 그 외에 피해야 할 안 좋은 습관들
- 파일 확장자 포함 금지: /posts/88.json 이나 /images/profile.png 처럼 주소 끝에 확장자를 붙이지 마세요. 대신 HTTP Header의 Accept나 Content-Type을 통해 데이터 형식을 지정하는 것이 좋습니다.
- 마지막에 슬래시(/) 포함 금지: /posts/88/ 처럼 주소 맨 끝에 슬래시를 붙이지 마세요. 혼선을 주기 딱 좋습니다.
✍️ 마무리하며
오늘은 RESTful한 API 주소를 설계할 때 지켜야 할 가장 기본적이면서도 중요한 규칙들과 Path Variable, Query Parameter의 차이점까지 심도 있게 알아보았습니다.
처음에는 입에 잘 안 붙고 /get-user가 더 편해 보일 수 있지만, 협업 규모가 커질수록 이 사소한 규칙들이 개발 생산성을 엄청나게 끌어올려 줍니다. 여러분의 프로젝트 주소창은 지금 어떤 모습을 하고 있나요?
Thanks
Hans
'IT' 카테고리의 다른 글
| 매일 쓰는 주소창의 비밀, URL 구조 완벽 정리 (Protocol부터 Fragment까지) (0) | 2026.06.07 |
|---|---|
| [MSA] 마이크로서비스 환경에서 데이터 일관성을 유지하는 5가지 방법 (Saga, CQRS, CDC) (0) | 2026.06.03 |
| API 성능을 획기적으로 개선하는 5가지 필수 전략 (0) | 2026.05.31 |
| Google Gemini CLI 설치 방법 (0) | 2025.11.01 |
| [OOP] 주차장 - ParkingLot (0) | 2024.12.29 |