본문 바로가기
프로젝트 기록/React, Node.js를 이용한 게시판 만들기

4. 게시판 validation 만들기 - React와 Node.js 게시판

by jeong11 2024. 11. 21.
반응형

 

프로젝트 정보

프론트엔드 : React
백엔드 : Node.js
DB : MySQL
VS Code 사용 
 
게시판 웹 애플리케이션 만들기 
<1. React와 Node.js를 사용한 게시판 웹 애플리케이션 만들기 - 게시판 만들기, 게시글 목록 자동 갱신, 글 추가, Router 설정, CORS 설정, MySQL>
https://tiny-immj.tistory.com/92

1. React와 Node.js를 사용한 게시판 웹 애플리케이션 만들기 - 게시판 만들기, 게시글 목록 자동 갱

Todo구현할 기능 : CRUD(게시글 작성, 조회, 수정, 삭제) RESTful API 이해하기https://tiny-immj.tistory.com/88 REST, REST API, RESTful의 기본 개념과 간단한 api 만드는 방법 진행=> RESTful API는 데이터를 표준화된 방

tiny-immj.tistory.com

 
<2. React와 Node.js를 사용한 게시판 웹 애플리케이션 만들기 - CRUD 구현, 게시글 수정과 삭제 이벤트, Endpoint>
https://tiny-immj.tistory.com/101

2. React와 Node.js를 사용한 게시판 웹 애플리케이션 만들기 - CRUD API 구현, 게시글 수정과 삭제 이벤

Todo구현할 기능 : CRUD (게시글 작성, 조회, 수정, 삭제)https://tiny-immj.tistory.com/88 REST, REST API, RESTful의 기본 개념과 간단한 api 만드는 방법 진행=> RESTful API는 데이터를 표준화된 방식으로 주고 받을

tiny-immj.tistory.com

 
<3. 게시판 조회수 구현과 React Bootstrap 사용한 껍데기 포장해보기 - React와 Node.js를 사용한 게시판 만들기>
https://tiny-immj.tistory.com/107

3. 게시판 조회수 구현과 React bootstrap 사용한 껍데기 포장해보기 - React와 Node.js를 사용한 게시판

프로젝트 정보 프론트엔드 : React백엔드 : Node.jsDB : MySQL VS Code 사용 게시판 웹 애플리케이션 만들기  https://tiny-immj.tistory.com/92 RESTful API는 데이터를 표준화된 방" data-og-host="tiny-immj.tistory.com" dat

tiny-immj.tistory.com

 


게시판 validation 만들기

게시글을 작성할 때 빈 글로 게시되지 않도록 validation을 구현해준다 
(지금은 글과 제목을 넣지 않아도 글 작성이 가능함) 
☞ 프론트엔드와 백엔드 모두 검증하는 것이 중요하다 
 

1. 검증

1-1. 백엔드 - 서버 측 검증 

▷ server.js의 게시글 작성, 게시글 수정 API에 검증을 넣는다 
> server.js
검증 코드는 아래와 같다 

// 제목과 내용이 비어있는지 확인
if (!title || !content || title.trim() === " || content.trim() === ") {
	return res.status(400).json({message: '제목과 내용을 모두 입력해야 합니다.'});
}

 
글 작성 이외에 수정 시에도 빈 값이 저장되지 않도록 검증을 해야한다
같은 검증 로직이 두 개의 API에 반복되므로 미들웨어를 사용하여 검증 미들웨어를 재사용해주는 방법으로 작성하였다

검증 부분
글 작성
글 수정
//server/server.js

/* 위쪽 코드 및 import 생략, 필요한 부분만 작성 */

//검증 미들웨어 작성 - 게시글 작성과 수정 부분
const ValidatePost = (req, res, next) => {
	const { title, content } = req.body;
    if (!title || !content || title.trim() === '' || content.trim() === '') {
    	return res.status(400).json({ message: '제목과 내용을 모두 입력해야 합니다.' });
    }
    next();
};

