lecture 라는 디렉토리를 생성하고 npm init 으로 시작
D:\code\node\lecture>npm init
This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sensible defaults.
See `npm help init` for definitive documentation on these fields
and exactly what they do.
Use `npm install <pkg>` afterwards to install a package and
save it as a dependency in the package.json file.
Press ^C at any time to quit.
package name: (lecture) nodebird
version: (1.0.0) 0.0.1
description: 익스프레스를 만드는 SNS 서비스
entry point: (index.js) app.js
test command:
git repository:
keywords:
author:
license: (ISC) MIT
About to write to D:\code\node\lecture\package.json:
{
"name": "nodebird",
"version": "0.0.1",
"description": "익스프레스를 만드는 SNS 서비스",
"main": "app.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "MIT"
}
Is this OK? (yes) yes
// 필요한 모듈 설치
D:\code\node\lecture>npm i sequelize mysql2 sequelize-cli
D:\code\node\lecture>npx sequelize init
D:\code\node\lecture>npm i express cookie-parser express-session morgan multer dotenv nunjucks
D:\code\node\lecture>npm i -D nodemon
app.js 가 메인 파일이다.
router 에서 필요한 것들은 res.locals를 사용한다.
// routes/page.js
const express = require('express');
const router = express.Router();
const {renderJoin, renderMain, renderProfile} = require('../controllers/page');
router.use((req, res, next)=>{
res.locals.user = null;
res.locals.follerCount = 0;
res.locals.followingCount = 0;
res.locals.followingIdList = [];
next();
})
router.get('/profile', renderProfile);
router.get('/join', renderJoin);
router.get('/', renderMain);
module.exports = router;
미들웨어 마지막에 위치하는 것들을 컨트롤러라고 부른다.
// controllers/page.js
exports.renderProfile = (req, res, next) =>{
// 서비스를 호출
res.redner('profile', {title : '내 정보 - NoreBird'});
};
exports.renderJoin = (req, res, next )=>{
res.render('join', {title : '회원 가입 - NodeBird'});
};
exports.renderMain = (req, res, next )=>{
res.render('main', {
title : 'Nodebird',
twits: [],
});
};
// 라우터 -> 컨트롤러 -> 서비스(요청, 응답 모른다.)
아래와 같이 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(); // process.env
const pageRouter = require('./routes/page')
const app = express();
app.set('port', process.env.PORT || 8001);
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,
secret : false,
}
}));
app.use('/', pageRouter);
app.use((req,res,next)=>{ // 404 NOT FOUND
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'),'번 포트에서 대기 중');
});
에러 발생! 다행히 검색해서 빨리 해결함 (오타..)
// 아래와 같이 에러 발생, 알려주는 위치로 갔는데 내가 작성한 파일이 아니므로
// 구글 검색 후 app.js 에서 engine 설정하는 부분에서 오타 발견하여 해결함.
[nodemon] starting `node app.js`
8001 번 포트에서 대기 중
GET / 500 9.394 ms - 1190
Error: No default engine was specified and no extension was provided.
at new NunjucksView (D:\code\node\lecture\node_modules\nunjucks\src\express-app.js:11:13)
// engine 오타 였음..
app.set('view engine','html');
에러 해결하고 다행히 아래와 같이 프로젝트 구성 후 실행 성공
sequelize 설정과 models 디렉토리 , config\config.json 에서 DB 설정을 완료한 후에 아래처럼 DB를 생성해준다.
D:\code\node\lecture>npx sequelize db:create
Sequelize CLI [Node: 20.16.0, CLI: 6.6.2, ORM: 6.37.3]
Loaded configuration file "config\config.json".
Using environment "development".
Database nodejs created.
그 이후에 npm start 했는데 아래와 같이 에러 발생
D:\code\node\lecture>npm start
> nodebird@0.0.1 start
> nodemon app.js
[nodemon] 3.1.4
[nodemon] to restart at any time, enter `rs`
[nodemon] watching path(s): *.*
[nodemon] watching extensions: js,mjs,cjs,json
[nodemon] starting `node app.js`
hashtag.js Hashtag
post.js Post
D:\code\node\lecture\models\index.js:24
model.initiate(sequelize);
^
TypeError: model.initiate is not a function
해당 파일인 index.js 파일 찾았는데도 오타 발견 못하였고, models 안에 있는 다른 .js 문제라고 생각되어 제로초님 깃허브와 비교한 결과 models 안에 있는 다른.js 에서 오타 찾아서 다시 수행하니 에러 해결되고 테이블 생성됨.
Node.js v20.16.0
[nodemon] app crashed - waiting for file changes before starting...
[nodemon] restarting due to changes...
[nodemon] starting `node app.js`
hashtag.js Hashtag
post.js Post
user.js User
8001 번 포트에서 대기 중
Executing (default): SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE' AND TABLE_NAME = 'hashtags' AND TABLE_SCHEMA = 'nodejs'
Executing (default): CREATE TABLE IF NOT EXISTS `hashtags` (`id` INTEGER NOT NULL auto_increment , `title` VARCHAR(15) NOT NULL UNIQUE, `createdAt` DATETIME NOT NULL, `updatedAt` DATETIME NOT NULL, PRIMARY
KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_general_ci;
Executing (default): SHOW INDEX FROM `hashtags` FROM `nodejs`
Executing (default): SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE' AND TABLE_NAME = 'users' AND TABLE_SCHEMA = 'nodejs'
Executing (default): CREATE TABLE IF NOT EXISTS `users` (`id` INTEGER NOT NULL auto_increment , `email` VARCHAR(40) UNIQUE, `nick` VARCHAR(15) NOT NULL, `password` VARCHAR(100), `provider` ENUM('local', 'kakao') NOT NULL DEFAULT 'local', `snsId` VARCHAR(30), `createdAt` DATETIME NOT NULL, `updatedAt` DATETIME NOT NULL, `deletedAt` DATETIME, PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_general_ci;
Executing (default): SHOW INDEX FROM `users` FROM `nodejs`
Executing (default): SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE' AND TABLE_NAME = 'posts' AND TABLE_SCHEMA = 'nodejs'
Executing (default): CREATE TABLE IF NOT EXISTS `posts` (`id` INTEGER NOT NULL auto_increment , `content` VARCHAR(140) NOT NULL, `img` VARCHAR(200), `createdAt` DATETIME NOT NULL, `updatedAt` DATETIME NOT NULL, `UserId` INTEGER, PRIMARY KEY (`id`), FOREIGN KEY (`UserId`) REFERENCES `users` (`id`) ON DELETE SET NULL ON UPDATE CASCADE) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_general_ci;
Executing (default): SHOW INDEX FROM `posts` FROM `nodejs`
Executing (default): SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE' AND TABLE_NAME = 'PostHashtag' AND TABLE_SCHEMA = 'nodejs'
Executing (default): CREATE TABLE IF NOT EXISTS `PostHashtag` (`createdAt` DATETIME NOT NULL, `updatedAt` DATETIME NOT NULL, `HashtagId` INTEGER , `PostId` INTEGER , PRIMARY KEY (`HashtagId`, `PostId`), FOREIGN KEY (`HashtagId`) REFERENCES `hashtags` (`id`) ON DELETE CASCADE ON UPDATE CASCADE, FOREIGN KEY (`PostId`) REFERENCES `posts` (`id`) ON DELETE CASCADE ON UPDATE CASCADE) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_general_ci;
Executing (default): SHOW INDEX FROM `PostHashtag` FROM `nodejs`
Executing (default): SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE' AND TABLE_NAME = 'Follow' AND TABLE_SCHEMA = 'nodejs'
Executing (default): CREATE TABLE IF NOT EXISTS `Follow` (`createdAt` DATETIME NOT NULL, `updatedAt` DATETIME NOT NULL, `followingId` INTEGER , `followerId` INTEGER , PRIMARY KEY (`followingId`, `followerId`), FOREIGN KEY (`followingId`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE, FOREIGN
KEY (`followerId`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE utf8_general_ci;
Executing (default): SHOW INDEX FROM `Follow` FROM `nodejs`
데이터베이스 연결 성공
위와 같이 테이블 생성된 것 확인.
passport 설정하고 회원 가입하는 코드까지만 작성하고 서버 시작해서 잘 가입되는지 확인
D:\code\node\lecture>npm start
> nodebird@0.0.1 start
> nodemon app.js
[nodemon] 3.1.4
[nodemon] to restart at any time, enter `rs`
[nodemon] watching path(s): *.*
[nodemon] watching extensions: js,mjs,cjs,json
[nodemon] starting `node app.js`
hashtag.js Hashtag
post.js Post
user.js User
8001 번 포트에서 대기 중
Executing (default): SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE' AND TABLE_NAME = 'hashtags' AND TABLE_SCHEMA = 'nodejs'
Executing (default): SHOW INDEX FROM `hashtags` FROM `nodejs`
Executing (default): SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE' AND TABLE_NAME = 'users' AND TABLE_SCHEMA = 'nodejs'
Executing (default): SHOW INDEX FROM `users` FROM `nodejs`
Executing (default): SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE' AND TABLE_NAME = 'posts' AND TABLE_SCHEMA = 'nodejs'
Executing (default): SHOW INDEX FROM `posts` FROM `nodejs`
Executing (default): SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE' AND TABLE_NAME = 'PostHashtag' AND TABLE_SCHEMA = 'nodejs'
Executing (default): SHOW INDEX FROM `PostHashtag` FROM `nodejs`
Executing (default): SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE' AND TABLE_NAME = 'Follow' AND TABLE_SCHEMA = 'nodejs'
Executing (default): SHOW INDEX FROM `Follow` FROM `nodejs`
데이터베이스 연결 성공
아래와 같이 회원 가입되면 insert into 구문이 보이고 302 코드를 반환한 것을 보면 성공적으로 가입된 것을 확인할 수 있다.
GET /main.css 200 3.224 ms - 2715
GET /join 200 2.651 ms - 2510
GET /main.css 304 0.854 ms - -
Executing (default): SELECT `id`, `email`, `nick`, `password`, `provider`, `snsId`, `createdAt`, `updatedAt`, `deletedAt` FROM `users` AS `User` WHERE (`User`.`deletedAt` IS NULL AND `User`.`email` = 'a@b.com');
Executing (default): INSERT INTO `users` (`id`,`email`,`nick`,`password`,`provider`,`createdAt`,`updatedAt`) VALUES (DEFAULT,?,?,?,?,?,?);
POST /auth/join 302 555.560 ms - 46
Executing (default): SELECT `Post`.`id`, `Post`.`content`, `Post`.`img`, `Post`.`createdAt`, `Post`.`updatedAt`, `Post`.`UserId`, `User`.`id` AS `User.id`, `User`.`nick` AS `User.nick` FROM `posts` AS `Post` LEFT OUTER JOIN `users` AS `User` ON `Post`.`UserId` = `User`.`id` AND (`User`.`deletedAt` IS NULL) ORDER BY `Post`.`createdAt` DESC;
GET / 200 20.424 ms - 3247
실제 DB에서도 정상적으로 잘 입력된 것 확인 가능.
로그인 기능까지 코드 작성한 뒤에 로그인 했을 때 성공한 화면
실제로 DB에서도 정상적으로 입력된 것도 확인
카카오톡 로그인 코드 작성한 뒤에 로그인 했을 때 성공한 화면
하지만 카카오톡 로그인이 강의 시점과 달라져서 아래와 같이 이메일은 권한이 없어서 못 받아오는 것으로 보인다. 비즈앱으로 등록을 해야만 권한이 허용되는 것 같다.
그래도 이름, snsID는 받아와서 로그인은 되었지만 아래와 같이 DB에는 이름만 받아오는 것을 확인할 수 있었다.
해시태그를 게시판 내용 안에서 추출하는 정규표현식 node 로 직접 수행해보면 아래와 같다
D:\code\node\lecture>node
Welcome to Node.js v20.16.0.
Type ".help" for more information.
> const str = '노드 교과서 너무 재밌어요. #노드교과서 #익스프레스 짱짱'
undefined
> str.match(/#[^\s#]*/g);
[ '#노드교과서', '#익스프레스' ]
해시태그 포함해서 게시판 글쓰기 코드 작성 후에 아래와 같이 이미지 올린 결과는 아래와 같다.
게시판 업로드까지 완료한 화면은 아래와 같다.
아래와 같이 DB에도 잘 들어간 것을 확인