WeniVooks

검색

FastAPI 베이스캠프

MPA로 블로그 구현하기

1. MPA 블로그 구현하기

이번 챕터에서는 이전 챕터에서 만들었던 SPA를 MPA로 변경하여 구현해보겠습니다. MPA(Multi Page Application)는 여러 페이지로 구성된 애플리케이션입니다. 각 페이지는 서버로부터 새로운 HTML을 받아와 렌더링하는 방식입니다.

1.1. MPA 구조

아래처럼 총 4개의 페이지로 구성된 MPA를 구현해보겠습니다. 여기서 http://127.0.0.1:5500은 여러분의 라이브서버 주소이기 때문에 일부 주소가 다를 수 있습니다.

  • blog_list.html: 블로그 글 목록 페이지
  • blog_detail.html: 블로그 글 상세 페이지
  • blog_create.html: 블로그 글 생성 페이지
  • blog_edit.html: 블로그 글 수정 페이지
1.2. MPA 구현
1.2.1. 블로그 목록 페이지

블로그 목록 페이지에서는 블로그 글 목록을 조회하고, 각 글을 클릭하면 상세 페이지로 이동할 수 있습니다. 파일명은 blog_list.html로 생성합니다.

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
</head>
<body>
    <h1>MPA</h1>
    <header>blog list</header>
    <main></main>
    <a href="http://127.0.0.1:5500/blog_create.html">블로그 생성하기</a>
    <script>
        const main = document.querySelector('main');
        fetch('http://127.0.0.1:8000/blogs')
            .then(response => response.json())
            .then(data => {
                console.log(data);
                data.forEach(element => {
                    main.innerHTML += `
                        <a href=http://127.0.0.1:5500/blog_detail.html?id=${element.id}>
                            <h2>${element.title}</h2>
                            <p>${element.created_at}</p>
                            <p>${element.updated_at}</p>
                            <p>${element.id}</p>
                            <p>${element.author}</p>
                            <p>${element.content}</p>
                        </a>
                    `;
                });
            });
    </script>
</body>
</html>
<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
</head>
<body>
    <h1>MPA</h1>
    <header>blog list</header>
    <main></main>
    <a href="http://127.0.0.1:5500/blog_create.html">블로그 생성하기</a>
    <script>
        const main = document.querySelector('main');
        fetch('http://127.0.0.1:8000/blogs')
            .then(response => response.json())
            .then(data => {
                console.log(data);
                data.forEach(element => {
                    main.innerHTML += `
                        <a href=http://127.0.0.1:5500/blog_detail.html?id=${element.id}>
                            <h2>${element.title}</h2>
                            <p>${element.created_at}</p>
                            <p>${element.updated_at}</p>
                            <p>${element.id}</p>
                            <p>${element.author}</p>
                            <p>${element.content}</p>
                        </a>
                    `;
                });
            });
    </script>
</body>
</html>
1.2.2. 블로그 상세 페이지

블로그 상세 페이지에서는 블로그 글의 상세 정보를 조회하고, 수정 및 삭제를 할 수 있습니다. 수정과 삭제 기능은 추후 로그인 한 사용자만 수정과 삭제가 가능해야 합니다. 파일명은 blog_detail.html로 생성합니다.

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
</head>
<body>
    <h1>MPA</h1>
    <header>blog detail</header>
    <main></main>
    <a href="http://127.0.0.1:5500/blog_list.html">목록으로 가기</a>
    <button class="edit">수정하기</button>
    <button class="delete">삭제하기</button>
    <script>
        const main = document.querySelector('main');
        // URL 구조에서 id를 가져오기
        // blog_detail.html?id=3
        const urlParams = new URLSearchParams(location.search);
        // console.log(urlParams.get('id'));
        const id = urlParams.get('id');
 
        fetch(`http://127.0.0.1:8000/blogs/${id}`)
            .then(response => response.json())
            .then(data => {
                console.log(data);
                main.innerHTML += `
                    <h2>${data.title}</h2>
                    <p>${data.created_at}</p>
                    <p>${data.updated_at}</p>
                    <p>${data.id}</p>
                    <p>${data.author}</p>
                    <p>${data.content}</p>
                `;
            });
 
        // 수정하기
        const editButton = document.querySelector('.edit');
        editButton.addEventListener('click', () => {
            location.href = `http://127.0.0.1:5500/blog_edit.html?id=${id}`;
        });
 
        // 삭제하기
        const deleteButton = document.querySelector('.delete');
        deleteButton.addEventListener('click', () => {
            fetch(`http://127.0.0.1:8000/blogs/${id}`, {
                method: 'DELETE'
            })
            .then(response => response.json())
            .then(data => {
                console.log(data);
                location.href = `http://127.0.0.1:5500/blog_list.html`;
            });
        });
    </script>
