본문 바로가기
Frontend

Next.js app router API Routes를 활용한 주문형 재검증

by dug_developer 2024. 8. 1.
반응형

사건의 발단

상사 : 제품 소개 페이지들을 만들자.

: 속으로 생각 중 ( 제품 소개 페이지들은 변경될 일이 거의 없으니까 SSG로 만들까? 근데 만약에 관리자 페이지에서 해당 제품 정보를 변경하면 어떡하지…? SSG는 프로젝트를 빌드한 시점에 페이지를 생성해서 변경되지 않잖아…)

: ISR로 캐싱시간을 10분? 1시간? 하루?를 줘서 페이지를 업데이트해주는 건 어떻게 생각하세요?

상사 : 만약에 그 10분, 1시간, 하루 사이에 중요한 정보가 바뀐다면 어떡할래? 책임질 수 있어?

: 어…그럼 사용자도 거의 없으니까… 그냥 요청마다… SSR하시죠… 캐싱하지 말죠… 하하하

 

(친구와 한풀이를 하며,,,)

 

: 오늘 이런 일이 있었다,,,

친구 : 어 그거 ISR on demand revalidation라고 검색해 봐

 

간단 단어 정리

SSG : 빌드 시점에 페이지를 생성해서 서버에서 갖고 있음.
SSR : 매요청마다 서버에서 페이지를 항상 렌더링 해서 사용자에게 제공함.
ISR : 특정 주기, 트리거에 의해서 서버에서 페이지를 렌더링해서 사용자에게 제공함.

 

주문형 재검증(On-Demand Revalidation)이란?

필요한 때에만 요청에 따라서 캐싱되어 있던 data를 최신의 상태로 변경할 수 있습니다.

그로 인해 사용자는 최신의 정보를 받을 수 있어서 사용자 경험 향상과 캐싱을 통해 서버의 부담 저하를 할 수 있습니다.

지금 우리는 AWS S3에 HTML을 올려둔 게 아니라 NextJS라는 서버에 HTML을 만들어놓은 거라서 업데이트를 할 수 있습니다.

즉, next.js의 SSG(static site generator)로 프로젝트 빌드 시에 생성된 웹 페이지의 경우 next.js 자체를 다시 빌드하지 않으면 해당 페이지가 업데이트되지 않지만, next.js는 서버로 동작하기 때문에 주문형 재검증을 사용하여 정적으로 만든 페이지를 다시 빌드하여 사용자에게 최신의 data를 지닌 페이지를 제공할 수 있습니다.

 

적용 원칙

  1. 사용자가 많이 이용하는 페이지.
  2. 자주 변경되지는 않지만 변경될 가능성이 있는 페이지.

이에 해당하는 페이지인 콘텐츠, 공지사항 페이지에만 적용하기로 함.

그러나, 전제는 서버의 성능을 위함이지만, 사용자들의 유입 정도코드의 유지보수 측면을 고려하여 적용해 주는 것이 좋을 것 같습니다.

revalidateTag

  • tag를 지정해서 해당 태그를 사용하여 Next.js의 api를 호출하여 알릴 수 있습니다.
1. SSG로 페이지 만들기
// src/app/content/[contentId]/page.tsx

export default async function page(params) {
  const res = await fetch('https://...', { cache: 'force-cache', next: { tags: [params.contentId] } })
  const data = await res.json()
  // ...
}

 

2. Next.js API Routes를 사용하여 API 만들기

  • API Routes는 간단히 설명하자면, next.js의 특정 페이지 경로에 HTTP 요청을 보낼 수 있는 것입니다. (그냥 백엔드 API 구현하는 거랑 같다고 생각하시면 됩니다)
  • 백엔드가 Next.js가 나눠져 있기 때문에 백엔드 서버에서 Next.js API를 호출해줘야 해서 API Routes를 생성하였습니다.
    • 백엔드도 Next.js에서 구현했다면 이 api는 만들 필요가 없었음.
    • POST “도메인/api/rebuild"에 body에 {rebuildUrl : 바꿀 TAG}를 실어서 요청하면 됨.
// src/app/api/rebuild/route.ts

import { revalidateTag } from 'next/cache';
import { NextRequest, NextResponse } from 'next/server';

export async function POST(request: NextRequest) {
  const { rebuildUrl } = await request.json();

  revalidateTag(rebuildUrl);

  return NextResponse.json({ revalidated: true, now: Date.now() });
}

도중에 만난 이슈

  1. body 값 이상함.
    원인 : request 변수에 await 안 해서 그럼
  2. 로컬에서 테스트 시 빌드된 페이지가 캐싱되어 있음.
    1. SSG로 해당 페이지 빌드생성 했음. (페이지 제목 : 김치)
    2. 해당 페이지의 data를 서버에서 변경함 (페이지 제목 : 김치찌개)
    3. next.js에서 빌드 다시 함 (npm run build)
    4. 해당 페이지는 변경 전 상태인 (페이지 제목 : 김치)인 상태
    로컬에서 빌드했기 때문에 문제가 있었던 것 같음 이미 생성된 정적 페이지가 업데이트되지 않았다, .next 폴더를 삭제하고 빌드하면 아무런 문제가 없음, 실제 운영과 테스트 서버에서는 git clone으로 덮어쓰니까 운영할 땐 상관없을 이슈다.
  3. Nextjs revalidatePath not working
    • 관련 이슈 : https://github.com/vercel/next.js/issues/49387  
    • 처음에는 revalidatePath 메서드를 사용하여 구현하였는데 재빌드 되지 않았다,,, 찾아보니 동적경로를 재빌드가 잘되지 않는다는 버그가 발견되었고 2023년에 생긴 이슈가 아직 해결되지 않아서… revalidateTag로 변경하였음.
  4. POST인가 GET인가
    • RESTful API를 하려면 멱등성을 지켜야 하기 때문에 POST 요청은 DB의 data가 바뀌거나 하는 거고 GET은 DB가 바뀌지 않고 조회만 해야 RESTFul 한 것이라 판단하였고 또한 GET을 사용하여 query string으로 요청하는 경우에는 data의 길이가 길어지는 것도 고심해야 해서 POST로 API를 생성하였다.
    • 지금은 페이지를 리빌드를 해야 해서 변경이니깐 POST가 맞다는 의견!

Reference

https://nextjs.org/docs/app/building-your-application/data-fetching/fetching-caching-and-revalidating#on-demand-revalidation

https://nextjs.org/docs/app/building-your-application/routing

https://nextjs.org/docs/app/building-your-application/data-fetching/fetching-caching-and-revalidating

반응형

'Frontend' 카테고리의 다른 글

styled-component로 GlobalStyle 정의하기  (0) 2023.04.04
디바운싱과 쓰로틀링  (0) 2022.11.26
Next.js 쓰면 SSR 하고 있는거 아님?  (2) 2022.11.18
프론트엔드 면접 경험  (0) 2022.11.16
[JS] this란?  (0) 2022.08.23