게시판 - Post Error 처리

소스코드

이 게시물에는 코드작성이 포함되어 있습니다. 소스코드를 받으신 후 진행해 주세요. MEAN Stack/개발 환경 구축에서 설명된 프로그램들(git, npm, atom editor)이 있어야 아래의 명령어들을 실행할 수 있습니다.

이 게시물의 소스코드는 게시판 만들기 / 게시판 - Login 기능 추가에서 이어집니다.

board.git 을 clone 한 적이 있는 경우: 터미널에서 해당 폴더로 이동 후 아래 명령어들을 붙여넣기합니다. 폴더 내 모든 코드가 이 게시물의 코드로 교체됩니다. 이를 원치 않으시면 이 방법을 선택하지 마세요.

git reset --hard
git pull
git reset --hard 0a4b23b
git reset --soft 4eac806
npm install
atom .

board.git 을 clone 한 적이 없는 경우: 터미널에서 코드를 다운 받을 폴더로 이동한 후 아래 명령어들을 붙여넣기하여 board.git 을 clone 합니다.

git clone https://github.com/a-mean-blogger/board.git
cd board
git reset --hard 0a4b23b
git reset --soft 4eac806
npm install
atom .

- Github에서 소스코드 보기: https://github.com/a-mean-blogger/board/tree/0a4b23bd412bc6c477c2f6a07aa71de09688555d


게시판 - User Error 처리에서처럼 post의 error를 처리해 봅시다.

또한 routes/user.js 에서 사용했던 parseError함수를 post에도 그대로 사용할텐데, 이처럼 여러 파일에서 사용하게 될 함수들을 하나의 module로 분리하겠습니다.

폴더구조

코드 - js

// util.js

var util = {};

util.parseError = function(errors){
  var parsed = {};
  if(errors.name == 'ValidationError'){
    for(var name in errors.errors){
      var validationError = errors.errors[name];
      parsed[name] = { message:validationError.message };
    }
  } 
  else if(errors.code == '11000' && errors.errmsg.indexOf('username') > 0) {
    parsed.username = { message:'This username already exists!' };
  } 
  else {
    parsed.unhandled = JSON.stringify(errors);
  }
  return parsed;
}

module.exports = util;

원래 routes/users.js에 있던 parseError함수를 module로 만들어 util.js 파일로 분리했습니다. 이처럼 여러 곳에서 공통으로 쓰게 될 함수들은 앞으로 util.js파일에 기록합니다

// routes/users.js

var express = require('express');
var router = express.Router();
var User = require('../models/User');
var util = require('../util'); // 1

...

// create
router.post('/', function(req, res){
  User.create(req.body, function(err, user){
    if(err){
      req.flash('user', req.body);
      req.flash('errors', util.parseError(err)); // 1
      return res.redirect('/users/new');
    }
    res.redirect('/users');
  });
});

...

// update
router.put('/:username', function(req, res, next){
  User.findOne({username:req.params.username})
    .select('password')
    .exec(function(err, user){
      if(err) return res.json(err);

      // update user object ...

      // save updated user
      user.save(function(err, user){
        if(err){
          req.flash('user', req.body);
          req.flash('errors', util.parseError(err));
          return res.redirect('/users/'+req.params.username+'/edit'); // 1
        }
        res.redirect('/users/'+user.username);
      });
  });
});

...

1. utilrequire됬고, 기존에parseErrorutil.parseError로 바뀌었습니다.

// model/Post.js

var mongoose = require('mongoose');

// schema
var postSchema = mongoose.Schema({
  title:{type:String, required:[true,'Title is required!']}, // 1
  body:{type:String, required:[true,'Body is required!']},   // 1
  createdAt:{type:Date, default:Date.now},
  updatedAt:{type:Date},
});

// model & export
var Post = mongoose.model('post', postSchema);
module.exports = Post;

1. post schema의 커스텀 에러메세지들이 추가되었습니다.

// routes/posts.js

var express  = require('express');
var router = express.Router();
var Post = require('../models/Post');
var util = require('../util'); // 1

...

// New
router.get('/new', function(req, res){
  var post = req.flash('post')[0] || {};
  var errors = req.flash('errors')[0] || {};
  res.render('posts/new', { post:post, errors:errors });
});

