사용 기술 스택
- Express JS
- React Native
- Mongo DB
- Docker Container
나는 백엔드 분야에 참여하였기 때문에 백엔드를 위주로 기록을 작성할 것이다.
MVC모델 (Model-View-Controller) 구조로 개발하였으며
다음과 같이 파일을 분류하였음
config : MongoDB와의 환경설정을 담당하는 폴더
models : 실제 DB에 저장되는 객체를 정의한 폴더
middleware : req요청을 받고 res를 리턴하기 전에 처리해야할 메소드를 정리한 폴더
controllers : 라우터에서 정의한 인터페이스의 동작을 정의해놓은 폴더, 라우터에 매핑한 URL로 이동하였을 때 이 컨트롤러의 코드에 따라 응답을 수행한다.
나는 뉴스 게시판을 생성하는 역할을 담당했으며 수행한 작업은 다음과 같다.
1) Model 생성하기
import mongoose from 'mongoose';
import autoIncrement from 'mongoose-auto-increment';
autoIncrement.initialize(mongoose.connection);
const newsSchema = new mongoose.Schema({
seq :{
type : Number,
default : 0
},
title:{
type : String,
required : [true, 'Title is required!']
},
contents:{
type : String,
required : [true, 'Content is required!']
},
author : {
type : mongoose.Schema.Types.ObjectId,
ref : 'user',
required: true
}, // ref : user을 통해 user collection의 id와 연결됨을 mongoose에 알림
createdAt : {
type : Date,
default : Date.now
}
});
newsSchema.plugin(autoIncrement.plugin, {
model: 'news',
field: 'seq',
startAt : 1,
increment : 1
});
// news 자체가 복수형..
const news = mongoose.model('news', newsSchema);
export default news;
// 모듈의 사용성을 늘리기 위한 exports
스키마의 이름을 지정해주고 new mongoose.Schema 키워드로 스키마를 생성해준다.
끝에는 exports defauilt news로 외부에서 쓸 수 있도록 처리
2) Router 생성하기
import express from 'express';
import routes from "./routes";
import {IsMember} from "../middleware/auth.js"
import {
postWriteNews,
postDeleteNews,
postEditNews,
getAllNews,
getOneNews
} from '../controllers/newsController';
const newsRouter = express.Router();
// 게시글 작성
newsRouter.post(routes.writeNews, IsMember, postWriteNews);
// 게시글 삭제
newsRouter.post(routes.deleteNews, postDeleteNews );
// 게시글 수정
newsRouter.post(routes.editNews, postEditNews );
// 게시글 조회
newsRouter.get(routes.allNews, getAllNews);
newsRouter.get(routes.oneNews, getOneNews );
export default newsRouter;
생성할 메소드 별로 Router를 생성하고, Controller와 연결하기 위해 메소드 이름을 import하여 사용한다.
사용할 route 이름을 지정(newsRouter) --> newsRouter = express.Router();
newsRouter.post(routes.writeNews, IsMember, postWirteNews);
[Router이름].[데이터전송방식](routes.[매핑할URL이름], [미들웨어이름], [매핑할 컨트롤러 내부 메소드 이름]);
이제 newsRouter에 의해서 localhost:5000/writeNews로 이동했을 때 컨트롤러의 postWriteNews 함수가 실행되고, req와 res의 사이에서 IsMember이라는 미들웨어 함수가 작동하게 된다.
3) Controller 생성하기
import News from "../models/News";
// 글 등록(인트아이 회원 권한)
export const postWriteNews = async(req, res) => {
const user = req.user;
const {title, contents, createdAt} = req.body;
if(!title || !contents){ // title나 contents가 비었을 때
return res.status(400).json({success : false, message : "title and contents both are required"});
}
try{
const news = await News.create({
title,
contents,
author : req.user.id,
createdAt
});
res.locals.post = news;
res.locals.schema = News;
res.locals.schemaName = "News";
// 클라이언트로 변수 전송
return res.status(200).json({success : true})
} catch (error) {
res.status(400).send({success : false, error : error.message});
}
}
// 글 삭제
export const postDeleteNews = async(req,res) => {
const user = req.user;
try{
const news = await News.findOne({seq : req.params.id});
if(news.author !== user.nickname){ // 글 작성자가 아닌 경우 예외처리
return res.status(403).json({success : false, message : "You can only edit posts that you wrote "});
}
const rawData = await News.findByIdAndDelete({seq : req.params.id});
res.locals.rawData = rawData;
res.locals.schema = News;
res.locals.schemaName = "News";
return res.status(200).json({success : true})
} catch (err) {
console.log("게시글 삭제 실패");
return res.status(400).json({success : false, error : error.message});
}
}
// 글 수정
export const postEditNews = async(req, res) => {
const user = req.user;
const { title, contents } = req.body;
// 수정된 값 전달 받기
if(!title || !contents){ // title나 contents가 비었을 때
return res.status(400).json({success : false, message : "title and contents both are required"});
}
try{
const news = await News.findOne({seq: req.params.id});
// 작성자 본인이 아닐 경우
if(news.author !== user.nickname){
return res.status(403).json({success : false, message : "You can only edit posts that you wrote "});
}
const rawData = await News.findByIdAndUpdate({seq : req.params.id},
{ $set : {title : title, contents : contents}});
res.locals.schema = News;
res.locals.rawData= rawData;
res.locals.schemaName = "News";
return res.status(200).json({success : true})
} catch (error) {
console.log("게시글 수정 실패", err);
return res.status(400).json({success: false, error : error.message});
}
};
// 기술 뉴스 게시판에서 글 전체 조회
export const getAllNews = async (req, res) => {
try {
const news = await News.find({});
return res.status(200).json({news : news});
}catch (error) {
console.log("404 : Cannot get the page of showing all lists", error);
res.status(400).send({error : error.message});
}
}
// 클릭한 게시글 하나만 조회
export const getOneNews = async(req, res) => {
try{
const news = await News.findById({seq : req.params.id});
return res.status(200).json({news:news});
} catch(err){
console.log("404 : Cannot get the page of showing the board", err);
res.status(400).send({error : error.message});
}
}
mongoose의 내장 함수(find, findById)등을 이용해 메서드를 개발한 컨트롤러!
미들웨어는 auth.js라는 middleware 디렉토리에서 개발한 메소드를 끌어다가 게시글 CRUD 권한을 설정하는 것에서 사용하였다.