DEVELOP
article thumbnail

 

Next.js 14버전으로 포트폴리오를 제작하려고 한다. 

이번 기회에 Next.js 14를 차근차근 익히고 싶다.

포트폴리오는 내 개인 프로젝트이니까, 궁금했거나 하고 싶었던 기능이나 기술 들을 활용할 예정이다.

그 과정에서 겪는 것들을 블로그에 정리하면 좋을 것 같아서 글을 작성해보고자 한다. 


첫번째 게시글은 Notion api에 대한 글이다.

Notion을 DB처럼 쓸 수 있도록, Notion api를 사용해보겠다. 

평소 Notion을 항상 켜두며 작업할 정도로 자주 쓰는데 ,  Notion api가 있다는 것을 처음 알았다. 🙀

하드코딩으로 포트폴리오 내부 내용을 작성하기 보다는, 내가 변경하거나 추가하고 싶을 때 Notion에서만 직접 수정하면 되어서 이 방법을 선택하게 되었다. 

 

API 통합 생성하기

API 통합을 생성해야한다. https://www.notion.so/my-integrations

 

내 위키, 문서, 프로젝트를 모두 한 곳에서 만나는 커넥티드 워크스페이스 | Notion (노션)

사용하는 모든 업무 앱을 Notion 하나에 담아 팀원들과 함께하는 올인원 워크스페이스를 꾸려 보세요.

www.notion.so

 

들어가게 되면, 위와 같은 페이지가 뜬다. 나는 생성한 후에 캡쳐해버려서 하나가 이미 있는 상태인데,

어쨌거나 새 API 통합 만들기 버튼을 클릭해 새로 생성해주면 된다. 

딱히 설정할 것은 없다. api 통합 이름을 입력하고, 연결할 노션 워크스페이스를 설정해주면 끝이다.

로고는 필수가 아니므로, 패스하겠다.

 

노션에서 데이터베이스 생성

DB로 쓰고자하는 페이지를 생성하고, /데이터베이스 를 입력하면 데이터베이스를 생성할 수 있다.

 

처음에는 빈 표가 생성되는데, 나는 아래처럼 표의 내용을 채워주었다. 

 

API 연결하기

노션 창의 가장 오른쪽 위에 보면 메뉴 버튼(···)이 있는데, 그 버튼을 누르면, 아래 사진처럼 메뉴가 뜨고, 연결항목에서 나의 api 통합 이름을 검색한 후에 연결해주면 된다. 

Next js 14에서 Notion api 사용하기

@notionhq/client 설치

https://www.npmjs.com/package/@notionhq/client

yarn add @notionhq/client
or
npm install @notionhq/client

API KEY & DB ID 설정

먼저, API 키는 아까 생성한 API 통합에 들어가면, 시크릿 키가 있다. 해당 내용을 복사하기 !

 

DB ID는, 생성했던 데이터베이스의 메뉴 - 보기 링크 복사를 하면, 

 

아래와 같은 형식으로 주소가 복사된다. (임의의 값 넣은것임)

여기서 DB ID는 전체 주소가 아닌, www.notion.so/  뒤부터 ?v= 앞까지 있는 문자이다. 

 

 

이제 API KEY와 DB ID 값을 원하는 이름으로 .env (또는 .env.local)에 넣어준다. 

 

api 생성하기

src/app/api 폴더 내부에 요청할 때 쓸 주소 이름대로 폴더를 생성하고, route.ts 파일을 생성한다.

나는 요청 엔드포인트를 temp 로 하였기에 아래와 같이 폴더를 생성하고, route.ts 파일을 생성했다. 

해당 파일 첫 부분에, API KEY와, DB ID, 해당 API 키로 notion Client를 초기화하여 notion이라는 상수에 넣어준다. 

 

그리고 GET 함수를 정의하는데, 이때 notion.database.query에 DB ID를 넘겨준다. 

그 후 NextResponse.json(response)로 값을 리턴해준다. 

import { ProjectResult } from "@/types/api";
import { Project } from "@/types/model";
import { NextResponse } from "next/server";

const { Client } = require("@notionhq/client");

const NOTION_API_KEY = process.env.NOTION_API_KEY;
const NOTION_DB_ID = process.env.NOTION_TEMP_DB_ID;
const notion = new Client({ auth: NOTION_API_KEY });