// 게시글 작성 API, validatePost 추가
app.post('/api/posts', validatePost, (req, res) => {
	const { title, content } = req.body;
    const query = 'INSERT INTO posts (title, content) VALUES (?, ?)';
    db.query(query, [title, content], (err, result) => {
    	if(err) {
        	return res.status(500).send('Error creating post');
        }
        // 데이터 저장 로직
        res.status(201).send('Post created successfully');
    });
});

// 게시글 수정 API, validatePost 추가
app.put('/api/posts/:id', validatePost, (req, res) => {
	const { id } =req.params;
    const { title, content } = req.body;
    const query = 'UPDATE posts SET title = ?, content = ? WHERE id = ?';
    db.query(query, [title, content, id], (err, result) => {
    	if (err) {
        	return res.status(500).send('Error updating post');
        }
        res.send('Post updated successfully');
    });
});

 
 

1-2. 프론트엔드 - 클라이언트 측 검증 

> PostForm.js

//import alert 추가
import { Row, Col, Form, Button, Container, Alert } from 'react-bootstrap';

function PostFORM({ setPosts }) {
	
    //validation error 메시지 추가
	const [error, serError] = useState('');
    
    const handleSubmit = (e) => {
    	e.preventDefault();
        
        // 제목과 내용이 비어 있는지 확인, 검증
    	if (!title.trim() || !content.trim()) {
        	setError('제목과 내용을 모두 입력해주세요.');
            return;
        }
        /* 서버로 데이터 전송, 게시글 목록을 갱신 */
    };
    
    return (
    	<Container style={{ maxWidth: '800px', marginTop: '50px' }}>
        	<h2 className="mb-5">새 게시글 작성</h2>
        	
            {/* 에러 메시지 표시 */}
            {error && <Alert variant="danger">{error}</Alert>}
            
            {/* form */}
            <form onSubmit={handleSubmit}>
            	{/* 제목 입력 */}
                <Row className="mb-3">
                	<Form.Label>제목</Form.Label>
                    <Col md={10}>
                    	<Form.Control
                        	type="text"
                            value={title}
                            onchange={(e) => setTitle(e.target.value)}
                            placeholder="제목을 입력하세요"
                            isInvalid={!title.trim() && error}	//제목이 비어있고 에러가 있으면 스타일 표시
                        >
                    </Col>
                </Row>
                
                {/* 내용 입력 및 버튼 */}
                <Row className="mb-4 align-items-center">
                	<Form.Label>내용</Form.Label>
                    <Col md={10} className="position-relative">
                    	<Form.Control
                        	as="textarea"
                            rows={15}
                            value={content}
                            onChange={(e) => setContent(e.target.value)}
                            placeholder="내용을 입력하세요"
                            style={{ paddingRight: '100px' }}
                            isInvalid={!content.trim() && error}	//내용이 비어있고 에러가 있으면 스타일 표시
                        />
                        
                        <Form.Control.Feedback type="invalid">
                        	내용을 입력해주세요.
                        </Form.Control.Feedback>
                        
                        {/* 작성 버튼을 textarea 왼쪽 아래에 위치 */}
                        <Button> 작성
                        </Button> 
                    </Col>
                </Row>
                
            </form>
        </Container>
    );
}

export default PostForm;

 

 
1-3. 실행화면 

 
 

2. 왜 모든 입력을 검증해야 할까? 

: 보안과 데이터 무결성 때문

2-1. 클라이언트 신뢰 부족

클라이언트 쪽에서 입력을 검증하더라도, 사용자가 서버에 직접 빈 값이나 잘못된 데이터를 보낼 수 있다 
서버 쪽에서도 항상 데이터 검증은 필요하다 
 

2-2. SQL Injection 방지

입력 데이터가 예상치 못한 형식일 경우 SQL Injection과 같은 보안 취약점이 발생할 수 있다 
SQL 사용시 반드시 프리페어드 스테이트먼트나 매개변수화된 쿼리를 사용해야 하는 이유이다
 

반응형