본문 바로가기
nestJS

NestJS | Pagination 페이지네이션

by 리잼 2024. 8. 22.
반응형

이전에 회사에서 외주 프로젝트를 진행할 때 뉴스 정보를 페이지 네이션으로 구현했었다.

 

내가 구현한 로직

const [currentPage, setCurrentPage] = useState(1);
const itemsPerPage = 5;
const totalPages = Math.ceil(mainData.length / itemsPerPage);
const currentData = mainData.slice((currentPage - 1) * itemsPerPage, currentPage * itemsPerPage);

// 첫번째 페이지로 이동
// window.scrollTo(0,0) : 화면 가장 상단으로 이동
const handleFirstPage = () => {
  window.scrollTo(0, 0);
  setCurrentPage(1);
};
// 이전 페이지로 이동 최소 값은 1
const handlePrevPage = () => {
  window.scrollTo(0, 0);
  setCurrentPage((prev) => Math.max(prev - 1, 1));
};
// 다음 페이지로 이동 최대 값은 totalPage값
const handleNextPage = () => {
  window.scrollTo(0, 0);
  setCurrentPage((prev) => Math.min(prev + 1, totalPages));
};
// 마지막 페이지로 이동
const handleLastPage = () => {
  window.scrollTo(0, 0);
  setCurrentPage(totalPages);
};
  • currentPage : 현재 페이지를 저장하고 초기값 1로 설정
  • itemPerPage : 한 페이지에 표시할 아이템 수를 설정
  • totalPages : 전체 페이지 수를 계산, mainData에 담긴 값을 itemPerPage로 나누고 반올림
  • currentData : mainData를 slice 함수로 보여줄 페이지 계산 ex ( page 1 : index(0-4), page 2 : index(5-9) ~ )

 

이렇게 비교적 간단하게 구현했었는데

새로 듣는 강의에서 좀 더 나은 방법이 있다고 하여 다시 정리해보려고 한다


Pagination

Pagination 이란?

많은 데이터를 부분적으로 나눠서 불러오는 기술이다

Pagination의 특징

  • 쿼리에 해당되는 모든 데이터를 한번에 불러오지 않고, 부분적으로 쪼개서 불러온다.
  • 쿠팡 같은 앱의 경우 수억개의 상품이 데이터베이스에 저장되어 있는데, 사용자가 상품 검색 화면을 들어갈 때마다 모든 상품정보를 서버에서 클라이언트로 전송할 필요가 없다
  • 현대 클라우드 시스템은 데이터 전송에 돈이 든다
  • 돈이 안들더라도 수억개의 데이터를 한번에 보내면 메모리가 터지고 말 것이다
  • 메모리가 터지지 않더라도 데이터 전송에 굉장한 시간이 걸릴 것이다.

Page Based Pagination

  • 페이지 기준으로 데이터를 잘라서 요청하는 페이지네이션
  • 요청을 보낼 . 때원하는 데이터 갯수와 몇번 째 페이지를 가져올지 명시
  • 페이지 숫자를 누르면 다음 페이지로 넘어가는 형태의 UI에서 사용
  • 페이지네이션 도중에 데이터베이스에서 데이터가 추가되거나 삭제될 경우 저장되는 데이터가 누락되거나 중복될 수 있음
  • 페이지네이션 알고리즘이 매우 간단함

Cursor Based Pagination

  • 가장 최근에 가져온 데이터를 기준으로 다음 데이터를 가져오는 Pagination
  • 요청시 보낼 때 마지막 데이터의 기준값( ID, Unique 값 ) 과 몇개의 데이터를 가져올지 명시
  • 스크롤 형태의 리스트에서 자주 사용
  • 최근 데이터의 기준값을 기반으로 쿼리가 작성되기 때문에 데이터가 누락되거나 중복될 확률이 적음

구현 코드

posts.controller.ts
@Get()
  getPosts(@Query() query: PaginatePostDto) {
    return this.postsService.paginatePosts(query);
  }