// create
router.post('/', function(req, res){
  Post.create(req.body, function(err, post){
    if(err){
      req.flash('post', req.body);
      req.flash('errors', util.parseError(err));
      return res.redirect('/posts/new');
    }
    res.redirect('/posts');
  });
});

...

// edit
router.get('/:id/edit', function(req, res){
  var post = req.flash('post')[0];
  var errors = req.flash('errors')[0] || {};
  if(!post){
    Post.findOne({_id:req.params.id}, function(err, post){
        if(err) return res.json(err);
        res.render('posts/edit', { post:post, errors:errors });
      });
  }
  else {
    post._id = req.params.id;
    res.render('posts/edit', { post:post, errors:errors });
  }
});

// update
router.put('/:id', function(req, res){
  req.body.updatedAt = Date.now();
  Post.findOneAndUpdate({_id:req.params.id}, req.body, {runValidators:true}, function(err, post){
    if(err){
      req.flash('post', req.body);
      req.flash('errors', util.parseError(err));
      return res.redirect('/posts/'+req.params.id+'/edit');
    }
    res.redirect('/posts/'+req.params.id);
  });
});

...

module.exports = router;

게시판 - User Error 처리에서 변경된 것과 동일하게 변경되었습니다. 상세한 설명은 생략합니다.

한가지 눈여겨 볼 점은 update의 Post.findOneAndUpdate{runValidators:true}이 추가된 것인데요, findOneAndUpdate는 기본설정이 schema에 있는 validation을 작동하지 않도록 되어 있기때문에 이 option을 통해서 validation이 작동하도록 설정해 주어야 합니다.

코드 - ejs

ejs 역시 게시판 - User Error 처리와 동일하게 변경되었기 때문에 설명은 생략합니다.

<!-- views/posts/edit.ejs -->

...

      <form action="/posts/<%= post._id %>?_method=put" method="post">

        <div class="form-group">
          <label for="title">Title</label>
          <input type="text" id="title" name="title" value="<%= post.title %>" class="form-control <%= (errors.title)?'is-invalid':'' %>">
          <% if(errors.title){ %>
            <span class="invalid-feedback"><%= errors.title.message %></span>
          <% } %>
        </div>

        <div class="form-group">
          <label for="body">Body</label>
          <textarea id="body" name="body" rows="5" class="form-control <%= (errors.body)?'is-invalid':'' %>"><%= post.body %></textarea>
          <% if(errors.body){ %>
            <span class="invalid-feedback"><%= errors.body.message %></span>
          <% } %>
        </div>

        <% if(errors.unhandled){ %>
          <div class="invalid-feedback b-block">
            <%= errors.unhandled %>
          </div>
        <% } %>

        <div>
          <a class="btn btn-primary" href="/posts">Back</a>
          <button type="submit" class="btn btn-primary">Submit</button>
        </div>

      </form>

...

<!-- views/posts/new.ejs -->

...

      <form action="/posts" method="post">

        <div class="form-group">
          <label for="title">Title</label>
          <input type="text" id="title" name="title" value="<%= post.title %>" class="form-control <%= (errors.title)?'is-invalid':'' %>">
          <% if(errors.title){ %>
            <span class="invalid-feedback"><%= errors.title.message %></span>
          <% } %>
        </div>
        
        <div class="form-group">
          <label for="body">Body</label>
          <textarea id="body" name="body" rows="5" class="form-control <%= (errors.body)?'is-invalid':'' %>"><%= post.body %></textarea>
          <% if(errors.body){ %>
            <span class="invalid-feedback"><%= errors.body.message %></span>
          <% } %>
        </div>

        <% if(errors.unhandled){ %>
          <div class="invalid-feedback d-block">
            <%= errors.unhandled %>
          </div>
        <% } %>

        <div>
          <a class="btn btn-primary" href="/posts">Back</a>
          <button type="submit" class="btn btn-primary">Submit</button>
        </div>

      </form>

...

실행결과

마치며...

이번 강의는 error 처리의 복습편이였고, 다음강의에는 다시 새로운 내용을 배워보겠습니다!

댓글

댓글쓰기

이 글에 댓글을 다시려면 SNS 계정으로 로그인하세요. 자세히 알아보기

UP