현재 만들어 놓은 list API는 작성된 모든 포스트를 불러오도록 작성되어있다.
만약 포스트 개수가 몇 백 개라면 로딩 속도가 느려질 것이므로 페이지화 하는 것이 좋다. 이를 페이지네이션 (pagination) 한다고 한다.
또, 포스트의 목록을 조회할 때에는 포스트의 내용 중 일부만 보여주고, 클릭시 포스트의 전체 내용을 보여주는 것이 합당하다.
1. 가짜 데이터 생성
우선, 페이지네이션 기능 구현을 위해 가짜 데이터를 생성한다.
- src/createFakeData.js
import Post from './models/post';
export default function createFakeData() {
// 0,1,2, ... 39로 이루어진 배열을 생성한 후 포스트 데이터로 변환
const posts = [...Array(40).keys()].map((i) => ({
title: `포스트 #${i}`,
// 좋아하는 노래 가사 :->
body: 'so no one told you life was gonna be this way Your job is joke, you are broke, your love life is DOA It is like you are always stuck in second gear when it hasnt been your day, your week, your month, or even your year, But I will be there for you (When the rain starts to pour) I will be there for you (Like Ive been there before) Cause you are there for me too',
tags: ['friends OST', '임시데이터'],
}));
Post.insertMany(posts, (err, docs) => {
console.log(docs);
});
}
body의 내용은 Friends의 유명한 OST인 I'll be there for you의 가사이다 ☺
위에서 만든 함수를 main.js에서 불러와 한 번 호출해준다.
- src/main.js
...
import createFakeData from './createFakeData';
const { PORT, MONGO_URI } = process.env;
mongoose
.connect(MONGO_URI)
.then(() => {
console.log('Connected to MongoDB');
createFakeData();
})
.catch((e) => {
console.log(e);
});
...
코드 저장 뒤 서버를 재시작했다.
데이터가 잘 등록된 것을 확인하고, 해당 코드(createFakeData를 호출하는 코드)를 main.js에서 지워주면 가짜 데이터 생성이 완료된다.
2. 포스트 역순으로 불러오기
우선 포스트를 역순으로 불러오는 방법을 알아보자.
현재 list API에서는 포스트가 작성된 순서대로 나열되는데, 블로그 방문시 작성한 지 오래된 포스트보다 가장 최근에 작성된 포스트를 먼저 보여주는 것이 좋을 것이다.
포스트 정렬을 위해서는 list API에서 exec() 전에 sort() 구문을 넣으면 된다.
sort() 내의 파라미터는 { key:1 } 형식으로 넣는다.
여기서 key는 정렬할 필드를 결정하며, 오른쪽 값은 오름차순인지(1) 내림차순인지(-1)를 결정한다.
나는 _id를 내림차순으로 정렬하고 싶으므로 { _id:-1} 로 설정하였다.
- src/api/posts/posts.ctrl.js
/*
GET /api/posts
*/
export const list = async (ctx) => {
try {
const posts = await Post.find().sort({ _id: -1 }).exec();
ctx.body = posts;
} catch (e) {
ctx.throw(500, e);
}
};
- Postman
테스팅 결과 가장 마지막 포스트가 먼저 조회되는 것을 확인하였다.
3. 보이는 개수 제한
이제 한 번에 포스트가 보여주는 개수를 제한해보자.
개수를 제한할 때는 limit() 함수를 사용한다.
파라미터에는 제한할 숫자를 넣으면 된다.
예를 들어 한 번에 보여주는 개수를 10개로 제한한다면 limit(10)이라고 입력하면 된다.
- src/api/posts/posts.ctrl.js
/*
GET /api/posts
*/
export const list = async (ctx) => {
try {
const posts = await Post.find().sort({ _id: -1 }).limit(10).exec();
ctx.body = posts;
} catch (e) {
ctx.throw(500, e);
}
};
4. 페이지 기능 구현
페이지 기능 구현을 위해서는 앞의 limit 함수와 함께 skip 함수를 사용해야한다.
skip 함수는 파라미터에 숫자를 입력하면 그 숫자만큼의 데이터를 제외(skip)하고 그 다음 데이터를 불러온다.
즉, skip 함수 파라미터에 (page-1)*10을 넣어주면 1페이지에는 처음 열 개의 포스트를, 2페이지에는 다음 열 개의 포스트를 불러온다.
page의 값은 query에서 받아 오도록 설정하고, 값이 없다면 1로 간주하여 코드를 작성하였다.
- src/api/posts/posts.ctrl.js
/*
GET /api/posts
*/
export const list = async (ctx) => {
// query는 문자열이기 때문에 숫자로 변환해 주어야 한다.
// parseInte( string, n) => string을 n진법으로 변환
const page = parseInt(ctx.query.page || '1',10);
if(page < 1) {
ctx.status = 400;
return;
}
try {
const posts = await Post.find()
.sort({ _id: -1 })
.limit(10)
.skip((page-1)*10)
.exec();
ctx.body = posts;
} catch (e) {
ctx.throw(500, e);
}
};
-Postman
page=2의 쿼리로 요청한 결과, 처음 10개의 포스트 (#40~#30)는 제외하고 #29번의 포스트부터 조회되는 것을 확인하였다.
5. 추가 기능 - 마지막 페이지 번호 알려주기
페이지에 관한 다양한 기능을 추가하기 위해 클라이언트 측에 정보를 제공하는 방법에는
응답 내용의 형식을 바꾸어 새로운 필드 설정 ,
Response 헤더 중 Link 설정,
커스텀 헤더를 설정하는 방법 등이 있다.
이 중 마지막 페이지 번호를 알려주기 위해 커스텀 헤더를 설정하는 방법을 사용해보았다.
- src/api/posts/posts.ctrl.js
/*
GET /api/posts
*/
export const list = async (ctx) => {
// query는 문자열이기 때문에 숫자로 변환해 주어야 한다.
// parseInte( string, n) => string을 n진법으로 변환
const page = parseInt(ctx.query.page || '1', 10);
if (page < 1) {
ctx.status = 400;
return;
}
try {
const posts = await Post.find()
.sort({ _id: -1 })
.limit(10)
.skip((page - 1) * 10)
.exec();
const postCount = await Post.countDocuments().exec();
ctx.set('Last-page', Math.ceil(postCount / 10));
ctx.body = posts;
} catch (e) {
ctx.throw(500, e);
}
};
set() 함수를 통해 커스텀 HTTP 헤더를 설정한다.
Last-page가 헤더의 key가 되고, 뒤의 Math.ceil(postCount/10)의 연산값이 헤더의 value가 된다.
- Postman
6. 목록의 포스트 내용 길이 제한
body의 길이가 200자 이상이면 뒤에 '...'를 붙이고 문자열을 자르는 기능을 구현해보자.
find()를 통해 조회한 데이터는 mongoose 문서 인스턴스의 형태이므로 데이터를 바로 변형할 수 없다.
대신 toJSON() 함수를 통해 JSON 형태로 변환한 뒤 필요한 변형을 수행하여야 한다.
- src/api/posts/posts.ctrl.js
/*
GET /api/posts
*/
export const list = async (ctx) => {
// query는 문자열이기 때문에 숫자로 변환해 주어야 한다.
// parseInte( string, n) => string을 n진법으로 변환
const page = parseInt(ctx.query.page || '1', 10);
if (page < 1) {
ctx.status = 400;
return;
}
try {
const posts = await Post.find()
.sort({ _id: -1 })
.limit(10)
.skip((page - 1) * 10)
.exec();
const postCount = await Post.countDocuments().exec();
ctx.set('Last-page', Math.ceil(postCount / 10));
ctx.body = posts
.map(post => post.toJSON())
.map(post => ({
...post,
body: post.body.length<200? post.body: `${post.body.slice(0,200)}...`,
}));
} catch (e) {
ctx.throw(500, e);
}
};
또는 lean() 함수를 사용하는 방법이 있다.
lean 함수를 사용하면, 데이터를 처음부터 JSON 형태로 조회한다.
- src/api/posts/posts.ctrl.js
- src/api/posts/posts.ctrl.js
/*
GET /api/posts
*/
export const list = async (ctx) => {
// query는 문자열이기 때문에 숫자로 변환해 주어야 한다.
// parseInte( string, n) => string을 n진법으로 변환
const page = parseInt(ctx.query.page || '1', 10);
if (page < 1) {
ctx.status = 400;
return;
}
try {
const posts = await Post.find()
.sort({ _id: -1 })
.limit(10)
.skip((page - 1) * 10)
.lean()
.exec();
const postCount = await Post.countDocuments().exec();
ctx.set('Last-page', Math.ceil(postCount / 10));
ctx.body = posts
.map(post => ({
...post,
body: post.body.length<200? post.body: `${post.body.slice(0,200)}...`,
}));
} catch (e) {
ctx.throw(500, e);
}
};
-Postman
테스팅 결과, 200자가 넘어가면 뒤 내용은 자르고 ... 로 출력되는 것을 확인하였다.
'Front-End > React' 카테고리의 다른 글
[React] 블로그 만들기 7 - 로그인 구현 (0) | 2022.03.15 |
---|---|
[React] 블로그 만들기 6 - 회원가입 구현 (0) | 2022.03.15 |
[React] 블로그 만들기 4 - Request Body 검증 (0) | 2022.03.14 |
[React] 블로그 만들기 3 - 요청 검증 (id 검증) (0) | 2022.03.14 |
[React] 블로그 만들기 2 - 데이터 생성, 조회, 삭제, 수정 기능 구현 (0) | 2022.03.14 |