아름다운 주소 만들기: REST API
REST (Representational State Transfer)는 일종의 약속입니다. 수많은 개발자가 협업할 때 주소(URL)만 봐도 "아, 이건 유저 정보를 삭제하는 기능이구나!" 하고 한눈에 파악할 수 있도록 일관된 규칙으로 API를 설계하는 방법론을 말합니다.
RESTful 설계의 3대 황금 원칙
| 원칙 |
설명 |
❌ 나쁜 예 |
✅ 좋은 예 |
| 1. 명사(Noun) 사용 |
URL에 get, create 같은 동사를 쓰지 않습니다. 행동은 HTTP 메서드(GET, POST)가 책임집니다. |
/getUser |
/users |
| 2. 복수형(Plural) 통일 |
자원의 이름은 통일성을 위해 가급적 단수보다는 복수형 명사로 통일합니다. |
/post/1 |
/posts/1 |
| 3. 계층 관계 표현 |
자원 간의 포함 관계는 슬래시(/)를 사용하여 상위/하위 개념을 표현합니다. |
/board-comment |
/boards/2/comments |
실무 자원 관리 (Users 예시)
동일한 /users 라는 주소라도 메서드에 따라 완전히 다른 로직이 수행됩니다.
GET /users // 전체 유저 목록 조회
POST /users // 새로운 유저 생성 (회원가입)
GET /users/:id // 특정 ID 유저 상세 조회
PUT /users/:id // 특정 ID 유저 정보 수정
DELETE /users/:id // 특정 ID 유저 탈퇴 (삭제)
나쁜 API와 좋은 API (RESTful) 비교 시뮬레이션
동사(Verb)를 섞어 쓴 잘못된 설계와, 오직 명사(Noun)와 HTTP 메서드만으로 깔끔하게 역할을 분리한 좋은 설계를 비교해 보세요.
const express = require('express');
const app = express();
// ❌ 나쁜 설계 1: 명사 대신 동사(get)를 남용한 방식
app.get('/getUsers', (req, res) => {
console.log(`\n[나쁜 설계] GET /getUsers 요청 수신`);
console.log(`> 🚨 피드백: URL에 "get"이라는 동사가 들어갔습니다!`);
console.log(`> HTTP 메서드(GET) 자체가 이미 행동을 의미하므로 주소에는 명사만 써야 합니다.`);
res.send('나쁜 설계 예시 1');
});
// ❌ 나쁜 설계 2: 목적에 맞지 않는 HTTP 메서드(POST)와 동사(delete) 사용
app.post('/deleteUser/:id', (req, res) => {
console.log(`\n[나쁜 설계] POST /deleteUser/${req.params.id} 요청 수신`);
console.log(`> 🚨 피드백: "삭제"를 하는데 왜 POST 메서드를 썼나요?`);
console.log(`> 주소에 "deleteUser"처럼 동작을 명시하면 REST 원칙에 어긋납니다.`);
res.send('나쁜 설계 예시 2');
});
// ✅ 좋은 설계 1 (RESTful): 복수형 명사 + 올바른 HTTP 메서드(GET)
app.get('/users', (req, res) => {
console.log(`\n[좋은 설계] GET /users 요청 수신`);
console.log(`> ✅ 완벽합니다! (자원: 복수형 명사 / 행동: GET 메서드)`);
console.log(`> 의도: "전체 유저(Users) 목록을 조회해줘."`);
res.send('좋은 설계 예시 1');
});
// ✅ 좋은 설계 2 (RESTful): 계층 관계 + 올바른 HTTP 메서드(DELETE)
app.delete('/users/:id', (req, res) => {
console.log(`\n[좋은 설계] DELETE /users/${req.params.id} 요청 수신`);
console.log(`> ✅ 완벽합니다! (자원: 특정 유저 / 행동: DELETE 메서드)`);
console.log(`> 의도: "유저(Users) 중 ID가 ${req.params.id}번인 자원을 삭제해줘."`);
res.send('좋은 설계 예시 2');
});
app.listen(3000, () => console.log('서버가 3000번 포트에서 시작되었습니다.'));
$ node server.js
서버가 3000번 포트에서 시작되었습니다.
(클라이언트 테스트 1: GET /getUsers 요청)
[나쁜 설계] GET /getUsers 요청 수신
> 🚨 피드백: URL에 "get"이라는 동사가 들어갔습니다!
> HTTP 메서드(GET) 자체가 이미 행동을 의미하므로 주소에는 명사만 써야 합니다.
(클라이언트 테스트 2: POST /deleteUser/5 요청)
[나쁜 설계] POST /deleteUser/5 요청 수신
> 🚨 피드백: "삭제"를 하는데 왜 POST 메서드를 썼나요?
> 주소에 "deleteUser"처럼 동작을 명시하면 REST 원칙에 어긋납니다.
(클라이언트 테스트 3: GET /users 요청)
[좋은 설계] GET /users 요청 수신
> ✅ 완벽합니다! (자원: 복수형 명사 / 행동: GET 메서드)
> 의도: "전체 유저(Users) 목록을 조회해줘."
(클라이언트 테스트 4: DELETE /users/5 요청)
[좋은 설계] DELETE /users/5 요청 수신
> ✅ 완벽합니다! (자원: 특정 유저 / 행동: DELETE 메서드)
> 의도: "유저(Users) 중 ID가 5번인 자원을 삭제해줘."