posts.service.ts
async paginatePosts(dto: PaginatePostDto) {
    if (dto.page) {
      return this.pagePaginatePosts(dto);
    } else {
      return this.cursorPaginatePosts(dto);
    }
  }

  async pagePaginatePosts(dto: PaginatePostDto) {
    /*
    data: Data[],
    total: number,

    [1],[2],[3],[4]
     */
    const [posts, count] = await this.postsRepository.findAndCount({
      skip: dto.take * (dto.page - 1),
      take: dto.take,
      order: {
        createdAt: dto.order__createdAt,
      },
    });

    return {
      data: posts,
      total: count,
    };
  }

  async cursorPaginatePosts(dto: PaginatePostDto) {
    const where: FindOptionsWhere<PostsModel> = {};
    if (dto.where__id_less_than) {
      where.id = LessThan(dto.where__id_less_than);
    } else if (dto.where__id_more_than) {
      where.id = MoreThan(dto.where__id_more_than);
    }
    // 1, 2, 3, 4, 5
    const posts = await this.postsRepository.find({
      where,
      // order__createdAt
      order: {
        createdAt: dto.order__createdAt,
      },
      take: dto.take,
    });

    // 해당되는 포스트가 0개 이상이면
    // 마지막 포스트를 가져오고
    // 아니면 null을 반환
    const lastItem = posts.length > 0 && posts.length === dto.take ? posts[posts.length - 1] : null;

    const nextUrl = lastItem && new URL(`${PROTOCOL}://${HOST}/posts`);
    if (nextUrl) {
      /*
      DTO 의 키값들을 루핑하면서
      키값에 해당되는 벨류가 존재하면
      param에 그대로 붙여넣는다.

      단 where__id_more_than 값만 lastItem의 마지막 값으로 넣어준다.
       */
      for (const key of Object.keys(dto)) {
        if (dto[key]) {
          if (key !== 'where__id_more_than' && key !== 'where__id_less_than') {
            nextUrl.searchParams.append(key, dto[key]);
          }
        }
      }
      let key = null;
      if (dto.order__createdAt === 'ASC') {
        key = 'where__id_more_than';
      } else {
        key = 'where__id_less_than';
      }

      nextUrl.searchParams.append(key, lastItem.id.toString());
    }
    /*
    Response

    data : Data[],
    cursor: {
      after: 마지막 데이터의 ID
    },
    count: 응답한 데이터의 갯수
    next: 다음 요청을 할 때 사용할 URL
     */
    return {
      data: posts,
      cursor: {
        after: lastItem?.id ?? null,
      },
      count: posts.length,
      next: nextUrl?.toString() ?? null,
    };
  }
paginte-post.dto.ts
import { IsIn, IsNumber, IsOptional } from 'class-validator';
import { Type } from 'class-transformer';

export class PaginatePostDto {
  @IsNumber()
  @IsOptional()
  page?: number;

  @IsNumber()
  @IsOptional()
  where__id_less_than?: number;
  // 이전 마지막 데이터의 ID
  // 이 프로퍼티에 입력된 ID 보다 높은 ID 부터 값을 가져오기
  @IsNumber()
  @IsOptional()
  where__id_more_than?: number;

  // 10, 9, 8, 7

  // 정렬
  // createdAt -> 생성된 시간의 내림차/오름차 설정
  @IsIn(['ASC', 'DESC'])
  @IsOptional()
  order__createdAt: 'ASC' | 'DESC' = 'ASC';

  // 몇개의 데이터를 가져올지
  @IsNumber()
  @IsOptional()
  take: number = 20;
}
Postman 테스트 결과 
Page Based Pagination / 첫번 째 장, 마지막 장

page key 값이 들어감

