
이 글은 이전 포스트에 이어 Next.js의 프론트엔드에서 REST API를 사용하는 방법을 설명합니다.
다음 지식들을 안다면 문제없이 읽을 수 있습니다.
- TypeScript
- Node.js
- React 기초 문법
- Next.js 기초 문법
- Promise
- ES6
- REST API
프론트엔드에서 api에 접근하기 위해서는 fetch 혹은 axios를 사용합니다. 두 메소드에 대한 자세한 내용은 좋은 포스트가 있으니 확인해 보시기 바랍니다. 여기서는 axios를 사용하겠습니다.
npm install axios 혹은 yarn add axios 를 이용해 설치합니다.
axios는 여러 가지 방법으로 사용할 수 있습니다. axios.(요청을 보낼 메소드 명) 방식으로 사용하겠습니다. 다시 설명하자면, api/users url에 GET 요청을 보내고 싶다면 다음과 같이 작성하면 됩니다.
axios.get("/api/users");
POST, PUT, DELETE 요청도 동일하게 작성하면 됩니다. 만약 추가 정보가 필요한 경우는 다음과 같이 두 번째 인자에 객체를 주면 됩니다.
axios.post("/api/users", {
headers: { ... },
data: { ... },
});
프론트엔드 코드를 작성하기 전에, 저번 포스트에서 작성한 내용을 바탕으로 /api 폴더의 백엔드 코드를 작성해보려 합니다. 그 전에, 각 요청을 받을때 API가 어떤 방식으로 동작해야할 지를 정의해 봅시다.
GET요청을 받는 경우: 모든user정보를 가게 이름들과 함께 주면 됨POST요청을 이름과 함께 받는 경우: 새user를 만듦PUT요청을id, 이름과 함께 받는 경우: 해당id의 유저 이름을 변경DELETE요청을id와 함께 받는 경우 : 해당id의 유저를 삭제
위 네 가지 동작을 수행하는 코드를 작성하는 것은 저번에 배웠지만, 요청에서 id 혹은 이름을 어떻게 가져올까요? 보통 axios에서는 요청의 body의 data에 정보를 담아 보내기 때문에, id를 가져오려면 다음 방법들 중 하나를 사용하면 됩니다.
const id = req.body.data.id;
// With ES6
const {
body: {
data: { id },
},
} = req;
GET 요청같은 경우에는 응답을 프론트엔드에 보내야 합니다. 이 경우에는 prisma client가 반환한 값을 json에 실어 보내면 됩니다.
const users = await client.users.findMany({});
res.json({ ok: true, users });
위와 같이 작성하면 프론트엔드에서는 수신한 데이터의 users 속성을 확인해 데이터를 확인할 수 있습니다.
이제 정보를 가져오고 응답을 보내는 방법을 알았으니 API를 작성하면 됩니다. 저번 포스트에서 설명한 내용이라 별도로 설명하지는 않겠습니다. 이 함수는 handler 함수의 내부를 작성한 것입니다.
if (req.method === "GET") {
const users = await client.users.findMany({
include: {
shops: {
select: {
name: true,
},
},
},
});
res.json({ ok: true, users });
}
if (req.method === "POST") {
const {
body: {
data: { name },
},
} = req;
const createUser = await client.users.create({
data: {
username: name,
},
});
res.json({ ok: true });
}
if (req.method === "PUT") {
const {
body: {
data: { id, name },
},
} = req;
const updateUser = await client.users.update({
where: {
id: +id,
},
data: {
username: name,
},
});
res.json({ ok: true });
}
if (req.method === "DELETE") {
const {
body: { id },
} = req;
const deleteUser = await client.users.delete({
where: {
id: +id,
},
});
}
id를 사용할때+id형태로 사용하는 것은, 받은id가 숫자인지 확실하지 않기 때문에 숫자로 변환시키기 위해 +를 붙여주는 것입니다.axios.delete함수가body내의data부분이 없다는 점 대문에DELETE메소드일땐id를 바로body에서 가져옵니다. (이 부분은 저도 조금 헷갈리네요...)
백엔드에서 어떻게 API를 다루는지는 끝났습니다. 이제는 프론트엔드에서 API에 요청을 보내는 코드를 작성해보겠습니다. 그 전에 데이터베이스에서 CRUD 작업이 잘 이루어지는지 확인하기 위해 prisma studio를 활용하겠습니다.
우선 /pages 폴더에 users.tsx 파일을 다음과 같이 생성해 줍니다.
export default function Users() {
const onPostClick = async () => {};
const onGetClick = async () => {};
const onPutClick = async () => {};
const onDeleteClick = async () => {};
return (
<div className="flex flex-col space-y-8">
<button onClick={onPostClick}>POST</button>
<button onClick={onGetClick}>GET</button>
<button onClick={onPutClick}>PUT</button>
<button onClick={onDeleteClick}>DELETE</button>
</div>
);
}
맨 상위
div에 작성된"flex flex-col space-y-8"은 CSS를 적용한 것입니다. 자세한 내용은 tailwindcss 를 참고 바랍니다.
위 코드는 각각 POST, GET, PUT, DELETE 요청을 보내는 버튼들을 모아두었습니다. 각 버튼에 연결된 함수들을 구현해 보겠습니다.
const onPostClick = async () => {
await axios.post("/api/users", {
headers: { "Content-Type": "application/json" },
data: {
name: "Max Demian",
},
});
};
위 코드가 실행되면 /api/users url로 {name: Max Demain} 데이터와 함께 POST 요청이 갑니다. 따라서 username에 Max Demian 속성을 가지고 있는 user가 만들어질 것입니다.
실제로 다음과 같이 데이터가 만들어진 것을 볼 수 있습니다.

