
API를 왜 사용해야하는가?
프론트와 백엔드의 분리
프론트는 디자인, 백엔드는 데이터 처리를
각자 독립적 개발이 가능하고 후에 API를 통해 연동
데이터 검증 및 제공의 편리성
잘못된 응답 제공 될 경우 거부 가능
데이터 제공시 가공 가능
같은 기능 사용
다양한 클라이언트의 환경에서 같은 API 제공 가능
REST API 명세 및 작성
URL은 자원을 표현해야함
사용자 목록을 조회하는 경우
GET /users → ✅
GET /getUsers → ❌, /user/show/users → ❌ (URL에 동사가 포함)
삭제의 경우
DELETE /users/test → ✅
DELETE /users?id=test → ❌ (자원의 명시가 쿼리 스트링)
HTTP 메서드로 행위를 표현해야함
GET → 조회
POST → 생성
PUT → 전체 수정
PATCH → 부분 수정
DELETE → 삭제
계층 구조의 표현
GET /users/123/posts → 123번 사용자의 게시글
응답은 일관성을 유지해야함
성공 응답과 에러시 실패 응답은 기본적으로 일관성을 유지해야함
예시를 들어, success와 message 라는 내부 조건 검토 필드를 성공에만
넣어놓고 실패시 message만 보내는 것은 잘못된 것임
명세 결론 정리
동사 보다 명사, 단수보다 복수
마지막에 / 사용하지 않기
_ 대신 - 사용하기
확장자 넣지 않기
계층화 하기
/items/{memberId}/members/{itemId} // 잘못됨! /members/{memberId}/items/{itemId} // 올바른 계층 구조!
실 사용 예시
// 사용자 목록 조회
app.get('/api/users', async (req, res) => {
try {
const users = await User.findAll();
res.status(200).json({
success: true,
data: users
});
} catch (error) {
res.status(500).json({
success: false,
message: '서버 오류'
});
}
});
// 특정 사용자 조회
app.get('/api/users/:id', async (req, res) => {
try {
const user = await User.findById(req.params.id);
if (!user) {
return res.status(404).json({
success: false,
message: '사용자를 찾을 수 없습니다'
});
}
res.status(200).json({
success: true,
data: user
});
} catch (error) {
res.status(500).json({
success: false,
message: '서버 오류'
});
}
});
// 사용자 생성
app.post('/api/users', async (req, res) => {
try {
const { name, email, password } = req.body;
// 유효성 검증
if (!email || !password) {
return res.status(400).json({
success: false,
message: '필수 항목을 입력해주세요'
});
}
const newUser = await User.create({ name, email, password });
res.status(201).json({
success: true,
data: newUser
});
} catch (error) {
res.status(500).json({
success: false,
message: '서버 오류'
});
}
});
// 사용자 수정
app.patch('/api/users/:id', async (req, res) => {
try {
const { name, email } = req.body;
const user = await User.findByIdAndUpdate(
req.params.id,
{ name, email },
{ new: true } // 수정된 데이터 반환
);
if (!user) {
return res.status(404).json({
success: false,
message: '사용자를 찾을 수 없습니다'
});
}
res.status(200).json({
success: true,
data: user
});
} catch (error) {
res.status(500).json({
success: false,
message: '서버 오류'
});
}
});
// 사용자 삭제
app.delete('/api/users/:id', async (req, res) => {
try {
const user = await User.findByIdAndDelete(req.params.id);
if (!user) {
return res.status(404).json({
success: false,
message: '사용자를 찾을 수 없습니다'
});
}
res.status(200).json({
success: true,
message: '삭제되었습니다'
});
} catch (error) {
res.status(500).json({
success: false,
message: '서버 오류'
});
}
});실전 팁
버전 관리를 명세
/…/v1/users → 해당 버전을 v1으로 명세
아래의 구성요소를 갖고 있어야 좋은 명세서
구성 요소
설명
API 개요
이 API가 어떤 목적으로 만들어졌는지, 버전 정보, 전체 주소(Base URL) 등
Endpoint
API가 제공하는 개별 기능의 '주소' (URI)
Method
해당 주소로 어떤 작업을 할지 결정 (HTTP Method)
Parameters
요청할 때 꼭 보내야 하는 추가 정보들
Request Body
생성하거나 수정할 데이터의 실체 (주로 JSON 형식)
Response
요청 처리 후 서버가 돌려주는 응답 정보
Status Codes
요청의 성공/실패 여부를 나타내는 숫자 코드