[Next.js] Prisma 를 사용하여 HTTP 요청 시 마이그레이션 에러 💫
개요 💥
Prisma
를 사용하여 CRUD
를 구현하는 중 Delete
과정에서 마주친 에러이다.
API Handler ✋
- delete.ts
import type { NextApiRequest, NextApiResponse } from 'next'
import { prisma } from '../../../utils/prisma'
export default async function handle(req: NextApiRequest, res: NextApiResponse) {
const { id } = req.query
if(req.method === 'DELETE') {
try {
await prisma.notice.delete({
where: { id: Number(id) },
})
console.log('Delete successful'); // 삭제 성공 로그
res.status(200).json({ success: true, message: 'Notice deleted successfully' });
} catch (error: any) {
console.error('Error deleting notice:', error.message); // 에러 메시지 확인
res.status(500).json({ error: "Unable to delete notice" })
}
} else {
console.log('Invalid method:', req.method); // 유효하지 않은 메서드 로그
res.status(405).end() // Method Not Allowed
}
}
해당 코드는 /pages/api
경로에 생성된 HTTP 요청을 처리하기 위한 핸들러이다.
웹 브라우저나 다른 클라이언트에서 HTTP DELETE
요청이 들어오면,
notice
레코드를 제거하고,
Prisma Client
를 사용하여 데이터베이스에 접근이 가능한 로직이다.
첫 줄에서 prisma
객체를 선언하여 이미 초기화된 Prisma Client
인스턴스를 불러와 사용한다.
handle
함수는 Next.js 의 API 라우트 핸들러
이며,
비동기적으로 HTTP 요청과 응답 객체를 인자로 받아 req.query
를 통해 URL 의 쿼리 파라미터를 추출한다.
요청 메서드가 DELETE
일 경우 아래 로직을 실행하며,
제거하는 요청이 성공 할 경우 200 번대의 상태코드를 반환하고,
실패할경우 500 번대의 상태코드를 반환한다.
이 외에 DELETE
요청이 아닐경우 유효한 메서드로 간주하지 않고,
405 상태코드를 반환한다.
Hooks 👊
- useDelete.ts
import { useCallback } from 'react';
import { useRouter } from 'next/router';
import axios from 'axios';
function useDelete() {
const router = useRouter();
const deleteNotice = useCallback(async (id: number) => {
try {
console.log('Sending delete request for id:', id); // id 값 확인
const res = await axios.delete(`/api/notice`, { params: { id } })
console.log('delete successfully: ', res.data);
router.push('/list'); // 또는 다른 경로로 리다이렉트
} catch (error: any) {
console.error(error.message);
}
}, [router]);
return { deleteNotice };
}
export default useDelete;
해당 로직은,
코드의 중복을 줄이고 컴포넌트의 재사용을 통해 유지보수에 용이할 수 있도록 사용한
커스텀 훅(Custom Hooks)
이다.
Next.js 에서 제공하는 router
를 가져와 페이지 내부에서 라우팅 처리를 위해 선언하고,
Delete
요청이 성공할 경우 router.push
함수를 통해 지정된 경로로 리다이렉트된다.
위에서 정의한 핸들러의 엔드포인트로 (
/api/notice,{ params: { id } }))
특정 id 를 찾아 제거하는 axios
요청을 보내 비동기적으로 수행한다.
만약,
이 요청이 실패할 경우 에러 메세지를 출력하고,
의존성 배열에 router 를 넣어줌으로 인해
router
객체가 변경될 때만 deleteNotice
함수가 재생성된다.
useDelete
Hooks 은,
deleteNotice
함수를 return 하므로 이 Hooks 를 사용하는 컴포넌트에서 사용가능하다.
Components 🔮
- /pages/read/[id].tsx
해당 경로에 생성한 컴포넌트는,
http://localhost:3000/read/{id}
의 값을 가지는 URL 을 생성한다.
useDelete
훅 에서 return 값으로 보낸 deleteNotice
를 불러와 사용한다.
const { deleteNotice } = useDelete();
목록 리스트에서 특정 게시물을 선택하면 {id}
값을 가져와
Detail
컴포넌트로 라우팅 처리되어 리다이렉트로 페이지가 이동된다.
Detail
페이지에는 3 개의 버튼을 구성했는데,
그 중 구현한 삭제 버튼에 onClick
이벤트를 추가하여 Delete
훅을 실행한다.
// delete event
const handleDelete = () => {
if (window.confirm("정말 삭제하시겠습니까?")) {
console.log(`Deleting notice with id: ${id}`);
deleteNotice(id);
}
};
<div
className="w-13 pl-3 pr-3 pt-2 pb-2 bg-red-600 rounded-md flex justify-center items-center space-x-2 cursor-pointer"
onClick={handleDelete}
>
<div className="text-center text-white text-lg font-medium leading-4 break-words font-pretendard">
삭제
</div>
</div>
Error ❌
- 404 Error
위에서 구현한 컴포넌트에서 구현한 삭제
버튼을 클릭 시 404 에러가 발생했다.
해당 프로젝트를 진행하며 주로 발생했던 404 에러는,
HTTP 요청을 보내는 엔드포인트를 잘못 지정했을 때 발생했다.
useDelete
훅을 보면,
const res = await axios.delete(`/api/notice`, { params: { id } })
위 경로로 Delete
요청을 보내는데,
이를 살펴보면
pages/api/
에 있는 디렉토리를 불러올 뿐 API 핸들러를 요청하는 엔드포인트가 아니었다.
즉, 엔드포인트가 다르게 지정되어 404 에러가 출력되고 있는것이다.
const res = await axios.delete(`/api/notice/delete`, { params: { id } });
요청하는 엔드포인트에 /delete
를 추가하여 정상적으로 API 핸들러에 요청을 보낼 수 있었다.
- Migration Error
위에서 구현한 컴포넌트에서 구현한 삭제
버튼을 클릭 시 다음과 같은 에러가 발생했다.
메세지를 살펴보면,
prisma.notice.delete()
를 요청했는데,
next_mariaDB 의 Notice 테이블에 createAt 컬럼이 없어서 해당 명령을 수행할 수 없다는것같다.
schema.prisma
에 정의되어있는 Notice 모델을 확인 해 보니,
실제 createAt
컬럼이 존재하지 않아 아래와 같이 추가 해 주었다.
schema.prisma
파일을 수정 한 후에는 수정사항을 적용하기 위해 아래 명령을 실행해줘야한다.
npx prisma migrate dev
마이그레이션을 통해 해당 스키마를 적용하고,
다시 컴포넌트에 구현된 삭제
버튼을 눌렀지만, 아직도 같은 에러가 발생한다.
schema 를 업데이트 하고난 후에는,
이를 기반으로 prisma.client
를 생성 해 주어야 한다고 한다.
https://www.prisma.io/docs/concepts/components/prisma-client
npx prisma generate
$ npx prisma generate Environment variables loaded from .env Prisma schema loaded from prisma\schema.prisma Error: EPERM: operation not permitted, unlink ‘D:\next_pagesup\node_modules.prisma\client\query_engine-windows.dll.node’
generate
명령을 실행하니 위 에러가 발생했다.
에러를 검색 해 보니,
파일시스템의 권한과 관련된 부분에서 해당 경로에 있는 .node
파일을 제거할 수 없다고 한다.
터미널을 관리자 권한으로 실행하여 명령어를 다시 입력해 보았지만 계속해서 에러가 발생한다.
나는 이 에러를 해결하기 위해
/node_modules
와 yanr.lock
을 GUI 로 지우고
다시 yarn install
을 통해 패키지 설치 후 prisma client
를 생성 해 주었다.
geneate
에러가 계속해서 발생한 이유로는,
에러가 발생했던 createAt
필드가 마이그레이션을 해도
이전에 존재했던 마이그레이션 또는 다른 곳에서 이 필드를 참조하고 있기 때문에 발생할 수 있다고 한다.
위와 같은 방법으로 /node_modules
을 지우고,
다시 yarn install
후 아래 명령어를 실행하니 권한 에러가 해결되고,
prisma Client
가 생성됨을 확인할 수 있었다.
npx prisma generate
Reference 🌊
https://www.prisma.io/docs/concepts/components/prisma-client
https://blog.outsider.ne.kr/1617
https://defineall.tistory.com/872
https://github.com/prisma/prisma/issues/9184
https://lightrun.com/answers/prisma-prisma-generator-output-is-relative-to-prisma
https://codingapple.com/forums/topic/api-handler-should-not-return-a-value-received-object-%EC%A7%88%EB%AC%B8/