GET 요청을 수행하기 전에 방금 만든 user와 연결되는 shop 두개를 만들어 보겠습니다. prisma studio로 만들거나 위 create 코드를 응용해 만드시면 됩니다.

const onGetClick = async () => {
const result = await axios.get("/api/users");
console.log(result);
};
위 코드와 같이 현재 GET 요청은 추가적인 정보를 필요로 하지 않습니다. 그리고 axios.get 함수의 반환값을 살펴보면 다음과 같습니다.

여기서 저희가 원하는 부분은 data 부분이므로, ES6의 도움을 받아 다음과 같이 작성해 원하는 결과를 얻을 수 있습니다.
const { data } = await axios.get("/api/users");
console.log(data);

위와 같이 users 배열을 반환하고, 각 우리가 만든 shops 정보도 user 데이터 안에 있는 것을 확인할 수 있습니다.
const onPutClick = async () => {
await axios.put("/api/users", {
data: {
id: 2,
name: "Max Emil",
},
});
};
PUT 요청은 간단합니다. 프론트엔드에서 id:2, name: "Max Emil"을 제공하면 위 API에서 설계한 바와 같이 해당 id를 가진 user의 username이 바뀌게 됩니다.

const onDeleteClick = async () => {
await axios.delete("/api/users", {
data: {
id: 2,
},
});
};
DELETE 요청 역시 PUT 요청과 크게 다르지 않습니다. 해당하는 id의 user를 삭제합니다.

데이터가 잘 삭제된 것을 확인할 수 있습니다. 또한 저번 포스트에서 shops의 onDelete 옵션을 cascade로 주었기 때문에 user가 삭제됨에 따라 shop도 같이 삭제된 것을 확인 가능합니다.
이 포스트에서는 저번에 만든 REST api를 프론트엔드에서 어떻게 사용하는지에 대해 알아 봤습니다. 원래는 form을 이용해 직접 데이터를 DB에 넣고 수정하는 것 까지 하려 그랬는데 너무 복잡해져서 그만뒀습니다. react-hook-form까지 이용한다면 쉽게 여러 페이지를 만드실 수 있을겁니다.
코드 원본은 여기를 참고해 주시면 됩니다.