</body>
</html>
<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
</head>
<body>
    <h1>MPA</h1>
    <header>blog detail</header>
    <main></main>
    <a href="http://127.0.0.1:5500/blog_list.html">목록으로 가기</a>
    <button class="edit">수정하기</button>
    <button class="delete">삭제하기</button>
    <script>
        const main = document.querySelector('main');
        // URL 구조에서 id를 가져오기
        // blog_detail.html?id=3
        const urlParams = new URLSearchParams(location.search);
        // console.log(urlParams.get('id'));
        const id = urlParams.get('id');
 
        fetch(`http://127.0.0.1:8000/blogs/${id}`)
            .then(response => response.json())
            .then(data => {
                console.log(data);
                main.innerHTML += `
                    <h2>${data.title}</h2>
                    <p>${data.created_at}</p>
                    <p>${data.updated_at}</p>
                    <p>${data.id}</p>
                    <p>${data.author}</p>
                    <p>${data.content}</p>
                `;
            });
 
        // 수정하기
        const editButton = document.querySelector('.edit');
        editButton.addEventListener('click', () => {
            location.href = `http://127.0.0.1:5500/blog_edit.html?id=${id}`;
        });
 
        // 삭제하기
        const deleteButton = document.querySelector('.delete');
        deleteButton.addEventListener('click', () => {
            fetch(`http://127.0.0.1:8000/blogs/${id}`, {
                method: 'DELETE'
            })
            .then(response => response.json())
            .then(data => {
                console.log(data);
                location.href = `http://127.0.0.1:5500/blog_list.html`;
            });
        });
    </script>
</body>
</html>
1.2.3. 블로그 생성 페이지

블로그 생성 페이지에서는 새로운 블로그 글을 생성할 수 있습니다. 파일명은 blog_create.html로 생성합니다. 다만 여기서 고려해야 할 것이 게시물을 생성한 다음에 어디로 가야할지입니다. 이번에는 게시물을 생성한 다음에 상세 페이지로 이동하도록 구현하겠습니다. 여기에 따라 프론트엔드 구현이 매우 달라집니다.

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title></title>
</head>
<body>
    <h1>블로그 생성하기</h1>
 
    <form action="127.0.0.1:8000/blogs" method="post">
        <input type="text" name="title" placeholder="제목"><br>
        <textarea name="content" placeholder="내용"></textarea><br>
        <button>게시물 작성</button>
    </form>
    <script>
        const form = document.querySelector('form');
        form.addEventListener('submit', (event) => {
            event.preventDefault();
            const title = event.target.title.value;
            const content = event.target.content.value;
            // console.log(title, content);
            fetch('http://127.0.0.1:8000/blogs', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify({
                    title: title,
                    content: content
                })
            })
            .then(response => response.json())
            .then(data => {
                console.log(data);
                location.href = `http://127.0.0.1:5500/blog_detail.html?id=${data.id}`
            });
        });
    </script>
