Notion API에 한 대 맞은 후기

pingu·2023년 11월 22일
3
post-thumbnail

약 2년전 노션에서 API를 공개했다.
노션에 데이터를 넣고 API를 통해 데이터를 주고 받을 수 있는 방식이다.
프로젝트나 포폴에 사용할 백엔드가 반드시 필요한 프론트엔드 개발자에겐 좋은 선택지가 더 생긴 셈이다.
NotionAPI를 활용한 포트폴리오 관련 영상도 많이 나오고 있어서 흥미가 생겼다.

일단 노션은 협업에서도 사용되고 개인 필기용으로도 많이 사용되는 서비스인데, NotionAPI는 DB 필요없이 노션 자체가 DB 역할을 하며 그 DB를 공개할 수 있다는 점에 있어서 굉장한 이점이 있다.

뭘 만들까?

그럼 이론상 엄청난 서비스이니 안써볼 수 없겠다.

노마드 코더 notionAPI 사용방법
개발하는 정대리 포폴 만들기
노션 API docs

위 자료를 참고하여 학습했다.

개인 블로그에 프로젝트 관련 탭을 하나 만들고 싶었는데, MD 파일을 로컬에 넣고 보여주는 방식을 이미 블로그로 쓰고 있는 상황이라 다른 방식으로 구현을 해보고 싶었는데 마침 잘 됐다.

포트폴리오 탭을 만들자


블로그 옆에 포트폴리오 탭을 하나 만들고 탭 안에 데이터는 모두 Notion API를 통해 데이터를 가져올 생각이다.

구현

데이터 추가

우선 노션에 데이터를 추가해줘야 한다.


노션에 카드를 만들고 하나씩 데이터를 넣어준다

데이터로 갖고 오고 싶은 부분은 프로퍼티를 추가해서 데이터를 넣어줄 수 있다.
난 커버 이미지, 스택, 프로젝트 소개, 이미지 등을 넣었다.

Notion API 연결 등록

데이터를 데이터베이스에 추가했으니 이제 API로 사용할 수 있도록 등록을 해야한다.
https://www.notion.so/ 에서 'View documentation'을 클릭해서 integration을 하나 만들자

Name 작명을 하고 넘어가면

Secret 키가 발급이 된다. 요건 나중에 잘 쓸거니 보관해두고 다음 내용은 기본값으로 만들어도 크게 상관없다.

다음 단계는 데이터를 읽기, 업데이트 등 어떻게 쓸지 기능 관련 탭과 public으로 할지 private 으로 할지 정하는 단계이다.


다 만들었으니 연결하러 가자

노션과 연결은 했지만 데이터베이스에 접근 하려면 ID가 또 필요하다.

아까 만든 데이터베이스를 새탭에서 열기를 클릭하면 새 탭이 열리는데,
이 탭의 query가 곧 database ID 이다

URL에서

https://www.notion.so/???

www.notion.so/ 뒤에 ???가 DatabaseID 이다.

데이터 불러오기

노션 공식문서 API Reference에 예시가 다 나와있으니 참고할 것.

일단 postman 에서 테스트를 해보자면

??? 는 아까 URL에서 찾은 데이터베이스 키이고 아래 토큰은 integration만들때 발급한 시크릿 키이다.

그리고 공식문서처럼 Notion-Version 을 꼭 넣어줘야 한다. 안하면 에러남

데이터 잘 나오는 것 확인.

코드에 적용하기

그대로 내 블로그 코드에 적용해보자

export async function getProjectData() {
  try {
    const response = await axios.post(
      `https://api.notion.com/v1/databases/${DATABASE_ID}/query`,
      {
        sorts: [
          {
            property: "Name",
            direction: "ascending",
          },
        ],
        page_size: 100,
      },
      {
        headers: {
          Accept: "application/json",
          "Notion-Version": "2022-06-28",
          "Content-Type": "application/json",
          Authorization: `Bearer ${TOKEN}`,
        },
      }
    );
    console.log(response);
    return { props: { data: response.data } };
  } catch (error) {
    console.error(error);
  }
}
export default async function Projects() {
  const data = await getProjectData();

  return (
    <MainContainer>
      <Title>Projects</Title>
      <ProjectContainer>
        {data && data.props.data.results.map((projectdata: any, index: number) => (
          <ProjectCard key={index} projectdata={projectdata} />
        ))}
      </ProjectContainer>
    </MainContainer>
  );
}
const ProjectCard = (projectdata: ProjectCardProps) => {
  const [isModalOpen, setIsModalOpen] = useState(false);

  console.log(projectdata.projectdata.properties.CoverImg.rich_text[0].href)

  return (
    <CardContainer>
      <CardImg
        src={projectdata.projectdata.properties.CoverImg.rich_text[0].href}
        alt="cover image"
        width={1000}
        height={1000}
        draggable={false}
      />
      <CardContents modalstate={`${isModalOpen}`}>
        <CardTitle>
          {projectdata.projectdata.properties.Name.title[0].plain_text}
        </CardTitle>
        <ProjectStack>
          {projectdata.projectdata.properties.Stack.multi_select.map((tag, index: number) => (
            <StackTag key={index}>{tag.name}</StackTag>
          ))}
        </ProjectStack>
        <ButtonContainer>
          <MoreButton onClick={() => setIsModalOpen(true)}>LEARN MORE</MoreButton>
          <Modal
            isModalOpen={isModalOpen}
            onClickCloseModal={() => {
              setIsModalOpen(false);
            }}
          >
            <ModalCardContents projectdata={projectdata.projectdata}></ModalCardContents>
          </Modal>
        </ButtonContainer>
      </CardContents>
    </CardContainer>
  )
}
export default ProjectCard;