{
    "data": [
        {
            "id": 110,
            "updatedAt": "2024-08-21T20:13:15.400Z",
            "createdAt": "2024-08-21T20:13:15.400Z",
            "title": "임의로 생성된 제목 99",
            "content": "임의로 생성된 콘텐츠 99",
            "likeCount": 0,
            "commentCount": 0
        },
        {
            "id": 109,
            "updatedAt": "2024-08-21T20:13:15.397Z",
            "createdAt": "2024-08-21T20:13:15.397Z",
            "title": "임의로 생성된 제목 98",
            "content": "임의로 생성된 콘텐츠 98",
            "likeCount": 0,
            "commentCount": 0
        },
        {
            "id": 108,
            "updatedAt": "2024-08-21T20:13:15.394Z",
            "createdAt": "2024-08-21T20:13:15.394Z",
            "title": "임의로 생성된 제목 97",
            "content": "임의로 생성된 콘텐츠 97",
            "likeCount": 0,
            "commentCount": 0
        },
        {
            "id": 107,
            "updatedAt": "2024-08-21T20:13:15.393Z",
            "createdAt": "2024-08-21T20:13:15.393Z",
            "title": "임의로 생성된 제목 96",
            "content": "임의로 생성된 콘텐츠 96",
            "likeCount": 0,
            "commentCount": 0
        },
        {
            "id": 106,
            "updatedAt": "2024-08-21T20:13:15.390Z",
            "createdAt": "2024-08-21T20:13:15.390Z",
            "title": "임의로 생성된 제목 95",
            "content": "임의로 생성된 콘텐츠 95",
            "likeCount": 0,
            "commentCount": 0
        },
        {
            "id": 105,
            "updatedAt": "2024-08-21T20:13:15.389Z",
            "createdAt": "2024-08-21T20:13:15.389Z",
            "title": "임의로 생성된 제목 94",
            "content": "임의로 생성된 콘텐츠 94",
            "likeCount": 0,
            "commentCount": 0
        },
        {
            "id": 104,
            "updatedAt": "2024-08-21T20:13:15.387Z",
            "createdAt": "2024-08-21T20:13:15.387Z",
            "title": "임의로 생성된 제목 93",
            "content": "임의로 생성된 콘텐츠 93",
            "likeCount": 0,
            "commentCount": 0
        },
        {
            "id": 103,
            "updatedAt": "2024-08-21T20:13:15.385Z",
            "createdAt": "2024-08-21T20:13:15.385Z",
            "title": "임의로 생성된 제목 92",
            "content": "임의로 생성된 콘텐츠 92",
            "likeCount": 0,
            "commentCount": 0
        },
        {
            "id": 102,
            "updatedAt": "2024-08-21T20:13:15.384Z",
            "createdAt": "2024-08-21T20:13:15.384Z",
            "title": "임의로 생성된 제목 91",
            "content": "임의로 생성된 콘텐츠 91",
            "likeCount": 0,
            "commentCount": 0
        },
        {
            "id": 101,
            "updatedAt": "2024-08-21T20:13:15.383Z",
            "createdAt": "2024-08-21T20:13:15.383Z",
            "title": "임의로 생성된 제목 90",
            "content": "임의로 생성된 콘텐츠 90",
            "likeCount": 0,
            "commentCount": 0
        },
        {
            "id": 100,
            "updatedAt": "2024-08-21T20:13:15.382Z",
            "createdAt": "2024-08-21T20:13:15.382Z",
            "title": "임의로 생성된 제목 89",
            "content": "임의로 생성된 콘텐츠 89",
            "likeCount": 0,
            "commentCount": 0
        },
        {
            "id": 99,
            "updatedAt": "2024-08-21T20:13:15.381Z",
            "createdAt": "2024-08-21T20:13:15.381Z",
            "title": "임의로 생성된 제목 88",
            "content": "임의로 생성된 콘텐츠 88",
            "likeCount": 0,
            "commentCount": 0
        },
        {
            "id": 98,
            "updatedAt": "2024-08-21T20:13:15.379Z",
            "createdAt": "2024-08-21T20:13:15.379Z",
            "title": "임의로 생성된 제목 87",
            "content": "임의로 생성된 콘텐츠 87",
            "likeCount": 0,
            "commentCount": 0
        },
        {
            "id": 97,
            "updatedAt": "2024-08-21T20:13:15.377Z",
            "createdAt": "2024-08-21T20:13:15.377Z",
            "title": "임의로 생성된 제목 86",
            "content": "임의로 생성된 콘텐츠 86",
            "likeCount": 0,
            "commentCount": 0
        },
        {
            "id": 96,
            "updatedAt": "2024-08-21T20:13:15.376Z",
            "createdAt": "2024-08-21T20:13:15.376Z",
            "title": "임의로 생성된 제목 85",
            "content": "임의로 생성된 콘텐츠 85",
            "likeCount": 0,
            "commentCount": 0
        },
        {
            "id": 95,
            "updatedAt": "2024-08-21T20:13:15.374Z",
            "createdAt": "2024-08-21T20:13:15.374Z",
            "title": "임의로 생성된 제목 84",
            "content": "임의로 생성된 콘텐츠 84",
            "likeCount": 0,
            "commentCount": 0
        },
        {
            "id": 94,
            "updatedAt": "2024-08-21T20:13:15.372Z",
            "createdAt": "2024-08-21T20:13:15.372Z",
            "title": "임의로 생성된 제목 83",
            "content": "임의로 생성된 콘텐츠 83",
            "likeCount": 0,
            "commentCount": 0
        },
        {
            "id": 93,
            "updatedAt": "2024-08-21T20:13:15.371Z",
            "createdAt": "2024-08-21T20:13:15.371Z",
            "title": "임의로 생성된 제목 82",
            "content": "임의로 생성된 콘텐츠 82",
            "likeCount": 0,
            "commentCount": 0
        },
        {
            "id": 92,
            "updatedAt": "2024-08-21T20:13:15.368Z",
            "createdAt": "2024-08-21T20:13:15.368Z",
            "title": "임의로 생성된 제목 81",
            "content": "임의로 생성된 콘텐츠 81",
            "likeCount": 0,
            "commentCount": 0
        },
        {
            "id": 91,
            "updatedAt": "2024-08-21T20:13:15.364Z",
            "createdAt": "2024-08-21T20:13:15.364Z",
            "title": "임의로 생성된 제목 80",
            "content": "임의로 생성된 콘텐츠 80",
            "likeCount": 0,
            "commentCount": 0
        }
    ],
    "count": 20,
    "total": 109
}

