REST(Representational State Transfer)는 월드 와이드 웹과 같은 분산 하이퍼미디어 시스템을 위한 소프트웨어 아키텍처의 한 형식
웹에 존재하는 모든 자원(이미지, 동영상, DB 자원)에 고유한 URI를 부여해 활용 하는 것
REST API의 구성
REST API의 구성은 크게 세 가지로 이루어 집니다
자원(Resource) - URL
행위 - HTTP method
이전에 배웠던 HTTP method 기억나시나요? GET, POST 등등이 있다고 했었는데요. 이것으로 해당 자원에 대한 행위를 표현할 수 있습니다. 예를 들어 GET 메소드는 해당 자원의 조회, POST 메소드는 해당 자원의 생성 이런 식으로요.
이렇게 나누어진 것을 보통 CRUD 라고 합니다. 자원에 대한 생성/조회/수정/삭제를 각각의 method 로 나누어놓은 것이지요.
Create : 생성(POST)
Read : 조회(GET)
Update : 수정(PUT)
Delete : 삭제(DELETE)
위 이미지의 예시처럼 쓰이는 것이 일반적인 method 사용방식입니다. 하지만 이것은 필수인 부분이 아니고 모든 곳에서 다 이렇게 지켜서 사용하지는 않습니다. 상황에 따라 저것을 완벽하게 지키기 어려운 부분들도 있으니 이 부분 참고 해주세요.
표현
mongoose 는 mongoDB 에 연결하고 데이터 모델링을 제공해주는 툴 입니다.
작동 확인
const mongoose = require('mongoose');
app.get('/mongodb', async (req, res) => {
await mongoose.connect('mongodb://localhost/voyage', {
useNewUrlParser: true,
ignoreUndefined: true
});
res.send('ok');
})
모델링 만들고 데이터 추가하기
상품 goods를 판매 시 나타나야 될 정보들
moongoose 에서는 이런 데이터를 모델링할 때 Schema 객체를 사용합니다.
const { Schema } = mongoose;
const goodsSchema = new Schema({
goodsId: {
type: Number,
required: true,
unique: true
},
name: {
type: String,
required: true,
unique: true
},
thumbnailUrl: {
type: String
},
category: {
type: String
},
price: {
type: Number
}
});
let Goods = mongoose.model("Goods", goodsSchema)
await Goods.create({
goodsId: 1,
name: "맛있는 저녁",
thumbnailUrl: "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRKRQ3NDs5bjulPr3JaXJzP7DH3Y-71WX9wzQ7N8XD9KLUHjT6L&usqp=CAc",
category: "food",
price: 15000
})
구조 만들기
지금 한 route 에 기능을 다 모아놓았던 것을 api 로 쓰기 위해 구조를 변경.
schemas/index.js
const mongoose = require("mongoose");
const connect = () => {
mongoose
.connect("mongodb://localhost:27017/voyage", {
useNewUrlParser: true,
useUnifiedTopology: true,
useCreateIndex: true,
ignoreUndefined: true
})
.catch(err => console.log(err));
};
mongoose.connection.on("error", err => {
console.error("몽고디비 연결 에러", err);
});
module.exports = connect;
schemas/goods.js
const mongoose = require("mongoose");
const { Schema } = mongoose;
const goodsSchema = new Schema({
goodsId: {
type: Number,
required: true,
unique: true
},
name: {
type: String,
required: true,
unique: true
},
thumbnailUrl: {
type: String
},
category: {
type: String
},
price: {
type: Number
}
});
module.exports = mongoose.model("Goods", goodsSchema);
index.js 파일 수정
const connect = require("./schemas");
connect();
api 추가하기
goods route 생성
index.js 파일에 추가
const goodsRouter = require("./routers/goods");
app.use("/api", [goodsRouter]);
router 내용 추가
/routers/goods.js
router.get("/goods", async (req, res, next) => {
try {
const { category } = req.query;
const goods = await Goods.find({ category }).sort("-goodsId");
res.json({ goods: goods });
} catch (err) {
console.error(err);
next(err);
}
});
위에 코드대로 /api/goods 으로 json data 가지고 옵니다.
클라이언트에게 보여 줄 부분 추가
/views/index.js 추가
function get_goods(category) {
$("#goodsList").empty()
console.log(category)
$.ajax({
type: "GET",
url: `/api/goods${category ? "?category=" + category : ""}`,
data: {},
success: function (response) {
let goods = response["goods"]
for (let i = 0; i < goods.length; i++) {
make_card(goods[i])
}
}
})
}
상세 페이지 만들기
router 내용 추가
/routers/goods.js
router.get("/goods/:goodsId", async (req, res) => {
const { goodsId } = req.params;
goods = await Goods.findOne({ goodsId: goodsId });
res.json({ detail: goods });
});
클라이언트에게 보여줄 상세페이지 부분
/views/detail.ejs
function get_detail() {
$.ajax({
type: "GET",
url: `/api/goods/${goodsId}`,
data: {},
error: function(xhr, status, error) {
if (status == 404) {
alert("존재하지 않는 상품입니다.");
}
window.location.href = "/goods";
},
success: function(response) {
let goodsDetail = response["detail"];
$("#goodsUrl").attr("src", goodsDetail["thumbnailUrl"]);
$("#goodsName").text(goodsDetail["name"]);
$("#goodsPrice").text("$" + number2decimals(goodsDetail["price"]));
sessionStorage.setItem("goodsId", goodsId);
sessionStorage.setItem("goodsName", goodsDetail["name"]);
sessionStorage.setItem("goodsPrice", goodsDetail["price"]);
sessionStorage.setItem("orderNum", 1);
}
});
}