Node.js Restful API Example
Restful API란?
- RESTful API : REST 원칙을 잘 지키며 설계된 API
- REST란?
- 웹서비스가 어떻게 동작해야하는지에 대한 아키텍처 스타일 또는 설계 원칙
- 클라이언트와 서버간의 상호작용을 규정하며 여러 원칙과 제약조건을 가진다.
- 무상태(Statelsee) 통신, 캐시가능한 응답을 지향
- REST 구성
- 자원(RESOURCE) - URI
- 행위(Verb) - HTTP METHOD
- 표현(Representations)
REST 특징
- Server-Client (서버-클라이언트 구조)
- server : api제공 및 비지니스 로직 처리 및 저장
- client : 사용자 인증이나 세션정보를 관리
- stateless (무상태성)
- 상태정보를 저장하고 관리 할 필요없이 요청만 처리하여 구현이 단순화됨.
- Cacheable (캐시 처리 가능)
- HTTP 프로토콜의 캐싱기능을 사용할수있어 서버의 부담이 적음
- Self - descriptiveness(자체표현구조)
- API문서없이도 직관적인 해석이 비교적 쉬움
- Layered System (계층화)
- 클라이언트와 서버가 분리되어있기 때문에 중간매체를 사용할 수 있어 자유도가 높음.
- Uniform Interface (인터페이스 일관성)
- 특정언어나 기술에 종속되지 않음
REST 설계규칙
- URI는 정보의 자원을 표현해야하며 소문자를 사용한다.
- 자원에 대한 행위는 HTTP Method (GET, POST, PUT, DELETE 등)으로 표현한다.
- GET : 리소스 조회
- POST : 리소스 생성
- PUT : 리소스 업데이트
- DELETE : 리소스 삭제
- 언더바(_)는 사용하지 않으며 하이픈(-)은 가독성 높일때 사용
- 슬래시(/)는 계층관계를 나타내는데 사용하며 마지막 문자로 슬래시를 포함하지 않는다.
- 파일 확장자는 uri에 포함하지 않는다. (Accept Header를 사용)
Restful API Request URI
- 음식 데이터 API를 간략하게 만들어봤다.

| REQUEST NAME | URI |
| get all | GET /api/food |
| get | GET /api/food/6780d04d3fda73fe2b4e1798 |
| create | POST /api/food |
| update | PUT /api/food/6780d04d3fda73fe2b4e1798 |
| delete | DELETE /api/food/6780d04d3fda73fe2b4e1798 |
Node.js Fridge
The Postman Documenter generates and maintains beautiful, live documentation for your collections. Never worry about maintaining API documentation again.
documenter.getpostman.com
Source Code
var express = require('express');
const Food = require('../models/Food');
const storage = require('../models/type/storage.js');
const {StatusCodes} = require('http-status-codes');
var router = express.Router();
const errMesage = {
NOTFOUND:"Food does not exist.",
DUPLICATE:"Alreay exist food name.",
INVALIDSTORAGETYPE:"Invalid strage type.",
DELETE:"Food is deleted",
DELETEALL:"All food is deleted"
}
// get all
router.get('/',async (req,res) => {
try{
const foods = await Food.find();
res.status(StatusCodes.OK).json(foods);
} catch(err){
res.status(StatusCodes.INTERNAL_SERVER_ERROR).json({error:err.message});
}
});
// get
router.get('/:id',async (req,res) => {
try{
const food = await Food.findById(req.params.id);
if(!food){
return res.status(StatusCodes.NOT_FOUND).json({error:errMesage.NOTFOUND});
}
res.status(StatusCodes.OK).json(food);
} catch(err){
res.status(StatusCodes.INTERNAL_SERVER_ERROR).json({error:err.message});
}
});
// create
router.post('/',async (req,res) => {
try{
let existFood = await Food.exists({name:req.body.name});
if(existFood){
throw new Error(errMesage.DUPLICATE);
}
let expireDateParam = req.body.expireDate;
if(expireDateParam){
expireDateParam = new Date(req.body.expireDate);
}
let storageTypeParam = req.body.storageType;
if(!Object.keys(storage.types).includes(storageTypeParam)){
throw new Error(errMesage.INVALIDSTORAGETYPE);
}
const newFood = new Food({
name:req.body.name,
expireDate: expireDateParam,
storageType: req.body.storageType
});
const createdFood = await newFood.save();
res.status(StatusCodes.CREATED).json(createdFood);
} catch(err){
res.status(StatusCodes.BAD_REQUEST).json({error:err.message});
}
});
// update
router.put('/:id',async (req,res) => {
try{
const orgFood = await Food.findById(req.params.id);
if(!orgFood){
return res.status(StatusCodes.NOT_FOUND).json({error:errMesage.NOTFOUND});
}
if(orgFood.name != req.body.name){
let existFoodName = await Food.exists({name:req.body.name});
if(existFoodName){
throw new Error(errMesage.DUPLICATE);
}
}
let storageTypeParam = req.body.storageType;
if(!Object.keys(storage.types).includes(storageTypeParam)){
throw new Error(errMesage.INVALIDSTORAGETYPE);
}
const updatedFood = await Food.findByIdAndUpdate(req.params.id,{$set:req.body},{new:true});
res.status(StatusCodes.OK).json(updatedFood);
} catch(err){
res.status(StatusCodes.BAD_REQUEST).json({error:err.message});
}
});
// delete
router.delete('/:id',async (req,res) => {
try{
const food = await Food.findByIdAndDelete(req.params.id);
if(!food){
return res.status(StatusCodes.NOT_FOUND).json({error:errMesage.NOTFOUND});
}else {
res.status(StatusCodes.OK).json({message: errMesage.DELETE});
}
} catch(err){
res.status(StatusCodes.BAD_REQUEST).json({error:err.message});
}
});
// delete all
router.delete('/',async (req,res) => {
try{
await Food.deleteMany({});
res.status(StatusCodes.OK).json({message: errMesage.DELETEALL});
} catch(err){
res.status(StatusCodes.BAD_REQUEST).json({error:err.message});
}
});
module.exports = router;
'Script > Node.js' 카테고리의 다른 글
| [Node.js] Node.js Express Google Oauth 연동하기 (0) | 2025.01.22 |
|---|---|
| [Node.js] Node.js 유용한 패키지들 (0) | 2025.01.13 |
| [Node.js] Node.js EJS 템플릿 적용 (0) | 2025.01.06 |
| [Node.js] Node.js로 간단한 Todo리스트 API 만들기 (0) | 2025.01.03 |
| [Node.js] 간단한 Node.js API Server 셋팅하기 (0) | 2025.01.03 |