{
    "data": [
        {
            "id": 10,
            "updatedAt": "2024-08-19T23:10:54.092Z",
            "createdAt": "2024-08-19T22:57:10.364Z",
            "title": "PUT_TITLE2",
            "content": "TEST_CONTENT2ss",
            "likeCount": 0,
            "commentCount": 0
        },
        {
            "id": 9,
            "updatedAt": "2024-08-19T22:47:47.432Z",
            "createdAt": "2024-08-19T22:47:47.432Z",
            "title": "1",
            "content": "TEST_CONTENT2ss",
            "likeCount": 0,
            "commentCount": 0
        },
        {
            "id": 8,
            "updatedAt": "2024-08-19T22:46:48.027Z",
            "createdAt": "2024-08-19T22:46:48.027Z",
            "title": "TEST_TITLE2?",
            "content": "TEST_CONTENT2ss",
            "likeCount": 0,
            "commentCount": 0
        },
        {
            "id": 7,
            "updatedAt": "2024-08-19T21:29:34.864Z",
            "createdAt": "2024-08-19T21:29:34.864Z",
            "title": "TEST_TITLE2",
            "content": "TEST_CONTENT2",
            "likeCount": 0,
            "commentCount": 0
        },
        {
            "id": 6,
            "updatedAt": "2024-08-19T21:05:11.319Z",
            "createdAt": "2024-08-19T21:05:11.319Z",
            "title": "TEST_TITLE2",
            "content": "TEST_CONTENT2",
            "likeCount": 0,
            "commentCount": 0
        },
        {
            "id": 5,
            "updatedAt": "2024-08-19T21:03:42.197Z",
            "createdAt": "2024-08-19T21:03:42.197Z",
            "title": "TEST_TITLE2",
            "content": "TEST_CONTENT2",
            "likeCount": 0,
            "commentCount": 0
        },
        {
            "id": 4,
            "updatedAt": "2024-08-19T20:59:01.795Z",
            "createdAt": "2024-08-19T20:59:01.795Z",
            "title": "TEST_TITLE2",
            "content": "TEST_CONTENT2",
            "likeCount": 0,
            "commentCount": 0
        },
        {
            "id": 3,
            "updatedAt": "2024-08-19T23:07:37.283Z",
            "createdAt": "2024-08-19T20:47:45.996Z",
            "title": "PUT_TITLE3",
            "content": "TEST_CONTENT2",
            "likeCount": 0,
            "commentCount": 0
        },
        {
            "id": 1,
            "updatedAt": "2024-08-19T20:44:12.127Z",
            "createdAt": "2024-08-19T20:44:12.127Z",
            "title": "TEST_TITLE2",
            "content": "TEST_CONTENT2",
            "likeCount": 0,
            "commentCount": 0
        }
    ],
    "count": 9,
    "total": 109
}
Postman 테스트 결과 
Cursor Based Pagination / 첫번 째 장, 마지막 장