export async function GET() {
  try {
    const response = await notion.databases.query({
      database_id: NOTION_DB_ID,
    });


    return NextResponse.json(response);
  } catch (error) {
    console.error(error);
  }
}

 

그러면 끝이다! 가 아니고, 노션에서 받아오는 데이터들이 엄청 복잡하게 넘어온다. 

그렇게 때문에 이 데이터들이 어떻게 생겼는지 파악을 한 뒤에, 해당 값들 중 사용하는 값만 추려서 가공하는 것이 좋다. 

 

그래서 포스트맨을 사용해서 값을 먼저 파악해보았다. 

대충봐도 엄청나게 복잡한 형태로 넘어오는데, 그 중에서 내가 사용할 값이 무엇인지 찾아내야한다. 

그래서 나는 필요한 값들을 모아 ProjectResult 라는 interface를 생성했다.

export interface ProjectResult {
  properties: {
    제목: {
      title: {
        text: {
          content: string;
        };
      }[];
    };
    부제목: {
      rich_text: {
        text: {
          content: string;
        };
      }[];
    };
    기간: {
      date: {
        start: string;
        end: string;
      };
    };
    기술스택: {
      multi_select: {
        name: string;
      }[];
    };
  };
}

그리고, 프론트에 응답으로 넘겨줄 Project 라는 interface를 정의했다. 

export interface Project {
  title: string;
  subTitle: string;
  period_end: string;
  period_start: string;
  stacks: string[];
}

위 설정들은 본인이 필요한 값을 찾아 골라서 보낼 수 있도록 설정해야한다.

 

그리고 나서 아래와 같이  값을 가공해서 리턴한다. 

export async function GET() {
  try {
    const response = await notion.databases.query({
      database_id: NOTION_DB_ID,
    });

    const data: Project[] = response.results.map((item: ProjectResult) => {
      return {
        title: item.properties.제목.title[0].text.content,
        subTitle: item.properties.부제목.rich_text[0].text.content,
        period_end: item.properties.기간.date.end,
        period_start: item.properties.기간.date.start,
        stacks: item.properties.기술스택.multi_select.map((s) => s.name),
      };
    });

    return NextResponse.json(data);
  } catch (error) {
    console.error(error);
  }
}

 

api 요청하기

이제 생성한 api를 요청해야한다.

기본 페이지인 Home 에서 시험삼아 해보도록 하겠다.

 

화면에 해당 내용을 띄우기 위해, state 를 생성 (project) 하고, 타입은 위에서 정의한 Project 타입으로 지정한다.

fetch할 주소는 본인이 생성했던 폴더의 구조에 맞게 적어주면 된다.

response를 setProject로 넘겨준다. 

import { Project } from "@/types/model";
import { useEffect, useState } from "react";

const Home = () => {
  const [project, setProject] = useState<Project[]>(); // 받아온 데이터를 화면에 뿌리기 위한 state

  const fetchProject = async () => {
    try {
    // fetch 주소 -> 생성한 폴더의 이름 
      const response = await fetch("/api/temp", {
        headers: {
          Accept: "application/json",
          method: "GET",
        },
      });
      if (response) {
        const data = await response.json();
        setProject(data);
      }
    } catch {}
  };

// 최초 한번만 fetch가 되도록 useEffect 사용 
  useEffect(() => {
    fetchProject();
  }, []);

 

콘솔에 project를 찍었을 때 잘 나오면 성공이다.! 

결과

이제 화면을 구성하면 되며, 임의로 아래와 같이 구성해보았다. 

  return (
    <div>
      {project &&
        project.map((item) => (
          <div key={item.title} className="p-2">
            <p>{item.title}</p>
            <p>{item.subTitle}</p>
            <p>
              {item.period_start} ~ {item.period_end}
            </p>
            <p>
              {item.stacks.map((stack) => (
                <span key={item + stack} className="mr-2 bg-orange-300">
                  {stack}
                </span>
              ))}
            </p>
          </div>
        ))}
    </div>
  );

 


DB없이 작은 프로젝트를 할 때, 변경될 수도 있는 값일때 노션 api를 사용하면 좋을 것 같다! 

'STUDY' 카테고리의 다른 글

라즈베리파이 스마트미러 구현 (매직미러 x, 웹 구현)  (0) 2023.11.20
profile

DEVELOP

@JUNGY00N