React.js NextJS API (DB, http req)

강정우·2023년 2월 3일
0

next.js

목록 보기
3/9
post-thumbnail
post-custom-banner

insert

api 메서드 만들기

  • pages 밑에 반드시 api라는 이름으로 폴더를 만들어야 한다.
  • 파일 경로에 해당하는 url로 라우트에서 요청이 오면 그때 함수가 트리거 된다.
  • API 라우트는 서버에서만 돌아기 때문에 디코드해도 클라이언트에게 노출되지 않는다.
import {MongoClient} from "mongodb";

async function handler(req, res) {
    if(req.method === "POST"){
        const data = req.body;
        const client = await MongoClient.connect("몽고db에서 제공하는 url")
        const db = client.db();

        const meetupsCollection = db.collection("콜렉션이름");
        const result = await meetupsCollection.insertOne(data);
        console.log(result);
        client.close();

        res.status(201).json({messge:"성공적으로 삽입됨"});
    }
}

export default handler();
  • 요청 객체는 들어오는 요청에 관한 데이터를 포함하고 응답 객체는 응답을 보낼 때 필요하다.
    (위 코드는 편의상 편집함)

몽고 DB 연결하기

  • 몽고 DB을 예전 node.js 포스팅에 아주 잠깐 다룬적이 있다.
  1. 프리티어는 클러스터를 1개밖에 생성 못 한다.
  2. DB Access와 NetWork Access 설정
  • 빨간 네모 박스를 눌러 나오는 url을 설정하여 url 내부에 있는 query param을 기존에 설정한 DB Access에 맞춰 집어 넣어주면 된다.

front에서 가져다 쓰기

  • DB와 백엔드 API를 구축했으면 이제 front에서 작성한 api를 그냥 갖다 쓰기만 하면 된다.

예제 코드

const router = useRouter();
async function addMeetupHandler(enteredMeetupData) {
  const response = await fetch("/api/new-meetup",{			// 1.
    method:"POST",
    body: JSON.stringify(enteredMeetupData),
    headers:{
      "Content-Type":"application/json"
    }
  });
  const data = await response.json();
  router.replace("/");
}
return(
  <NewMeetupForm onAddMeetup={addMeetupHandler}/>			// 2.
)
  1. API 폴더에 있는 new-meetup js 파일로 request가 전송되고 여기의 function을 trigger 한다.
    그리고 request가 경로에 도달하면 NextJS가 이 function을 trigger 한다.

  2. NewMeetupForm에 있는 form에 맞춰 stringfy 하여 data를 따로 구조분해 없이 보내도 된다. 왜냐면 몽고DB는 기본적으로 JSON통신을 하니까

  • 2객의 객체가 이상없이 insert 된 것을 확인할 수 있다.

data 가져오기

export async function getStaticProps() {
    const data = fetch("/api/meetups")
    //fetch data from an API first then
    return {
        props:{
            meetups: data,
        },
        revalidate:3
    };
}
  • 이런식으로 fetch에서 가져온 data를 사용하면 얼마나 편할까 하지만 이는 API의 endpoint에 request를 보내는 것은 불필요하고 중복될 수도 있기 때문에 좋은 코드는 아니다.

  • 또한 getStaticProps함수 자체도 build 프로세스 때 실행되므로 클라이언트 사이드에서는 실행이 되지 않는다.
    따라서 모든 data를 불러오려면 API 경로에 request를 보낼 필요가 없고 바로 여기서 코드를 실행해야 한다는 것이다.
    그렇다면 드는 의문=> fetch에 어려 DB의 보안 정보들이 들어있는데 이를 클라이언트 사이드에서 실행하면 보안적으로 괜찮을 걸까?

  • 아주 훌륭한 질문이다.
    페이지 구성 요소 파일에서 항목을 import 하면 해당 import 항목은 getServerSide Props나 getStaticProps에서만 사용되는 경우 import 된 패키지는 클라이언트 측 번들에 포함되지 않는다. 이게 어떻게 가능할까?

  • NextJS가 이를 감지하여 클라이언트 측 번들에 포함시키지 않기 때문에 번들 크기뿐만 아니라 보안에도 유용하다!

  • 즉, 서버 측 코드와 클라이언트 측 코드를 모두 import 할 수 있고 사용하는 위치에 따라 서로 독립적인 다른 번들에 포함 된다. NextJS에 내장된 아주 훌륭한 기능이다.

export async function getStaticProps() {
    const client = await MongoClient.connect("몽고DBURL")
    const db = client.db();

    const meetupsCollection = db.collection("콜렉션이름");

    const meetupsAry = await meetupsCollection.find().toArray();

    client.close();

    return {
        props:{
            meetups: meetupsAry.map(meetup=>({
                title:meetup.title,
                address:meetup.address,
                image:meetup.image,
                id:meetup._id.toString()
            })),
        },
        revalidate:3
    };
}
  • 위 코드가 자주 쓰인다면 이것을 refactor하고 복사를 막기 위해 별도의 함수로 아웃소싱해주면 좋다.
  • 위 함수의 반환값을 props으로 가져가서 페이지 컴포넌트에 뿌려주면 된다.

    항상 주의해야할 점은 fetch 처럼 DB에서 값을 가져올 때 비동기로 처리하고 이때 반드시 await으로 promise 해주어야 한다!

특정 item 데이터 가져오기

export async function getStaticProps(context) {
    const meetupId = context.params.meetupId;
    const client = await MongoClient.connect("몽고DBURL")
    const db = client.db();
    const meetupsCollection = db.collection("콜렉션이름");
    const selectedMeetup = await meetupsCollection.findOne({ _id: ObjectId(meetupId) });
    client.close();

    return {
        props: {
            meetupData: {
                id: selectedMeetup._id.toString(),
                title: selectedMeetup.title,
                address: selectedMeetup.address,
                image: selectedMeetup.image,
                description: selectedMeetup.description
            }
        }
    }
}
profile
智(지)! 德(덕)! 體(체)!
post-custom-banner

0개의 댓글