Page Based 와는 달리 쿼리스트링을 제외함

{
    "data": [
        {
            "id": 1,
            "updatedAt": "2024-08-19T20:44:12.127Z",
            "createdAt": "2024-08-19T20:44:12.127Z",
            "title": "TEST_TITLE2",
            "content": "TEST_CONTENT2",
            "likeCount": 0,
            "commentCount": 0
        },
        {
            "id": 3,
            "updatedAt": "2024-08-19T23:07:37.283Z",
            "createdAt": "2024-08-19T20:47:45.996Z",
            "title": "PUT_TITLE3",
            "content": "TEST_CONTENT2",
            "likeCount": 0,
            "commentCount": 0
        },
        {
            "id": 4,
            "updatedAt": "2024-08-19T20:59:01.795Z",
            "createdAt": "2024-08-19T20:59:01.795Z",
            "title": "TEST_TITLE2",
            "content": "TEST_CONTENT2",
            "likeCount": 0,
            "commentCount": 0
        },
        {
            "id": 5,
            "updatedAt": "2024-08-19T21:03:42.197Z",
            "createdAt": "2024-08-19T21:03:42.197Z",
            "title": "TEST_TITLE2",
            "content": "TEST_CONTENT2",
            "likeCount": 0,
            "commentCount": 0
        },
        {
            "id": 6,
            "updatedAt": "2024-08-19T21:05:11.319Z",
            "createdAt": "2024-08-19T21:05:11.319Z",
            "title": "TEST_TITLE2",
            "content": "TEST_CONTENT2",
            "likeCount": 0,
            "commentCount": 0
        },
        {
            "id": 7,
            "updatedAt": "2024-08-19T21:29:34.864Z",
            "createdAt": "2024-08-19T21:29:34.864Z",
            "title": "TEST_TITLE2",
            "content": "TEST_CONTENT2",
            "likeCount": 0,
            "commentCount": 0
        },
        {
            "id": 8,
            "updatedAt": "2024-08-19T22:46:48.027Z",
            "createdAt": "2024-08-19T22:46:48.027Z",
            "title": "TEST_TITLE2?",
            "content": "TEST_CONTENT2ss",
            "likeCount": 0,
            "commentCount": 0
        },
        {
            "id": 9,
            "updatedAt": "2024-08-19T22:47:47.432Z",
            "createdAt": "2024-08-19T22:47:47.432Z",
            "title": "1",
            "content": "TEST_CONTENT2ss",
            "likeCount": 0,
            "commentCount": 0
        },
        {
            "id": 10,
            "updatedAt": "2024-08-19T23:10:54.092Z",
            "createdAt": "2024-08-19T22:57:10.364Z",
            "title": "PUT_TITLE2",
            "content": "TEST_CONTENT2ss",
            "likeCount": 0,
            "commentCount": 0
        },
        {
            "id": 11,
            "updatedAt": "2024-08-21T20:13:15.108Z",
            "createdAt": "2024-08-21T20:13:15.108Z",
            "title": "임의로 생성된 제목 0",
            "content": "임의로 생성된 콘텐츠 0",
            "likeCount": 0,
            "commentCount": 0
        },
        {
            "id": 12,
            "updatedAt": "2024-08-21T20:13:15.118Z",
            "createdAt": "2024-08-21T20:13:15.118Z",
            "title": "임의로 생성된 제목 1",
            "content": "임의로 생성된 콘텐츠 1",
            "likeCount": 0,
            "commentCount": 0
        },
        {
            "id": 13,
            "updatedAt": "2024-08-21T20:13:15.123Z",
            "createdAt": "2024-08-21T20:13:15.123Z",
            "title": "임의로 생성된 제목 2",
            "content": "임의로 생성된 콘텐츠 2",
            "likeCount": 0,
            "commentCount": 0
        },
        {
            "id": 14,
            "updatedAt": "2024-08-21T20:13:15.126Z",
            "createdAt": "2024-08-21T20:13:15.126Z",
            "title": "임의로 생성된 제목 3",
            "content": "임의로 생성된 콘텐츠 3",
            "likeCount": 0,
            "commentCount": 0
        },
        {
            "id": 15,
            "updatedAt": "2024-08-21T20:13:15.130Z",
            "createdAt": "2024-08-21T20:13:15.130Z",
            "title": "임의로 생성된 제목 4",
            "content": "임의로 생성된 콘텐츠 4",
            "likeCount": 0,
            "commentCount": 0
        },
        {
            "id": 16,
            "updatedAt": "2024-08-21T20:13:15.133Z",
            "createdAt": "2024-08-21T20:13:15.133Z",
            "title": "임의로 생성된 제목 5",
            "content": "임의로 생성된 콘텐츠 5",
            "likeCount": 0,
            "commentCount": 0
        },
        {
            "id": 17,
            "updatedAt": "2024-08-21T20:13:15.137Z",
            "createdAt": "2024-08-21T20:13:15.137Z",
            "title": "임의로 생성된 제목 6",
            "content": "임의로 생성된 콘텐츠 6",
            "likeCount": 0,
            "commentCount": 0
        },
        {
            "id": 18,
            "updatedAt": "2024-08-21T20:13:15.140Z",
            "createdAt": "2024-08-21T20:13:15.140Z",
            "title": "임의로 생성된 제목 7",
            "content": "임의로 생성된 콘텐츠 7",
            "likeCount": 0,
            "commentCount": 0
        },
        {
            "id": 19,
            "updatedAt": "2024-08-21T20:13:15.143Z",
            "createdAt": "2024-08-21T20:13:15.143Z",
            "title": "임의로 생성된 제목 8",
            "content": "임의로 생성된 콘텐츠 8",
            "likeCount": 0,
            "commentCount": 0
        },
        {
            "id": 20,
            "updatedAt": "2024-08-21T20:13:15.147Z",
            "createdAt": "2024-08-21T20:13:15.147Z",
            "title": "임의로 생성된 제목 9",
            "content": "임의로 생성된 콘텐츠 9",
            "likeCount": 0,
            "commentCount": 0
        },
        {
            "id": 21,
            "updatedAt": "2024-08-21T20:13:15.151Z",
            "createdAt": "2024-08-21T20:13:15.151Z",
            "title": "임의로 생성된 제목 10",
            "content": "임의로 생성된 콘텐츠 10",
            "likeCount": 0,
            "commentCount": 0
        }
    ],
    "cursor": {
        "after": 21
    },
    "count": 20,
    "next": "http://localhost:3000/posts?order__createdAt=ASC&take=20&where__id_more_than=21"
}

 