데이터를 가져온 후에 조합해서 페이지를 꾸며보았다.

후기

생각보다 사용하기 편리하고 노션 데이터 get 요청 말고도 생성, 수정, 삭제 등 모두 가능하다고 하니 활용도가 어마무시할 것 같다. 역시 노션...?

뒷통수 한 대

역시 이렇게 쉽게 끝날리가 없지

개발 환경에선 별문제 없이 잘 동작하지만 문제는 배포환경에서 발생한다.

ㅋㅋㅋ...

배포한 후 어느정도 시간이 지나면 이미지들이 502 Bad Request를 응답하면서 로드되지 않는다.

심지어 왜 발생하는지 찾기도 어렵게 랜덤으로 발생하고 있다.

Vercel 배포 로그를 보면 이미지들이 어떤건 200 으로 잘 나오고 있고 다른 이미지는 502인 것을 확인할 수 있다.

이런 경우는 대체 뭐지...?

그래서 내가 생각한 원인들을 정리해 본다면

  1. Notion API 요청 제한이 있다?
  • 링크에 의하면, 초당 3건의 요청 제한이 있다고 한다. 근데 난 요청을 한번밖에 보내지 않는다
  1. Notion API 서버, 이미지 서버의 문제
  • 가장 유력
  1. next/Image 태그의 이미지 용량 크기로 인한 에러일 수 있다.
  • Postman 으로 확인해본 결과 이미지 URL은 문제없이 나오는 것을 확인함

노션이 이미지 서버를 관리하는데 있어서 용량 문제 때문에 일방적으로 정리는 하는건지 공개를 하지 않아서 도무지 감 잡기가 어렵다.

개발하는 정대리 포폴 만들기 유툽 포폴만들기 강의에서 직접 만든 배포파일도 502 에러가 발생하는건 물론이고

수강생이 만든 페이지까지 모조리 다 502 Bad Request 가 발생하고 있다... 다들 알고는 있을라나...?

https://github.com/makenotion/notion-sdk-js/issues/172
해당 이슈에 의하면, notion API 서버의 문제가 맞는 듯 하다. 예전에도 이런 일이 있었는데 해결되었다가 다시 발생한 듯? 하다.

https://www.reddit.com/r/Notion/comments/16opf3a/notion_api_502_error_not_in_the_documentation/
레딧에서도 다들 안된다고 짜증내는 중ㅋㅋㅋ

나와 똑같이 무작위로 문제가 발생하는 사람도 찾았다. 말은 안했을 뿐이지 다들 비슷한 문제일 것으로 추정된다.

스택오버플로우에 해결법이 몇개 올라와 있는데 모두 시도해봤지만 소용 없었다.
https://stackoverflow.com/questions/73292256/images-return-502-error-after-deploy-project-in-vercel
https://stackoverflow.com/questions/68879010/nextjs-image-component-502-error-in-server
https://community.make.com/t/notion-api-bad-gateway/16455

그래서 어떻게 해결하냐?

일단 문제가 notion API 사용시 이미지 서버가 말썽을 피우는 상황이니, 노션 인프라에 적용된 이미지 서버를 안쓰면 그만이잖아...?

이미지 URL을 잘 살펴보면
어차피 노션도 S3 Bucket을 통해서 이미지를 호스팅하는 것 같은데 이놈들 이미지 서버만 피해보자

  1. 이미지만 로컬에 따로 올려서 사용한다.
  2. 별도로 이미지 서버를 따로 호스팅해서 데이터베이스에 저장한다.

이미지를 로컬에 올리는건 안될 이유가 없으니 2번을 도전해보는게 좋지 않을까...?

별도 이미지 서버 운영하기

https://imgbb.com/ 같은 이미지만 호스팅할 수 있는 서비스에서 이미지만 올리고
호스팅된 URL 을 노션 데이터베이스에 이미지 파일 대신 올릴 것이다.

로그인 후에 이미지를 올리면 바로 사용이 가능하다.

노션에 파일을 삭제하고 링크만 올리고 API를 통해 클라이언트에선 문자열로 받으면 됨

성공!

뭔가 이미지 로그 속도가 더 빨라진 것 같기도 하고...?

한대 맞은 후기

Notion API 가 굉장히 좋은 서비스라는건 달라지지 않는 것 같다. 결국 이미지만 호스팅하지 않는다면 충분히 활용한 용도가 많다는 뜻이니까.

그래도 인프라에 대한 이해와 서버로그 보기, 코드 정적 분석 등 문제를 해결하기 위한 다양한 시도를 해봤다는 점에 있어서 재밌는 경험이였다고 생각한다.

그래도 가능하면 검증된 Firebase를 쓰는게 더 좋을 듯..ㅋㅋ

profile
코딩공부 리뷰

0개의 댓글