
우리 프로젝트에서는 클라이언트 컴포넌트 파일일 경우 route handler를 사용하기로 했기에, 밑의 기존 함수를 route handler로 바꿀 필요가 있었다.
// GroupWriteForm.tsx
const addImageHandler = async (e: React.ChangeEvent<HTMLInputElement>) => {
e.preventDefault();
if (e.target.files) {
const fileObj = e.target.files[0];
const supabase = createClient();
const { data } = await supabase.storage
.from("groupposts")
.upload(`grouppost_${Date.now()}.png`, fileObj);
if (data) {
setImgUrl(
`https://nqqsefrllkqytkwxfshk.supabase.co/storage/v1/object/public/groupposts/${data.path}`
);
}
}
};
때문에 기존에 게시물 등록을 하던 로직을 바탕으로 비슷하게 구현하려고 했는데, 한가지 문제가 있었다. 아래는 게시물을 등록하는 route와 연동된 함수이다.
// grouppost.ts
export async function insertGroupPost(newGroupPost: TNewGroupPost) {
await fetch("/api/grouppost", {
method: "POST",
body: JSON.stringify(newGroupPost),
});
}
기존에는 supabase에 등록해줄 객체만 넘겨주면 되었고, 그 방식으로 body에서 JSON.stringify()를 사용하여 넘겨주는 방식을 사용해왔다. (그 외의 방식을 기존에 특별히 사용해오지 않았기에 다른 방식이 있는지는 모르고 있었다.) 그러나 이미지 파일은 객체 형태가 아니었기 때문에, 다르게 넘겨줄 방법이 필요했다. 때문에 다른 방식을 찾아보았고, formData로 넘겨주는 방식을 찾게 되었다.
formData로 데이터를 넘겨주는 방식은 사실 이미 학습을 했던 상태였지만, 학습 이후 사용하지 않아 잊은 상태였다. 나는 아래와 같이 로직을 구성하여 route handler로 이미지를 supabase에 등록해주었다.
// GroupWriteForm.tsx
const addImageMutation = useMutation({
mutationFn: async (newGroupImage: any) => {
const formData = new FormData();
formData.append("file", newGroupImage);
const response = await insertGroupImage(formData);
setImgUrl(
`https://nqqsefrllkqytkwxfshk.supabase.co/storage/v1/object/public/groupposts/${response.path}`
);
},
});
const addImageHandler = async (e: React.ChangeEvent<HTMLInputElement>) => {
e.preventDefault();
if (e.target.files) {
const newGroupImage = e.target.files[0];
addImageMutation.mutate(newGroupImage);
}
};
우선 useMutation을 사용해 파일을 넘겨준 다음, 새로운 formData를 만든 다음 해당 formData에 이미지 파일을 넣고 formData를 insertGroupImage 함수에 인자로 넘겨준다.
// grouppost.ts
export async function insertGroupImage(formData: any) {
const response = await fetch("/api/grouppost/image", {
method: "POST",
body: formData,
});
const data = await response.json();
return data;
}
크게 설명할 필요없이, formData를 route.ts 파일에 넘겨준다.
export async function POST(request: NextRequest) {
// 공구템 작성
const formData = await request.formData();
const newGroupImage: any = formData.get("file");
try {
const supabase = createClient();
const { data } = await supabase.storage
.from("groupposts")
.upload(`grouppost_${Date.now()}.png`, newGroupImage);
return NextResponse.json(data);
} catch (error) {
return NextResponse.json({ error: "데이터를 등록하는 데 실패했습니다." });
}
}
request 내의 formData를 가져오고, 해당 formData 내에 넣어준 file을 가져온다. 이 방식을 사용하니 이미지 데이터가 잘 전달이 되었고, supabase에 잘 올라간 것을 볼 수 있었다.
기존에 객체만 전달하다가 다른 파일을 올리려고 하니 익숙치 않아 발생한 문제였다.
디테일한 부분까지 신경을 쓰려면 많이 남기는 했지만, 큼직한 기능들이 빠르게 진행이 되어가고 있는 것 같아서, 다음 주 초에 빨리 기능을 완성하고 추가적인 부분에 도전을 해보는 식으로 진행을 해봐야할 것 같다. 잘 가고 있는 거라고 생각한다.