{
    "data": [
        {
            "id": 96,
            "updatedAt": "2024-08-21T20:13:15.376Z",
            "createdAt": "2024-08-21T20:13:15.376Z",
            "title": "임의로 생성된 제목 85",
            "content": "임의로 생성된 콘텐츠 85",
            "likeCount": 0,
            "commentCount": 0
        },
        {
            "id": 97,
            "updatedAt": "2024-08-21T20:13:15.377Z",
            "createdAt": "2024-08-21T20:13:15.377Z",
            "title": "임의로 생성된 제목 86",
            "content": "임의로 생성된 콘텐츠 86",
            "likeCount": 0,
            "commentCount": 0
        },
        {
            "id": 98,
            "updatedAt": "2024-08-21T20:13:15.379Z",
            "createdAt": "2024-08-21T20:13:15.379Z",
            "title": "임의로 생성된 제목 87",
            "content": "임의로 생성된 콘텐츠 87",
            "likeCount": 0,
            "commentCount": 0
        },
        {
            "id": 99,
            "updatedAt": "2024-08-21T20:13:15.381Z",
            "createdAt": "2024-08-21T20:13:15.381Z",
            "title": "임의로 생성된 제목 88",
            "content": "임의로 생성된 콘텐츠 88",
            "likeCount": 0,
            "commentCount": 0
        },
        {
            "id": 100,
            "updatedAt": "2024-08-21T20:13:15.382Z",
            "createdAt": "2024-08-21T20:13:15.382Z",
            "title": "임의로 생성된 제목 89",
            "content": "임의로 생성된 콘텐츠 89",
            "likeCount": 0,
            "commentCount": 0
        },
        {
            "id": 101,
            "updatedAt": "2024-08-21T20:13:15.383Z",
            "createdAt": "2024-08-21T20:13:15.383Z",
            "title": "임의로 생성된 제목 90",
            "content": "임의로 생성된 콘텐츠 90",
            "likeCount": 0,
            "commentCount": 0
        },
        {
            "id": 102,
            "updatedAt": "2024-08-21T20:13:15.384Z",
            "createdAt": "2024-08-21T20:13:15.384Z",
            "title": "임의로 생성된 제목 91",
            "content": "임의로 생성된 콘텐츠 91",
            "likeCount": 0,
            "commentCount": 0
        },
        {
            "id": 103,
            "updatedAt": "2024-08-21T20:13:15.385Z",
            "createdAt": "2024-08-21T20:13:15.385Z",
            "title": "임의로 생성된 제목 92",
            "content": "임의로 생성된 콘텐츠 92",
            "likeCount": 0,
            "commentCount": 0
        },
        {
            "id": 104,
            "updatedAt": "2024-08-21T20:13:15.387Z",
            "createdAt": "2024-08-21T20:13:15.387Z",
            "title": "임의로 생성된 제목 93",
            "content": "임의로 생성된 콘텐츠 93",
            "likeCount": 0,
            "commentCount": 0
        },
        {
            "id": 105,
            "updatedAt": "2024-08-21T20:13:15.389Z",
            "createdAt": "2024-08-21T20:13:15.389Z",
            "title": "임의로 생성된 제목 94",
            "content": "임의로 생성된 콘텐츠 94",
            "likeCount": 0,
            "commentCount": 0
        },
        {
            "id": 106,
            "updatedAt": "2024-08-21T20:13:15.390Z",
            "createdAt": "2024-08-21T20:13:15.390Z",
            "title": "임의로 생성된 제목 95",
            "content": "임의로 생성된 콘텐츠 95",
            "likeCount": 0,
            "commentCount": 0
        },
        {
            "id": 107,
            "updatedAt": "2024-08-21T20:13:15.393Z",
            "createdAt": "2024-08-21T20:13:15.393Z",
            "title": "임의로 생성된 제목 96",
            "content": "임의로 생성된 콘텐츠 96",
            "likeCount": 0,
            "commentCount": 0
        },
        {
            "id": 108,
            "updatedAt": "2024-08-21T20:13:15.394Z",
            "createdAt": "2024-08-21T20:13:15.394Z",
            "title": "임의로 생성된 제목 97",
            "content": "임의로 생성된 콘텐츠 97",
            "likeCount": 0,
            "commentCount": 0
        },
        {
            "id": 109,
            "updatedAt": "2024-08-21T20:13:15.397Z",
            "createdAt": "2024-08-21T20:13:15.397Z",
            "title": "임의로 생성된 제목 98",
            "content": "임의로 생성된 콘텐츠 98",
            "likeCount": 0,
            "commentCount": 0
        },
        {
            "id": 110,
            "updatedAt": "2024-08-21T20:13:15.400Z",
            "createdAt": "2024-08-21T20:13:15.400Z",
            "title": "임의로 생성된 제목 99",
            "content": "임의로 생성된 콘텐츠 99",
            "likeCount": 0,
            "commentCount": 0
        }
    ],
    "cursor": {
        "after": null
    },
    "count": 15,
    "next": null
}
반응형