Prisma로 간단한 CRUD 구현해보기
Prisma 공식문서를 참고한 포스트입니다
블로그 서비스를 만든다고 했을때 글(Articles)에 대한 간단한 CRUD를 prisma를 이용해서 구현해보겠습니다!
model articles {
id Int @id @default(autoincrement())
user_id Int
title String
body String
status articles_status @default(DRAFT)
created_at DateTime? @default(now())
updated_at DateTime?
deleted_at DateTime?
users users @relation(fields: [user_id], references: [id])
comments comments[]
@@index([user_id], name: "user_id")
}
Articles 테이블의 스키마입니다! users 테이블의 id를 fk로 가지고 있습니다.
그리고 status 필드는 enum으로 default값은 DRAFT이고, PUBLISHED, DELETED가 있습니다.
const app = express();
app.post('/articles', createArticle);
app.get('/articles', getArticles);
app.get('/articles/:id', getArticle);
app.put('/articles/:id', updateArticle);
app.delete('/articles/:id', deleteArticle);
우선 endpoint는 위와 같이 연결되어있습니다
CREATE
const createArticle = async(req, res) => {
try {
const {user_id, title, body} = req.body; // request의 body에서 user_id, title, body를 받음
if(!user_id || !title || !body) { // 셋 중 req의 body에 들어오지 않은 것이 있다면 error!
const error = new Error('invalid input');
error.status = 400;
throw error;
}
const foundUser = await prisma.users.findUnique({where : {id : user_id}}); // user_id를 이용하여 users 테이블에서 user를 찾음
if(!foundUser) { // 만약 user_id가 존재하지 않는 user의 id라면 error!
const error = new Error('user not found');
error.status = 404;
throw error;
}
const createdArticle = await prisma.articles.create({ // articles 테이블에 새로운 row 생성
data: {
users : {
connect : {id: user_id} // users 테이블의 id가 fk로 연결되어 있어서 이런식으로 작성해주어야 함
} , title, body, status: 'PUBLISHED'
}
});
res.status(201).json({createdArticle});
} catch (error) {
res.status(error.status).json({message : error.message});
}
}
findUnique
The
findUnique
query lets you retrieve a single database record by ID or another unique attribute. You can use theselect
andinclude
options to determine which properties should be included on the returned object.
findUnique는 where로 들어온 조건으로 db에서 해당 조건에 해당하는 하나의 record를 찾아서 반환합니다. 리턴타입은 null이거나 js object입니다.
create
The
create
query creates a new database record. You can use theselect
andinclude
options to determine which properties should be included on the returned object.
create는 db에 새로운 record를 추가합니다. data에 어떤 내용이 들어가야 하는지 적어주면 됩니다.
Table 설정 중 not null인 값들을 적어주면 되겠네요!
create는 새로 생성된 데이터의 js object를 리턴합니다.
READ
const getArticles = async(req, res) => { // articles 테이블의 모든 row 조회
try {
const articles = await prisma.articles.findMany({
where: { // 해당 조건에 해당하는 모든 데이터를 찾음
OR: [
{
status: 'DRAFT'
},
{
status: 'PUBLISHED'
}
]
}
});
res.status(200).json({articles});
} catch (error) {
res.status(500).json({message : error.message});
}
}
findMany
The
findMany
query returns a list of records. You can use theselect
andinclude
options to determine which properties the returned objects should include. You can also paginate, filter, and order the list.
where절을 사용해서 위 코드처럼 조건을 걸 수도 있지만 만약 아무런 조건을 걸고 싶지 않은 경우
const articles = await prisma.articles.findMany();
이렇게 할 수 있겠습니다. 제가 저렇게 조건을 걸어준 이유는 뭔가 articles의 필드를 봤을 때 status에 DELETED 가 있기 때문에
db에서 직접 row를 삭제하지 않고 status를 변경해주는 식으로 구현했기 때문입니다.
const getArticle = async(req, res) => { //path parameter로 입력된 id에 해당하는 article 조회
try {
const {id} = req.params; // path parameter로 들어온 id
const foundArticle = await prisma.articles.findUnique({ // 해당 article이 존재하는지 확인
where: {
id : Number(id)
}
});
if(!foundArticle || foundArticle.status === 'DELETED'){ // 만약 존재하지 않거나 DELETED 상태면 error
const error = new Error('invalid id');
error.status = 400;
throw error;
}
console.log(foundArticle);
res.status(200).json({foundArticle});
} catch (error) {
res.status(error.status).json({message : error.message});
}
}
따라서 article의 목록이 아닌 하나의 article을 조회하는 함수도 위와 같이 구현했습니다.
UPDATE
const updateArticle = async(req, res) => {
try {
const {id} = req.params; // 수정하길 바라는 article의 id
const {title, body} = req.body;
if(!title || !body){ // title, body가 입력으로 들어오지 않은 경우 error
const error = new Error('invalid input');
error.status(400);
throw error;
}
const foundArticle = await prisma.articles.findUnique({ // 해당 article이 존재하는지 확인
where: {
id : Number(id)
}
});
if(!foundArticle || foundArticle.status === 'DELETED'){ // article이 존재하지 않거나 DELETED면 error
const error = new Error('invalid id');
error.status = 400;
throw error;
}
const updatedArticle = await prisma.articles.update({ // article 내용 수정
where: {
id : Number(id)
},
data: {
title, body
}
});
res.status(200).json({updatedArticle});
} catch (error) {
res.status(error.status).json({message : error.message});
}
}
Update
The
update
query updates an existing database record. You can use theselect
andinclude
options to determine which properties should be included on the returned object.
where에 어떤 데이터를 수정할건지 필터링 하는 옵션을 명시해주고, data에는 변경할 내용을 적어주면 됩니다.
DELETE
const deleteArticle = async (req, res) => {
try {
const {id} = req.params; // 삭제하길 바라는 article의 id
const foundArticle = await prisma.articles.findUnique({ // 해당 id를 가진 article이 있는지 확인
where: {
id : Number(id)
}
});
if(!foundArticle){
const error = new Error('invalid id');
error.status = 400;
throw error;
}
const deletedArticle = await prisma.articles.update({ // 해당 id를 가진 article의 status를 DELETED로 변경
where: {
id: Number(id)
},
data: {
status: 'DELETED'
}
});
res.status(200).json({deletedArticle});
} catch (error) {
res.status(error.status).json({message : error.message});
}
}
사실 제가 구현한 delete는 delete의 탈을 쓴 update입니다 (…) 만약 prisma의 delete 함수를 사용해서 구현한다면 아래와 같은 모습이겠네요!
delete
The
delete
query deletes an existing database record. Even though the record is being deleted,delete
still returns the object that was deleted. You can use theselect
andinclude
options to determine which properties should be included on the returned object.
const deletedArticle = await prisma.articles.delete({
where : {
id: Number(id)
}
})
댓글남기기