REST(Representational State Transfer)는 웹 서비스의 아키텍처 스타일로, 다음과 같은 특징을 가집니다.
클라이언트와 서버의 관심사를 분리하여 독립적 진화 가능
각 요청은 이전 요청과 독립적으로 처리되어야 함
응답은 캐시 가능 여부를 명시해야 함
URI로 지정한 리소스에 대한 조작을 통일되고 한정적인 인터페이스로 수행
중간 계층을 둘 수 있으며, 클라이언트는 서버와 직접 통신하는지 알 필요가 없음
서버가 클라이언트에 실행 가능한 코드를 전송하여 기능을 확장할 수 있음
RESTful API는 REST 아키텍처의 제약조건을 준수하며 REST API를 제공하는 웹 서비스를 의미합니다.
// RESTful API 예시
GET /users // 사용자 목록 조회
GET /users/:id // 특정 사용자 조회
POST /users // 새 사용자 생성
PUT /users/:id // 사용자 정보 전체 수정
PATCH /users/:id // 사용자 정보 일부 수정
DELETE /users/:id // 사용자 삭제
// REST API 예시 (덜 RESTful한 방식)
GET /getAllUsers
POST /createUser
PUT /updateUser
DELETE /deleteUser/:id
// RESTful API 예시 (리소스 중심)
GET /users
POST /users
PUT /users/:id
DELETE /users/:id
import express from "express";
const router = express.Router();
// 사용자 관련 엔드포인트
router.get("/users", async (req, res) => {
try {
const users = await User.find();
res.status(200).json(users);
} catch (error) {
res.status(500).json({ error: "Internal Server Error" });
}
});
router.get("/users/:id", async (req, res) => {
try {
const user = await User.findById(req.params.id);
if (!user) {
return res.status(404).json({ error: "User not found" });
}
res.status(200).json(user);
} catch (error) {
res.status(500).json({ error: "Internal Server Error" });
}
});
router.post("/users", async (req, res) => {
try {
const newUser = await User.create(req.body);
res.status(201).json(newUser);
} catch (error) {
res.status(400).json({ error: "Invalid request" });
}
});
// 상태 코드 사용 예시
200: OK
201: Created
204: No Content
400: Bad Request
401: Unauthorized
403: Forbidden
404: Not Found
500: Internal Server Error
/api/v1/users
/api/v2/users
// 쿼리 파라미터를 통한 페이지네이션
GET /api/users?page=1&limit=10
// 응답 예시
{
"data": [...],
"pagination": {
"currentPage": 1,
"totalPages": 5,
"totalItems": 48,
"itemsPerPage": 10
}
}
// 에러 응답 형식
{
"error": {
"code": "USER_NOT_FOUND",
"message": "사용자를 찾을 수 없습니다.",
"details": {
"userId": "123"
}
}
}
// HATEOAS 응답 예시
{
"id": 1,
"name": "John Doe",
"_links": {
"self": { "href": "/api/users/1" },
"profile": { "href": "/api/users/1/profile" },
"orders": { "href": "/api/users/1/orders" }
}
}
src/
├── controllers/
│ ├── userController.ts
│ └── postController.ts
├── routes/
│ ├── userRoutes.ts
│ └── postRoutes.ts
├── models/
│ ├── User.ts
│ └── Post.ts
├── middleware/
│ ├── auth.ts
│ └── errorHandler.ts
└── app.ts
/users:
get:
summary: 사용자 목록 조회
parameters:
- name: page
in: query
type: integer
description: 페이지 번호
responses:
200:
description: 성공
schema:
type: array
items:
$ref: "#/definitions/User"
// JWT를 사용한 인증 예시
app.use("/api", authenticate);
function authenticate(req, res, next) {
const token = req.headers.authorization?.split(" ")[1];
if (!token) {
return res.status(401).json({ error: "Authentication required" });
}
// JWT 검증 로직
}
import rateLimit from "express-rate-limit";
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15분
max: 100 // IP당 최대 요청 수
});
app.use("/api", limiter);
RESTful API를 설계할 때는 다음 사항을 고려해야 합니다.