27.블로그 포스트 작성 및 에디터 기능 추가, 서버에서 마크다운 파일을 HTML로 변환하여 렌더링

현대 웹 애플리케이션 개발에서 블로그 시스템은 많은 인기를 끌고 있습니다. 특히나 개인이 자신을 표현할 수 있는 공간으로 블로그는 매우 중요한 역할을 합니다. 이번 포스트에서는 Nest.js와 Next.js를 활용하여 블로그 포스트 작성 및 에디터 기능을 추가하는 방법에 대해 논의하고자 합니다.

1. 프로젝트 구성

Nest.js는 서버 사이드 프레임워크로, TypeScript로 작성되어 있으며, Next.js는 리액트 기반의 서버 사이드 렌더링(SSR) 프레임워크입니다. 이 두 프레임워크를 조합하여 효율적인 블로그 애플리케이션을 구현할 수 있습니다. 먼저, Nest.js를 사용하여 API 서버를 구축하고, Next.js로 클라이언트 애플리케이션을 만듭니다.

2. Nest.js API 서버 구축

Nest.js에서 API를 구축하는 기본적인 과정은 다음과 같습니다. 먼저, Nest.js CLI를 사용하여 프로젝트를 생성합니다.

npm i -g @nestjs/cli
nest new blog-server

생성된 프로젝트 폴더로 이동한 후, 필요한 패키지를 설치합니다. Markdown 파일을 처리하기 위해 `marked` 패키지를 사용할 것입니다.

npm install marked

다음으로, 포스트를 관리할 수 있는 기본적인 CRUD API를 만듭니다. `posts`라는 모듈을 생성합니다.

nest generate module posts
nest generate service posts
nest generate controller posts

2.1. 포스트 DTO(Data Transfer Object) 정의

포스트 데이터를 다루기 위해 DTO를 만듭니다. `create-post.dto.ts` 파일을 생성하고 아래와 같이 작성합니다.

import { IsString, IsNotEmpty } from 'class-validator';

        export class CreatePostDto {
            @IsString()
            @IsNotEmpty()
            title: string;

            @IsString()
            @IsNotEmpty()
            content: string;
        }

2.2. 서비스 구현

`posts.service.ts` 파일을 열고 포스트 데이터를 관리하는 메서드를 추가합니다. 여기서는 간단히 메모리에 데이터를 저장합니다.

import { Injectable } from '@nestjs/common';
        import { CreatePostDto } from './dto/create-post.dto';

        interface Post {
            id: number;
            title: string;
            content: string;
        }

        @Injectable()
        export class PostsService {
            private posts: Post[] = [];
            private idCounter = 1;

            create(postDto: CreatePostDto): Post {
                const newPost = {
                    id: this.idCounter++,
                    ...postDto,
                };
                this.posts.push(newPost);
                return newPost;
            }

            findAll(): Post[] {
                return this.posts;
            }

            findOne(id: number): Post {
                return this.posts.find(post => post.id === id);
            }
        }

2.3. 컨트롤러 구현

`posts.controller.ts` 파일을 열고 API 엔드포인트를 추가합니다. 포스트를 추가하고, 목록을 가져오는 기능을 구현합니다.

import { Controller, Post, Body, Get } from '@nestjs/common';
        import { PostsService } from './posts.service';
        import { CreatePostDto } from './dto/create-post.dto';

        @Controller('posts')
        export class PostsController {
            constructor(private readonly postsService: PostsService) {}

            @Post()
            create(@Body() postDto: CreatePostDto) {
                return this.postsService.create(postDto);
            }

            @Get()
            findAll() {
                return this.postsService.findAll();
            }
        }

3. 클라이언트 애플리케이션 Next.js 구축

이제 Next.js를 사용하여 블로그 클라이언트를 구축하겠습니다. 새로운 Next.js 프로젝트를 생성합니다.

npx create-next-app blog-client

클라이언트 애플리케이션에서도 Markdown 파일을 사용하기 위해 `remark` 패키지를 설치합니다.

npm install remark remark-html

3.1. 포스트 작성 페이지

포스트를 작성할 수 있는 페이지를 만들어야 합니다. `pages/create-post.js` 파일을 생성하고 아래와 같이 작성합니다.

import { useState } from 'react';

        export default function CreatePost() {
            const [title, setTitle] = useState('');
            const [content, setContent] = useState('');

            const handleSubmit = async (e) => {
                e.preventDefault();
                const response = await fetch('http://localhost:3000/posts', {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json',
                    },
                    body: JSON.stringify({ title, content }),
                });
                if (response.ok) {
                    alert('포스트가 성공적으로 작성되었습니다.');
                }
            };

            return (
                
setTitle(e.target.value)} required />
); }

4. 마크다운 처리 및 HTML 렌더링

사용자가 작성한 마크다운 내용을 HTML로 변환하여 렌더링하는 기능을 추가해야 합니다. 이 과정에서 `remark`와 `remark-html`을 사용하여 마크다운을 HTML로 변환합니다.

4.1. Markdown to HTML 변환 구현

포스트를 조회하는 페이지를 만들어 HTML로 변환된 내용을 렌더링합니다. `pages/posts/[id].js` 파일을 생성하고 아래와 같이 작성합니다.

import { useEffect, useState } from 'react';
        import { remark } from 'remark';
        import html from 'remark-html';

        const Post = ({ post }) => {
            const [contentHtml, setContentHtml] = useState('');

            useEffect(() => {
                const convertMarkdownToHtml = async () => {
                    const processedContent = await remark()
                        .use(html)
                        .process(post.content);
                    setContentHtml(processedContent.toString());
                };
                convertMarkdownToHtml();
            }, [post.content]);

            return (
                

{post.title}

); }; export async function getServerSideProps(context) { const { id } = context.params; const res = await fetch(`http://localhost:3000/posts/${id}`); const post = await res.json(); return { props: { post } }; } export default Post;

5. 전체 흐름 정리

이제 사용자가 블로그 포스트를 작성하고, 이를 마크다운 형식으로 저장하고, 이후 이를 HTML로 변환하여 렌더링할 수 있는 전체적인 기능을 갖춘 시스템이 완성되었습니다. Nest.js는 백엔드에서 포스트를 저장하고 관리하며, Next.js는 클라이언트에서 포스트 작성과 내용을 표시하는 역할을 합니다. 이러한 시스템 구성은 개발의 유연성을 높여주며, 유지보수 또한 쉽게 만들어줍니다.

6. 결론

블로그 포스트 작성 및 에디터 기능을 추가하는 과정에서 Nest.js와 Next.js를 활용한 다양한 예제를 살펴보았습니다. 마크다운을 HTML로 변환하는 과정은 블로그 개발에서 매우 중요한 부분이며, 이를 통해 사용자에게 더 나은 콘텐츠를 제공할 수 있습니다. 앞으로 자신만의 블로그를 구축하는 데 있어 Nest.js와 Next.js를 적극 활용해보세요!

저자: 조광형

게시일: 2024년 11월 26일