계기도입 전 고민관계형과 롤업양방향 연결 이유과정노션 DB 생성기존 포스트 DB 와 포스트 시리즈 DB 연결Notion API 를 통한 데이터 조회포스트 상세 페이지에 데이터 조회 함수 적용포스트 시리즈 컴포넌트 생성포스트 상세 컴포넌트에 시리즈 컴포넌트 적용유의 사항이슈 사항해결결과
해당 문서는 react-notion-x 와 notion API 가 적용된 환경을 기준으로 설명하고 있습니다.
계기
얼마 전, 블로그 리팩토링 관련 작업 회고 글을 4개의 주제로 나눠서 작성하였다.
하나의 문서에 작성해도 되지만 아직 글 쓰는 실력이 부족해서인지 몰라도 하나의 문서에 전부 담아서 작성하려니 글이 너무 중구난방 해질 것 같기도 했고 개인적으로는 글이 너무 길어지는 것을 좋아하지 않아 나눠서 작성하였다.
이로 인해 포스트가 4개가 생겼는데 나중에 보니까 ‘블로그 리팩토링’이라는 공통적인 주제로 묶여있는 것이 시각적으로 보이지 않아 서로 관련이 없는 포스트처럼 보였다.
이 문제를 어떻게 해결할 수 있을까 고민하다가 velog 에 있는 시리즈 기능을 도입하면 좋겠다는 생각이 들어 도입을 해보기로 하였다.
도입 전 고민
초반에는 현재 이미지를 관리하고 있는 supabase 에서 데이터베이스 기능을 활용하여 개발을 진행하려고 했는데 기존에 노션을 CMS 로 사용하고 있는 상황에서 컨텐츠 관련 사항(시리즈)을 노션 외부인 supabase 에서 관리하게 되면 유지보수가 번거로워질 것이라고 생각했다.
유지보수가 번거로워지는 상황은 ‘확인’과 ‘변경’ 시 존재한다.
- 특정 시리즈에 어떤 포스트가 있는지 확인하려는 경우
이 경우 먼저 시리즈 정보를 확인하기 위해 supabase 를 확인 후 확인한 시리즈 내부의 포스트 id 를 바탕으로 노션에서 해당 포스트가 어떤 내용인지 확인해야한다.
- 특정 시리즈에 포스트를 추가 또는 변경하려는 경우
A 라는 시리즈에 B 라는 포스트를 추가하려는 경우, 먼저 A 시리즈에 추가하려는 B 포스트가 어떤 내용인지 확인하기 위해 노션을 확인해야 하고, 확인 후 A 시리즈에 추가하기 위해 supabase 의 데이터베이스에 포스트 id 를 바탕으로 데이터를 변경해야 한다.
이러한 문제점들로 인해 해당 방법을 최후의 수단으로 두고 최대한 노션 내부에서 기능을 구현할 방법을 찾기로 하였고, 찾던 중 예전에 개인적인 쇼핑 목록을 노션 데이터베이스로 관리할 때 사용했던 관계형과 롤업 기능을 사용하면 구현할 수 있지 않을까? 라는 생각이 들어 이를 활용해 보기로 하였다.
관계형과 롤업
예전에 만들었던 쇼핑 목록은 이런 형식으로 되어있다.
(개인적인 쇼핑 목록을 기반으로 형식만 비슷하게 해서 만들어봤다.)
이미지를 보면 2개의 데이터베이스를 통해 구매하려는 옷을 상위 카테고리와 옷 정보로 분류해서 관리하고 있다.
이 기능을 노션에서 제공하는 관계형과 롤업을 통해 구현할 수 있다.
관계형을 통해 서로 다른 데이터베이스를 연결할 수 있고, 롤업을 통해 연결된 데이터베이스의 특정 속성을 조회할 수 있게 된다. (이미지의 속성 영역에서 대각선 화살표 아이콘이 관계형 속성이고 돋보기 아이콘이 롤업 속성이다.)
연결 과정을 글로 설명하면 먼저 옷 정보 DB 에서 ‘관계형’ 속성을 통해 카테고리 DB 를 양방향으로 연결한다. 이로 인해 옷 정보 DB 에 ‘카테고리’ 속성이 생성되고 카테고리 DB 에 ‘옷 정보’ 속성이 생성된다. 이후 옷 정보 DB 에 있는 아이템의 ‘카테고리’ 속성을 클릭하면 카테고리 DB 의 아이템(상의, 하의 등)을 적용할 수 있게 되고 적용이 되면 카테고리 DB 의 ‘옷 정보’ 속성에도 함께 적용된다.
이 과정을 바탕으로 포스트 시리즈 기능을 구현하기 위한 노션 세팅을 진행할 건데 여기서 하나 짚고 넘어가면 좋은 부분이 있다.
양방향 연결 이유
노션에서 관계형을 적용할 때 기본값은 단방향이지만 포스트 시리즈에 대한 데이터베이스 설정 시 예시와 같이 관계형을 양방향으로 설정해 줘야 한다.
그 이유는 포스트 시리즈를 구현할 때 포스트 상세 페이지에 보여주는 방향으로 진행할 건데 이때 포스트 상세 페이지의 정보(
postId
)를 바탕으로 시리즈 제목과 시리즈에 속한 포스트 리스트를 조회해야하기 때문에 양방향으로 적용하여 포스트 시리즈 DB 뿐만 아니라 기존 포스트 DB 에서도 해당 정보를 보여줘야 한다.과정
설명을 위해 코드를 요약해서 작성하였습니다. 전체 코드는 레포지토리에서 확인 가능합니다.
노션 DB 생성
포스트 시리즈를 관리하기 위해 노션에서 새 데이터베이스를 생성한다. (이름은 ‘포스트 시리즈’)
기존 포스트 DB 와 포스트 시리즈 DB 연결
기존 포스트 데이터베이스와 새로 생성한 ‘포스트 시리즈’ 데이터베이스를 관계형, 롤업을 통해 연결해 준다.
연결된 2개의 데이터베이스는 이런 구조로 보여진다.
Notion API 를 통한 데이터 조회
Notion API 를 통해 특정 포스트의 ID 값을 바탕으로 특정 포스트가 속한 시리즈의 제목과 해당 시리즈에 속해 있는 포스트 리스트 정보를 조회할 수 있다.
전체적인 과정은 다음과 같다.
‘관계형’, ‘롤업’ 속성 ID 는 기존 포스트 데이터베이스를 데이터베이스 정보를 조회하는 Notion API 를 통해 확인할 수 있고, 페이지 속성 검색은 페이지의 속성을 조회하는 Notion API 로 할 수 있다.
해당 과정을 시리즈 조회 기능을 담당하는
getPageSeries
함수와 Notion API 를 통해 데이터를 조회하는 로직을 담당하는 PageSeries
클래스를 조합하여 단일 책임 원칙을 준수하는 방식으로 코드를 작성하였다.포스트 상세 페이지에 데이터 조회 함수 적용
현재 블로그 프로젝트에서는 SWR 을 통해 데이터를 관리하고 있어 기존 데이터 처리 방식을 그대로 사용하였다.
포스트 시리즈 컴포넌트 생성
포스트 상세 페이지에서 보여줄 시리즈 컴포넌트를 생성한다.
포스트 상세 컴포넌트에 시리즈 컴포넌트 적용
react-notion-x 라이브러리를 사용하는 경우
<NotionRenderer/>
컴포넌트를 사용할 텐데, 이때 components
라는 props 를 통해서 추가적인 설정을 할 수 있다.설정 중 상세 페이지의 속성(태그, 작성일 등)관련 메서드가 존재하는데, 이러한 메서드를 통해 위에서 만들었던 시리즈 컴포넌트를 적용할 수 있다.
propertyRelationValue()
는 관계형 속성 관련 메서드이다. 해당 메서드를 통해 관계형 속성이 표시되는 영역에 기존 관계형 데이터 정보를 시리즈 UI 컴포넌트로 대체하여 표시할 수 있다.유의 사항
포스트마다 시리즈가 존재하는 포스트도 있고 존재하지 않는 포스트도 있기 때문에 이에 대한 예외 처리를 꼭 적용해야 한다.
- 포스트가 존재하는 경우 (
results
값 데이터 존재)
- 포스트가 존재하지 않는 경우 (
results
값 빈 배열)
이슈 사항
해당 포스트에는 추가하지 않았지만, Notion API 를 통한 조회 로직과
NotionPageSeries
컴포넌트에 대한 테스트 코드도 작성하였는데 이 중 NotionPageSeries
컴포넌트에 대한 테스트 코드 작성 시 한 가지 이슈가 발생하였다.NotionPageSeries
컴포넌트는 시리즈에 속한 포스트 리스트에서 현재 접속한 포스트에 대해 active 스타일을 적용하게 되어있다. (e.g. 시리즈 내 포스트가 [1,2,3,4] 이고 현재 페이지가 3 인 경우, 시리즈 리스트에서 3에 active 스타일을 적용)이 기능에 대해 테스트 코드를 해당 과정으로 작성하였다.
- ‘목록 열기’ 버튼 클릭
- 첫 번째 아이템 링크 클릭 → 링크 이동
- 목록에서 첫 번째 아이템에 active 스타일이 적용되었는지 검증
해당 과정을 통해 검증을 시도했는데 첫 번째 아이템에 active 스타일이 적용되지 않는 이슈가 발생하였다.
해결
컴포넌트를 테스트할 때 링크 클릭 후 이동에 대한 테스트를 진행하기 위해서 next-router-mock 라이브러리를 적용하여 테스트를 진행하고 있다.
이때 포스트 시리즈 컴포넌트는 동적 라우팅 환경(포스트 상세 페이지)에서 사용하는데 이 경우 기존 테스트와 다른 방식으로 적용 후 테스트를 진행해야 한다.
해당 이슈의 원인은 올바르지 않은 링크 이동 처리(과정 2번)였고 이를 공식 문서를 참고하여 수정 후 테스트를 진행하니 정상적으로 active 스타일이 적용되는 것을 확인할 수 있었다.
결과
참고