반응형
이전에 회사에서 외주 프로젝트를 진행할 때 뉴스 정보를 페이지 네이션으로 구현했었다.
내가 구현한 로직
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 / 첫번 째 장, 마지막 장
{
"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 / 첫번 째 장, 마지막 장
{
"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
}
반응형
'nestJS' 카테고리의 다른 글
NestJS | 의존성 주입, 제어의 역전 (0) | 2024.11.06 |
---|---|
NestJS | Config (env) (0) | 2024.08.25 |
NestJS | Session vs JWT Token , Refresh Token & Access Token (0) | 2024.08.18 |
NestJS | Service (0) | 2024.08.14 |
NestJS | Controller | 모듈 생성하기, Postman 요청 보내기 (0) | 2024.08.13 |