</body>
</html>
<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title></title>
</head>
<body>
    <h1>블로그 생성하기</h1>
 
    <form action="127.0.0.1:8000/blogs" method="post">
        <input type="text" name="title" placeholder="제목"><br>
        <textarea name="content" placeholder="내용"></textarea><br>
        <button>게시물 작성</button>
    </form>
    <script>
        const form = document.querySelector('form');
        form.addEventListener('submit', (event) => {
            event.preventDefault();
            const title = event.target.title.value;
            const content = event.target.content.value;
            // console.log(title, content);
            fetch('http://127.0.0.1:8000/blogs', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify({
                    title: title,
                    content: content
                })
            })
            .then(response => response.json())
            .then(data => {
                console.log(data);
                location.href = `http://127.0.0.1:5500/blog_detail.html?id=${data.id}`
            });
        });
    </script>
</body>
</html>
1.2.4. 블로그 수정 페이지

블로그 수정 페이지에서는 기존 블로그 글을 수정할 수 있습니다. 파일명은 blog_edit.html로 생성합니다.

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title></title>
</head>
<body>
    <h1>블로그 수정하기</h1>
    <!--
        블로그 수정하기에는 기존 데이터가 필요합니다. 
    -->
    <form action="127.0.0.1:8000/blogs" method="post">
        <input type="text" name="title" placeholder="제목"><br>
        <textarea name="content" placeholder="내용"></textarea><br>
        <button>게시물 작성</button>
    </form>
    <script>
        const urlParams = new URLSearchParams(location.search);
        const form = document.querySelector('form');
        const id = urlParams.get('id');
        // 이 id를 기반으로 fetch를 날려서 데이터를 가져와서 form에 넣어줍니다.
        fetch(`http://127.0.0.1:8000/blogs/${id}`)
            .then(response => response.json())
            .then(data => {
                console.log(data);
                form.title.value = data.title;
                form.content.value = data.content;
            });
 
        form.addEventListener('submit', (event) => {
            event.preventDefault();
            const title = event.target.title.value;
            const content = event.target.content.value;
            // console.log(title, content);
            fetch(`http://127.0.0.1:8000/blogs/${id}`, {
                method: 'PUT',
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify({
                    title: title,
                    content: content
                })
            })
            .then(response => response.json())
            .then(data => {
                console.log(data);
                location.href = `http://127.0.0.1:5500/blog_detail.html?id=${data.id}`
            });
        });
    </script>
</body>
</html>
<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title></title>
</head>
<body>
    <h1>블로그 수정하기</h1>
    <!--
        블로그 수정하기에는 기존 데이터가 필요합니다. 
    -->
    <form action="127.0.0.1:8000/blogs" method="post">
        <input type="text" name="title" placeholder="제목"><br>
        <textarea name="content" placeholder="내용"></textarea><br>
        <button>게시물 작성</button>
    </form>
    <script>
        const urlParams = new URLSearchParams(location.search);
        const form = document.querySelector('form');
        const id = urlParams.get('id');
        // 이 id를 기반으로 fetch를 날려서 데이터를 가져와서 form에 넣어줍니다.
        fetch(`http://127.0.0.1:8000/blogs/${id}`)
            .then(response => response.json())
            .then(data => {
                console.log(data);
                form.title.value = data.title;
                form.content.value = data.content;
            });
 
        form.addEventListener('submit', (event) => {
            event.preventDefault();
            const title = event.target.title.value;
            const content = event.target.content.value;
            // console.log(title, content);
            fetch(`http://127.0.0.1:8000/blogs/${id}`, {
                method: 'PUT',
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify({
                    title: title,
                    content: content
                })
            })
            .then(response => response.json())
            .then(data => {
                console.log(data);
                location.href = `http://127.0.0.1:5500/blog_detail.html?id=${data.id}`
            });
        });
    </script>
</body>
</html>
5.3 SPA로 블로그 구현하기5.5 DB 구성 및 static 파일 서빙