익스프레스로 간단한 SNS 서비스를 만들어보겠습니다! 로그인, 이미지 업로드, 게시글 작성, 해시태그 검색, 팔로잉 기능이 들어갈 예정입니다 하나씩 차근차근 해보겠습니다 :)
1. 프로젝트 세팅하기
npm init 을 콘솔에 입력하여 package.json 파일을 만듭니다.
npm init
{
"name": "nodebird",
"version": "0.0.1",
"description": "익스프레스로 만드는 SNS 서비스",
"main": "app.js",
"scripts": {
"start": "nodemon app"
},
"author": "sh",
"license": "MIT"
}
데이터베이스 연결을 위해 시퀄라이즈를 사용할 것입니다. 시퀄라이즈를 설치하고 sequelize init 으로 프로젝트 기본 세팅을 합니다. 기본 세팅 후 필요한 패키지들을 설치합니다. 템플릿 엔진은 넌적스를 사용합니다.
npm install sequelize sequelize-cli mysql2
npx sequelize init
npm install express cookie-parser express-session morgan multer dotenv nunjucks
npm install -D nodemon
2. 필요한 파일 생성하기
app.js 와 .env 파일을 작성합니다. 현재 app.js 에는 라우터가 pageRouter만 있는 상태입니다. .env 는 비밀번호가 담겨있는 파일입니다. 비밀번호 같은 개인정보는 하드 코딩하지 않고 .env 에 저장하는 것이 좋습니다.
// app.js
const express = require('express');
const cookieParser = require('cookie-parser');
const morgan = require('morgan');
const path = require('path');
const session = require('express-session');
const nunjucks = require('nunjucks');
const dotenv = require('dotenv');
dotenv.config();
const pageRouter = require('./routes/page'); // 라우터 가져오기
const app = express();
app.set('port', process.env.PORT || 3000);
app.set('view engine', 'html');
nunjucks.configure('views', {
express: app,
watch: true,
});
app.use(morgan('dev'));
app.use(express.static(path.join(__dirname, 'public')));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser(process.env.COOKIE_SECRET));
app.use(session({
resave: false,
saveUninitialized: false,
secret: process.env.COOKIE_SECRET,
cookie: {
httpOnly: true,
secure: false,
},
}));
app.use('/', pageRouter); // 라우터 연결하기
app.use((req, res, next) => {
const error = new Error(`${req.method} ${req.url} 라우터가 없습니다.`);
error.status = 404;
next(error);
});
app.use((err, req, res, next) => {
res.locals.message = err.message;
res.locals.error = process.env.NODE_ENV !== 'production' ? err : {};
res.status(err.status || 500);
res.render('error');
});
app.listen(app.get('port'), () => {
console.log(app.get('port'), '번 포트에서 대기중');
});
// .env
COOKIE_SECRET=nodebirdsecret
app.js 에 있던 pageRouter 파일을 생성하겠습니다. routes 폴더 생성 후 page.js 파일을 만듭니다. 이 라우터는 메인페이지로 세 가지 페이지로 이루어져 있습니다. GET /profile 은 내 정보 페이지이고, GET /join 은 회원가입 페이지이고, GET / 은 메인 페이지 입니다. 세 경로 모두 html 파일을 렌더링하여 페이지를 보여줍니다.
router.use 는 라우터용 미들웨어로 템플릿 엔진(넌적스)에서 사용할 변수를 설정합니다. 모든 템플릿 엔진에서 공통으로 사용하기 위해 res.locals 로 설정합니다.
// routes/page.js
const express = require('express');
const router = express.Router();
// 템플릿 엔진에서 사용할 변수 설정
router.use((req, res, next) => {
res.locals.user = null;
res.locals.followerCount = 0;
res.locals.followingCount = 0;
res.locals.followerIdList = [];
next();
});
// http://localhost:3000/profile
router.get('/profile', (req, res) => {
res.render('profile', { title: '내 정보 - NodeBird' });
});
// http://localhost:3000/join
router.get('/join', (req, res) => {
res.render('join', { title: '회원가입 - NodeBird' });
});
// http://localhost:3000/
router.get('/', (req, res, next) => {
const twits = [];
res.render('main', {
title: 'NodeBird',
twits,
});
});
module.exports = router;
3. 프론트 구성하기
프론트 부분 코드는 파일로 첨부하겠습니다. 서버 코드에 초점을 맞추고 있어서 프론트 코드는 따로 설명하지 않겠습니다. view 폴더 안에 layout.html, main.html, profile.html, join.html, error.html 을 생성합니다. public 폴더 안에 main.css 을 생성합니다.
여기까지 하면 프로젝트의 기본적인 세팅은 끝났고 콘솔에 npm start 입력 후 웹 페이지에 접속하면 다음과 같은 화면을 볼 수 있습니다!
4. 데이터베이스 세팅하기
데이터베이스는 MYSQL을 사용하겠습니다. 시퀄라이즈를 사용하기 위해 먼저 모델을 정의합니다. 모델을 정의할 때 모델 간의 관계도 정의해야 하므로 모델 간의 관계에 대해 먼저 살펴보겠습니다. User는 사용자 정보를 저장하는 모델, Post는 게시물을 저장하는 모델, Hashtag는 해시 태그 이름을 저장하는 모델입니다.
User : Post | 1 : N (한 사용자가 여러 게시물을 작성할 수 있음) |
User : User | N : M (사용자들끼리 팔로잉할 수 있음) |
Post : Hashtag | N : M (게시물에 여러 해시태그가 붙음) |
models 폴더 안에 user.js, post.js, hashtag.js, index.js 을 생성합니다.
// models/user.js
const Sequelize = require('sequelize');
module.exports = class User extends Sequelize.Model {
static init(sequelize) { // 테이블에 대한 설정
return super.init({
email: { // 이메일
type: Sequelize.STRING(40),
allowNull: true,
unique: true,
},
nick: { // 닉네임
type: Sequelize.STRING(15),
allowNull: false,
},
password: { // 패스워드
type: Sequelize.STRING(100),
allowNull: true,
},
provider: { // SNS 로그인한 경우에 사용하는 변수
type: Sequelize.STRING(10),
allowNull: false,
defaultValue: 'local',
},
snsId: { // SNS 로그인한 경우에 사용하는 변수
type: Sequelize.STRING(30),
allowNull: true,
},
}, {
sequelize,
timestamps: true, // createdAt, updatedAt 자동 생성
underscored: false,
modelName: 'User',
tableName: 'users',
paranoid: true, // deletedAt 자동 생성
charset: 'utf8',
collate: 'utf8_general_ci',
});
}
static associate(db) { // 테이블 간 관계 설정
db.User.hasMany(db.Post); // 사용자와 게시물 관계
// 사용자와 사용자 관계
db.User.belongsToMany(db.User, { // 사용자가 여러 사용자를 팔로잉
foreignKey: 'followingId',
as: 'Followers',
through: 'Follow',
});
db.User.belongsToMany(db.User, { // 사용자를 팔로잉하는 여러 명의 팔로워
foreignKey: 'followerId',
as: 'Followings',
through: 'Follow',
});
}
};
User 모델과 Post 모델은 1:N 관계이므로 hasMany로 연결되어 있습니다. 팔로잉 기능은 User 모델과 User 모델이 N:M 관계를 가지므로 belongsToMany 로 연결되어 있습니다. N:M 관계에서는 모델들을 연결할 모델이 필요합니다. 그 모델을 정의해야 하는데 그것이 belongsToMany의 옵션입니다. through 는 모델들을 연결할 모델의 이름이고, foreignKey 는 모델에서 사용자 아이디를 저장하는 컬럼입니다. 둘 다 User 모델이기 때문에 아이디 컬럼명이 모두 UserId 이므로 foreignKey 로 따로 설정해야 합니다. as 는 foreignKey와 반대되는 모델을 의미합니다. 이렇게 관계를 설정하면 Followers - Follow - Followings 관계가 됩니다.
// models/post.js
const Sequelize = require('sequelize');
module.exports = class Post extends Sequelize.Model {
static init(sequelize) { // 테이블에 대한 설정
return super.init({
content: { // 게시글 내용
type: Sequelize.STRING(140),
allowNull: false,
},
img: { // 이미지 경로
type: Sequelize.STRING(200),
allowNull: true,
},
}, {
sequelize,
timestamps: true, // createdAt, updatedAt 자동 생성
underscored: false,
modelName: 'Post',
tableName: 'posts',
paranoid: false,
charset: 'utf8mb4',
collate: 'utf8mb4_general_ci',
});
}
static associate(db) { // 테이블 간 관계 설정
db.Post.belongsTo(db.User);
db.Post.belongsToMany(db.Hashtag, { through: 'PostHashtag' });
}
};
User 모델과 Post 모델은 1:N 관계이므로 belongsTo로 연결되어 있습니다. Post 모델과 PostHashtag 모델은 N:M 관계이므로 belongsToMany 로 연결되어 있습니다. through 는 모델들을 연결할 모델의 이름입니다.
// models/hashtag.js
const Sequelize = require('sequelize');
module.exports = class Hashtag extends Sequelize.Model {
static init(sequelize) { // 테이블에 대한 설정
return super.init({
title: { // 해시 태그 이름
type: Sequelize.STRING(15),
allowNull: false,
unique: true,
},
}, {
sequelize,
timestamps: true, // createdAt, updatedAt 자동 생성
underscored: false,
modelName: 'Hashtag',
tableName: 'hashtags',
paranoid: false,
charset: 'utf8mb4',
collate: 'utf8mb4_general_ci',
});
}
static associate(db) { // 테이블 간 관계 설정
db.Hashtag.belongsToMany(db.Post, { through: 'PostHashtag' });
}
};
Post 모델과 Hashtag 모델이 N:M 관계이므로 belongsToMany로 연결되어 있습니다. through 는 모델들을 연결할 모델의 이름입니다.
// models/index.js
const Sequelize = require('sequelize');
const env = process.env.NODE_ENV || 'development';
const config = require('../config/config')[env];
const User = require('./user');
const Post = require('./post');
const Hashtag = require('./hashtag');
const db = {};
const sequelize = new Sequelize(
config.database, config.username, config.password, config,
);
db.sequelize = sequelize;
db.User = User;
db.Post = Post;
db.Hashtag = Hashtag;
User.init(sequelize);
Post.init(sequelize);
Hashtag.init(sequelize);
User.associate(db);
Post.associate(db);
Hashtag.associate(db);
module.exports = db;
위에서 생성한 모델들을 시퀄라이즈에 연결합니다. 각 모델들을 시퀄라이즈 객체에 연결합니다.
데이터베이스와 연결할 정보를 수정합니다. config/config.json 파일을 자신의 데이터베이스에 맞게 수정하면 됩니다.
// config/config.json
{
"development": {
"username": "root",
"password": "root의 비밀번호",
"database": "nodebird",
"host": "127.0.0.1",
"dialect": "mysql"
},
}
직접 MYSQL에 데이터베이스를 생성해도 되지만 다음 명령어를 입력하면 데이터베이스가 생성됩니다.
npx sequelize db:create
데이터베이스 생성 후 app.js 에 시퀄라이즈를 연결합니다.
// app.js
const express = require('express');
const cookieParser = require('cookie-parser');
const morgan = require('morgan');
const path = require('path');
const session = require('express-session');
const nunjucks = require('nunjucks');
const dotenv = require('dotenv');
dotenv.config();
const pageRouter = require('./routes/page');
const { sequelize } = require('./models'); // 시퀄라이즈 연결
// .. 생략
sequelize.sync({ force: false }) // 서버 실행 시 데이터베이스 연결
.then(() => {
console.log('데이터베이스 연결 성공');
})
.catch((err) => {
console.error(err);
});
// .. 생략
콘솔에 npm start 를 입력하면 콘솔에 다음과 같은 로그를 볼 수 있을 것 입니다!
'Back-end > Node.js' 카테고리의 다른 글
[Node.js] 익스프레스로 SNS 서비스 만들기 (3) (0) | 2021.07.27 |
---|---|
[Node.js] 익스프레스로 SNS 서비스 만들기 (2) (0) | 2021.07.27 |
[Node.js+MongoDB] 몽구스 (2) (Mongoose) (0) | 2021.07.23 |
[Node.js+MongoDB] 몽구스 (1) (Mongoose) (0) | 2021.07.20 |
[Node.js+MYSQL] 시퀄라이즈 (3) (Sequelize) (0) | 2021.07.20 |