728x90
반응형

1) map()이란 무엇인가

모든 배열의 아이템에 function을 실행하는 메서드다.
그리고 함수의 결과 값으로 새로운 배열을 만든다.

const days = ["Mon", "Tue", "Wed", "Thurs", "Fri"];
//함수 자체를 변수에 할당하여 쓰거나
const addNumber = (day, index) => `#${index+1} 😍${day}`;
const smilingDays = days.map(addNumber);

// 또는 함수를 직접 넣어 사용
// const smilingDays = days.map((day, index) => `#${index+1} 😍${day}`);
console.log(smilingDays)

 

2) 콜백함수란 무엇인가

 

정의 : 함수에 파라미터로 들어가는 함수
용도 : 순차적으로 실행하고 싶을 때 씀
참고 : 콜백함수가 필요한 함수들에만 콜백함수 사용가능

          잘만들어진 함수를 협업하는 팀원이 가져다 쓰고 싶을 때 사용

          콜백함수로 함수를 디자인하지 말고, Promise도 있고 async, await도 있음.

 

document.querySelector("button").addEventListener("click", 콜백함수)
// 버튼을 클릭했을 때, 이 함수가 실행되게 해주세요.
function first(파라미터){
    console.log(1)
    파라미터()
}
function seconde(){
    console.log(2)
}

// 순차적으로 실행하기 위해 함수의 파라미터에 다른 함수를 넣음(콜백함수)
first(second)

 

3) jwt이란 무엇인가? (+ 세션,토큰 차이점)

로그인 기능을 구현할때
1. session : 정보가 간단하게 담김 => db확인하느라 처리시간이 김
2. token(jwt방식) : 정보가 많이 담김 => 정보 보고 바로 통과
둘 중 하나 이용하여 구현함

단점 : 디코딩이 쉬움, 시크릿키를 쉽게하면 털림, 남의 jwt 탈취 => 리프레쉬토크

별일 없으면 역사와 전통의 session 방식이 좋다.
그러나 많은 데이터를 처리해야한다면 jwt를 써야하는데 보안에 신경써야 한다.


쿠키: 서버와 사용자간에 주고 받는 데이터(웹에는 있지만, 앱에는 없음)

세션: 중요한 정보는 모두 서버->DB에 담겨 있음. 유저가 가진 것은 세션ID뿐

토큰: 서버가 기억하는 이상하게 생긴 문자열(ID카드)
JWT:  정보를 갖고 있는 토큰(DB없이 검증가능)
       토큰형식. DB를 생성하지 않음. 토큰을 받으면 '사인된 정보'를 유저에게 보냄
       토큰이 유효한지만 검사하고, 암호화하진 않음(비밀번호를 담으면 안됨)

세션장점 :  모든 정보를 저장. 해당 정보를 이용해 새로운 기능을 추가가능.
               예를 들어 세션을 삭제하고 쫓아낼 수 있음(ex.넷플리스)
JWT장점 :  토큰을 추적하지 않음. 토큰 유효성만 검사함. 하지만 강제로그아웃 등 하지 못함.

 

=> 규모가 작을때는 JWT를 추천하지만, 규모가 커진다면 세션을 쓰는게 좋은 편


4) 미들웨어란 무엇인가

미들웨어의 정의: 양쪽을 연결해서 데이터를 주고 받을 수 있도록 중간에서 매개 역활을 하는 소프트웨어

 

[어플리케이션 레벨] app.use(+get post put 등)의 메서드로 미들웨어를 등록할 수 있음.
[라우터 레벨] router.use는 인스턴스에 바인딩된다는 점을 제외하면 어플리케이션의 레벨과 동일하게 작동한다.
[오류처리 미들웨어] (err, req, res, next) 꼭 4개의 인수를 사용해야 한다. 하나라도 생략되면 일반 미들웨어로 인식한다.

[타사 미들웨어] 제 3자가 만든 미들웨어 (body-parser, morgan 등)
[내장 미들웨어] Express가 내장한 미들웨어들을 뜻한다

내장 미들웨어

 

5)  라우팅이란? (+app.use란 무엇인가)


라우팅은 응용 프로그램이 URI(또는 경로) 및 특정 HTTP 요청 메서드(GET, POST 등)인 특정 끝점에 대한

클라이언트 요청에 응답하는 방법을 결정하는 것을 말합니다.

appHTTP 메서드에 해당하는 Express 개체의 메서드를 사용하여 라우팅을 정의합니다 . 

예를 들어 app.get()GET 요청을 처리하고 app.postPOST 요청을 처리합니다.

app.use()를 사용하여 미들웨어를 콜백 함수로 지정할 수 있습니다

 

=> 콜백함수 정의 : 함수에 파라미터로 들어가는 함수 / 용도 : 순차적으로 실행하고 싶을 때 씀

 

응답 방법

728x90
반응형
728x90
반응형

1) map()이란 무엇인가

모든 배열의 아이템에 function을 실행하는 메서드다.
그리고 함수의 결과 값으로 새로운 배열을 만든다.

const days = ["Mon", "Tue", "Wed", "Thurs", "Fri"];
//함수 자체를 변수에 할당하여 쓰거나
const addNumber = (day, index) => `#${index+1} 😍${day}`;
const smilingDays = days.map(addNumber);

// 또는 함수를 직접 넣어 사용
// const smilingDays = days.map((day, index) => `#${index+1} 😍${day}`);
console.log(smilingDays)

 

2) 콜백함수란 무엇인가

 

정의 : 함수에 파라미터로 들어가는 함수
용도 : 순차적으로 실행하고 싶을 때 씀
참고 : 콜백함수가 필요한 함수들에만 콜백함수 사용가능

          잘만들어진 함수를 협업하는 팀원이 가져다 쓰고 싶을 때 사용

          콜백함수로 함수를 디자인하지 말고, Promise도 있고 async, await도 있음.

 

document.querySelector("button").addEventListener("click", 콜백함수)
// 버튼을 클릭했을 때, 이 함수가 실행되게 해주세요.
function first(파라미터){
    console.log(1)
    파라미터()
}
function seconde(){
    console.log(2)
}

// 순차적으로 실행하기 위해 함수의 파라미터에 다른 함수를 넣음(콜백함수)
first(second)

 

3) jwt이란 무엇인가? (+ 세션,토큰 차이점)

로그인 기능을 구현할때
1. session : 정보가 간단하게 담김 => db확인하느라 처리시간이 김
2. token(jwt방식) : 정보가 많이 담김 => 정보 보고 바로 통과
둘 중 하나 이용하여 구현함

단점 : 디코딩이 쉬움, 시크릿키를 쉽게하면 털림, 남의 jwt 탈취 => 리프레쉬토크

별일 없으면 역사와 전통의 session 방식이 좋다.
그러나 많은 데이터를 처리해야한다면 jwt를 써야하는데 보안에 신경써야 한다.


쿠키: 서버와 사용자간에 주고 받는 데이터(웹에는 있지만, 앱에는 없음)

세션: 중요한 정보는 모두 서버->DB에 담겨 있음. 유저가 가진 것은 세션ID뿐

토큰: 서버가 기억하는 이상하게 생긴 문자열(ID카드)
JWT:  정보를 갖고 있는 토큰(DB없이 검증가능)
       토큰형식. DB를 생성하지 않음. 토큰을 받으면 '사인된 정보'를 유저에게 보냄
       토큰이 유효한지만 검사하고, 암호화하진 않음(비밀번호를 담으면 안됨)

세션장점 :  모든 정보를 저장. 해당 정보를 이용해 새로운 기능을 추가가능.
               예를 들어 세션을 삭제하고 쫓아낼 수 있음(ex.넷플리스)
JWT장점 :  토큰을 추적하지 않음. 토큰 유효성만 검사함. 하지만 강제로그아웃 등 하지 못함.

 

=> 규모가 작을때는 JWT를 추천하지만, 규모가 커진다면 세션을 쓰는게 좋은 편


4) 미들웨어란 무엇인가

미들웨어의 정의: 양쪽을 연결해서 데이터를 주고 받을 수 있도록 중간에서 매개 역활을 하는 소프트웨어

 

[어플리케이션 레벨] app.use(+get post put 등)의 메서드로 미들웨어를 등록할 수 있음.
[라우터 레벨] router.use는 인스턴스에 바인딩된다는 점을 제외하면 어플리케이션의 레벨과 동일하게 작동한다.
[오류처리 미들웨어] (err, req, res, next) 꼭 4개의 인수를 사용해야 한다. 하나라도 생략되면 일반 미들웨어로 인식한다.

[타사 미들웨어] 제 3자가 만든 미들웨어 (body-parser, morgan 등)
[내장 미들웨어] Express가 내장한 미들웨어들을 뜻한다

내장 미들웨어

 

5)  라우팅이란? (+app.use란 무엇인가)


라우팅은 응용 프로그램이 URI(또는 경로) 및 특정 HTTP 요청 메서드(GET, POST 등)인 특정 끝점에 대한

클라이언트 요청에 응답하는 방법을 결정하는 것을 말합니다.

appHTTP 메서드에 해당하는 Express 개체의 메서드를 사용하여 라우팅을 정의합니다 . 

예를 들어 app.get()GET 요청을 처리하고 app.postPOST 요청을 처리합니다.

app.use()를 사용하여 미들웨어를 콜백 함수로 지정할 수 있습니다

 

=> 콜백함수 정의 : 함수에 파라미터로 들어가는 함수 / 용도 : 순차적으로 실행하고 싶을 때 씀

 

응답 방법

 

 

 

 

728x90
반응형
728x90
반응형

회원가입 프로젝트를 만드는 도중, 

post를 사용시에 해당 에러 발견

 

테이블이 없다고? 무슨소리지.. Users라는 것을 찾아봐야겠다!

 

 

models 폴더에서 tableName을 추가했어야 했다. 추가하니까 성공적으로 정보를 전달할 수 있었다.

728x90
반응형
728x90
반응형

설치 명령어

 

npm init -y
npm i -g sequelize-cli
npm i express mysql2 sequelize joi jsonwebtoken bcrypt

npx sequelize init (config파일생성됨) -> config에서 development 정보 수정

npx sequelize db:create (데이터베이스 생성)

npx sequelize model:generate --name User --attributes nickname:string,password:string,confirm:string(모델생성)

npx sequelize db:migrate (테이블 생성)

4개는 한세트다. 진행하다보면 1개씩 까먹어서 에러발생한 경우가 많았다!ㅠㅠ

 

app.js파일 만들기

const express = require("express");
const { sequelize } = require("./models");

const app = express();

app.listen(3000, async () => {
  console.log("3000번 서버 가동");
  await sequelize.authenticate();
  console.log("db authenticate");
});

 

회원가입

1. User 모델 만들기

   a. npx sequelize model:generate --name User --attributes nickname:string,password:string,confirm:string

   b. (모두 수정했으면) npx sequelize db:migrate

 

models 폴더에 있는 users.js 파일 수정

 

User.init(
    {
      nickname: {
        type: DataTypes.STRING,
        allowNull: false,
      },
      password: {
        type: DataTypes.STRING,
        allowNull: false,
      },
      confirm: {
        type: DataTypes.STRING,
      },
    },
    {
      sequelize,
      tableName: "users",   //이걸 꼭 추가해야한다.
      modelName: "User",
    }
  );

 

migrations 테이블이름을 Users에서 users로 모두 변경

"use strict";
/** @type {import('sequelize-cli').Migration} */
module.exports = {
  async up(queryInterface, Sequelize) {
    await queryInterface.createTable("users", {
      id: {
        allowNull: false,
        autoIncrement: true,
        primaryKey: true,
        type: Sequelize.INTEGER,
      },
      nickname: {
        type: Sequelize.STRING,
        allowNull: false,
      },
      password: {
        type: Sequelize.STRING,
        allowNull: false,
      },
      confirm: {
        type: Sequelize.STRING,
      },
      createdAt: {
        allowNull: false,
        type: Sequelize.DATE,
      },
      updatedAt: {
        allowNull: false,
        type: Sequelize.DATE,
      },
    });
  },
  async down(queryInterface, Sequelize) {
    await queryInterface.dropTable("users");
  },
};

 

시퀄라이즈 문법이 기억안날땐, npx sequelize 치면 명령어가 나온다

그중에서 다시 되돌릴땐 npx sequelize db:migrate:undo

 

2. users 테이블 생성하기

   a. npx sequelize db:migrate

DBeaver 생성확인

3. Route와 로직 만들기

routes 폴더 만들고 auth.js 만들어서 로직 정리

validation 폴더 만들고, index.js 만들어서 Joi사용

const Joi = require("joi");

const signupValidation = Joi.object({
  nickname: Joi.string().alphanum().not("").required(),
  password: Joi.string().min(3).not("").required(),
  confirm: Joi.equal(Joi.ref("password")).required().messages({
    "any.only": "비밀번호가 일치하지 않습니다.",
  }),
});


module.exports = {
  signupValidation,
};

4. bcrypt로 비밀번호 암호화하기

auth.js

const express = require("express");

const router = express.Router();
const { signupValidation } = require("../validations");
const { User } = require("../models");
const bcrypt = require("bcrypt");

router.get("/users", async (req, res) => {
  try {
    const users = await User.findAll({
      attributes: { exclude: ["password"] },
    });
    res.json(users);
  } catch (err) {}
});

router.post("/signup", async (req, res) => {
  try {
    const { nickname, password } = await signupValidation.validateAsync(req.body);
    const hashedPassword = await bcrypt.hash(password, 12);
    const user = await User.create({
      nickname,
      password: hashedPassword,
    });

    res.json(user);
  } catch (err) {
    if (err.isJoi) {
      return res.status(422).json({ message: err.details[0].message });
    }
    res.status(500).json({ message: err.message });
  }
});

module.exports = router;

 

게시글

모델 생성

npx sequelize model:generate --name Post --attributes title:string,content:string,userId:integer

 

models폴더에서 post.js 파일 수정

Post.init({
    title: {
      type: DataTypes.STRING,
      allowNull: false,
    },
    content: {
      type: DataTypes.STRING,
      allowNull: false,
    },
    userId: {
      type: DataTypes.INTEGER,
      allowNull: false,
    }
  }, {
    sequelize,
    tableName: "posts",
    modelName: 'Post',
  });

마이그레이션 post도 변경(소문자 posts 변경 및 allowNull 추가)

"use strict";
/** @type {import('sequelize-cli').Migration} */
module.exports = {
  async up(queryInterface, Sequelize) {
    await queryInterface.createTable("posts", {
      id: {
        allowNull: false,
        autoIncrement: true,
        primaryKey: true,
        type: Sequelize.INTEGER,
      },
      title: {
        type: Sequelize.STRING,
        allowNull: false,
      },
      content: {
        type: Sequelize.STRING,
        allowNull: false,
      },
      userId: {
        type: Sequelize.INTEGER,
        allowNull: false,
      },
      createdAt: {
        allowNull: false,
        type: Sequelize.DATE,
      },
      updatedAt: {
        allowNull: false,
        type: Sequelize.DATE,
      },
    });
  },
  async down(queryInterface, Sequelize) {
    await queryInterface.dropTable("posts");
  },
};

모두 수정후에 npx sequelize db:migrate 하기

routes 폴더에 posts.js 파일 만들고 app.js에 연결하기

 

models/post.js + user.js 연결하기

    static associate({ User }) {
      // define association here
      // UserId => userId 카멜케이스로 바꿈
      this.belongsTo(User, { foreignKey: "userId", as: "user" });
    }

    static associate({Post}) {
      // define association here
      this.hasMany(Post, {foreignKey:'userId', as: "posts"})
    }

 

validation/index.js 파일변경(게시물 생성 및 수정 검증로직 추가)

const Joi = require("joi");

const signupValidation = Joi.object({
  nickname: Joi.string().alphanum().not("").required(),
  password: Joi.string().min(3).not("").required(),
  confirm: Joi.equal(Joi.ref("password")).required().messages({
    "any.only": "비밀번호가 일치하지 않습니다.",
  }),
});

const postCreateValidation = Joi.object({
  title: Joi.string().not("").required(),
  content: Joi.string().not("").required(),
  userId: Joi.number().required(),
});

const postUpdateValidation = Joi.object({
  title: Joi.string().optional().not(""),
  content: Joi.string().optional().not(""),
  userId: Joi.forbidden(),
});

module.exports = {
  signupValidation,
  postCreateValidation,
  postUpdateValidation,
};

 

routes/posts.js

const express = require("express");
const router = express.Router();
const { Post, User } = require("../models");
const { postCreateValidation, postUpdateValidation } = require("../validations");

// 게시물 조회
router.get("/", async (req, res) => {
  try {
    const posts = await Post.findAll({
      include: [{ model: User, as: "user", attributes: ["nickname"] }],
      attributes: { exclude: ["userId"] },
    });
    res.json(posts);
  } catch (err) {
    res.status(500).json({ message: err.message });
  }
});

// 게시물 상세 조회
router.get("/:id", async (req, res) => {
  const { id } = req.params;
  try {
    const post = await Post.findByPk(id, {
      include: [{ model: User, as: "user", attributes: ["nickname"] }],
      attributes: { exclude: ["userId"] },
    });
    res.json(post);
  } catch (err) {
    res.status(500).json({ message: err.message });
  }
});

// 게시물 작성
router.post("/", async (req, res) => {
  try {
    const { title, content, userId } = await postCreateValidation.validateAsync(req.body);
    const post = await Post.create({
      title,
      content,
      userId,
    });
    res.json(post);
  } catch (err) {
    if (err.isJoi) {
      return res.status(422).json({ message: err.details[0].message });
    }
    res.status(500).json({ message: err.message });
  }
});

// 게시물수정
router.patch("/:id", async (req, res) => {
  const { id } = req.params;
  try {
    const fieldsToBeUpdated = await postUpdateValidation.validateAsync(req.body);
    const updatedPost = await Post.update(fieldsToBeUpdated, {
      where: { id },
    });
    res.json(updatedPost);
  } catch (err) {
    if (err.isJoi) {
      return res.status(422).json({ message: err.details[0].message });
    }
    res.status(500).json({ message: err.message });
  }
});

// 게시물삭제
router.delete("/:id", async (req, res) => {
  try {
    const { id } = req.params;
    const post = await Post.destroy({ where: { id } });
    res.json(post);
  } catch (err) {
    res.status(500).json({ message: err.message });
  }
});

module.exports = router;

 

 

댓글

모델 만들기

npx sequelize model:generate --name Comment --attributes content:string,userId:integer,postId:integer

 

models/comment.js에 들어가서 tableName:'comments' 추가, type: ~~~ 및 allowNull 추가(+관계형성하기)

마이그레이션에서 대문자 Comments를 소문자로 바꿔주고, allowNull 추가

완료한후 npx sequelize db:migrate 로 병합하기

라우터 폴더에서 comments.js 파일을 만들고 app.js에 적용시키기

validation에서 게시물작성 및 수정 유효검사 로직 작성후 routes/comments.js에서 로직 작성

 

routes/comments.js

const express = require("express");
const router = express.Router();
const { Comment, Post } = require("../models");
const { commentCreateValidation, commentUpdateValidation } = require("../validations/index");

// 댓글 전체 조회
router.get("/", async (req, res) => {
  try {
    const comments = await Comment.findAll();
    res.json(comments);
  } catch (err) {
    res.status(500).json({ message: err.message });
  }
});

// 특정 댓글 조회
router.get("/:postId", async (req, res) => {
  const { postId } = req.params;

  try {
    const post = await Post.findByPk(postId);
    const postComments = await post.getComments();
    res.json(postComments);
  } catch (err) {
    res.status(500).json({ message: err.message });
  }
});

// 댓글 작성
router.post("/:postId", async (req, res) => {
  const { postId } = req.params;
  try {
    const { content, userId } = await commentCreateValidation.validateAsync(req.body);
    const comment = await Comment.create({
      content,
      userId,
      postId,
    });
    res.json(comment);
  } catch (err) {
    if (err.isJoi) {
      return res.status(422).json({ message: err.details[0].message });
    }
    res.status(500).json({ message: err.message });
  }
});

//댓글 수정
router.patch("/:id", async (req, res) => {
  const { id } = req.params;

  try {
    const fieldsToUpdate = await commentUpdateValidation.validateAsync(req.body);
    const updatedComment = await Comment.update(fieldsToUpdate, { where: { id } });
    res.json(updatedComment);
  } catch (err) {
    if (err.isJoi) {
      return res.status(422).json({ message: err.details[0].message });
    }
    res.status(500).json({ message: err.message });
  }
});

//댓글 삭제
router.delete("/:id", async (req, res) => {
  const { id } = req.params;
  try {
    const deletedComment = await Comment.destroy({ where: { id } });
    res.json(deletedComment);
  } catch (err) {
    res.status(500).json({ message: err.message });
  }
});

module.exports = router;

 

로그인

auth.js (dotenv 설치, jwt사용하기)

require("dotenv").config();
const express = require("express");

const router = express.Router();
const { signupValidation } = require("../validations");
const { User } = require("../models");
const bcrypt = require("bcrypt");
const jwt = require("jsonwebtoken");

const { JWT_SECRET_KEY } = process.env;

//회원가입
router.get("/users", async (req, res) => {
  try {
    const users = await User.findAll({
      attributes: { exclude: ["password"] },
    });
    res.json(users);
  } catch (err) {}
});

router.post("/signup", async (req, res) => {
  try {
    const { nickname, password } = await signupValidation.validateAsync(req.body);
    const hashedPassword = await bcrypt.hash(password, 12);
    const user = await User.create({
      nickname,
      password: hashedPassword,
    });

    res.json(user);
  } catch (err) {
    if (err.isJoi) {
      return res.status(422).json({ message: err.details[0].message });
    }
    res.status(500).json({ message: err.message });
  }
});

//로그인
router.post("/login", async (req, res) => {
  const { nickname, password } = req.body;
  try {
    const user = await User.findOne({ nickname });
    const isPasswordCorrect = await bcrypt.compare(password, user.password);
    if (!user || !isPasswordCorrect) {
      return res.status(400).json({ message: "이메일 또는 비밀번호가 틀렸습니다." });
    }
    res.json({ token: jwt.sign({ nickname }, JWT_SECRET_KEY) });
  } catch (err) {
    res.status(500).json({ message: err.message });
  }
});

module.exports = router;

 

Auth 미들웨어

middleware 폴더 생성 - auth.js 파일 생성

const { User } = require("../models");
const jwt = require("jsonwebtoken");

const { JWT_SECRET_KEY } = process.env;

const authMiddleware = async (req, res, next) => {
  const { authorization = "" } = req.headers;
  const [tokenType, token] = authorization.split(" "); //['Bearer', '<token>']

  const isTokenValid = token && tokenType === "Bearer";

  if (!isTokenValid) {
    return res.status(401).json({
      message: "로그인 후 이용 가능한 기능입니다.",
    });
  }

  try {
    const { nickname } = jwt.verify(token, JWT_SECRET_KEY);
    const user = await User.findOne({ where: { nickname } });
    res.locals.currentUser = user; //미들웨어를 걸쳐 전역에서 사용가능한 변수 생성
    next();
  } catch (err) {
    res.status(401).json({
      message: "로그인 후 이용 가능한 기능입니다.",
    });
  }
};

module.exports = authMiddleware;

미들웨어를 사용하고 싶다면 해당 파일에서 require를 해주고 붙여주면 된다.

나는 app.js에서 app.use로 모두 경유하게 만들면 되지 않나? 했는데

로그인 했을때만 이용가능하게 전역에서 쓴다면 문제가 발생할 수 있다.

const authMiddleware = require("../middleware/auth");

router.post("/", authMiddleware, async (req, res) =>{}

 

라이크

npx sequelize model:generate --name Like --attributes userId:integer,postId:integer

테이블네임 추가, allow추가, Likes를 likes로 변경 (동일작업)

npx sequelize db:migrate

 

이후 유저, 댓글, 게시물과의 관계를 설정

const express = require("express");
const router = express.Router();
const { Post, User, Like, Sequelize } = require("../models");
const { postCreateValidation, postUpdateValidation } = require("../validations");
const authMiddleware = require("../middleware/auth");

// 게시물 조회
router.get("/", async (req, res) => {
  try {
    const posts = await Post.findAll({
      // attributes: { exclude: ["userId"] },
      attributes: ["id", "title", "content", [Sequelize.fn("count", Sequelize.col("likes.id")), "numOfLikes"]],
      include: [
        { model: User, as: "user", attributes: ["nickname"] },
        {
          model: Like,
          as: "likes",
          attributes: [],
        },
      ],
      group: ["post.id"],
      order: [[Sequelize.literal("numOfLikes"), "DESC"]],
    });

    res.json(posts);
  } catch (err) {
    res.status(500).json({ message: err.message });
  }
});

// 게시물 상세 조회
router.get("/:id", async (req, res) => {
  const { id } = req.params;
  try {
    const post = await Post.findByPk(id, {
      include: [{ model: User, as: "user", attributes: ["nickname"] }],
      attributes: { exclude: ["userId"] },
    });
    res.json(post);
  } catch (err) {
    res.status(500).json({ message: err.message });
  }
});

// 게시물 작성
router.post("/", authMiddleware, async (req, res) => {
  const { currentUser } = res.locals;
  const userId = currentUser.id;
  try {
    const { title, content } = await postCreateValidation.validateAsync(req.body);
    const post = await Post.create({
      title,
      content,
      userId,
    });
    res.json(post);
  } catch (err) {
    if (err.isJoi) {
      return res.status(422).json({ message: err.details[0].message });
    }
    res.status(500).json({ message: err.message });
  }
});

// 게시물수정
router.patch("/:id", async (req, res) => {
  const { id } = req.params;
  try {
    const fieldsToBeUpdated = await postUpdateValidation.validateAsync(req.body);
    const updatedPost = await Post.update(fieldsToBeUpdated, {
      where: { id },
    });
    res.json(updatedPost);
  } catch (err) {
    if (err.isJoi) {
      return res.status(422).json({ message: err.details[0].message });
    }
    res.status(500).json({ message: err.message });
  }
});

// 게시물삭제
router.delete("/:id", async (req, res) => {
  try {
    const { id } = req.params;
    const post = await Post.destroy({ where: { id } });
    res.json(post);
  } catch (err) {
    res.status(500).json({ message: err.message });
  }
});

// 좋아요 추가 및 취소
router.post("/:id/like", authMiddleware, async (req, res) => {
  const { id: postId } = req.params;
  const {
    currentUser: { id: userId },
  } = res.locals;
  // const userId = currentUser.id;

  try {
    const like = await Like.findOne({
      where: {
        userId,
        postId,
      },
    });

    const isLikedAlready = !!like;

    if (isLikedAlready) {
      //있다면 취소
      const deletedLike = await Like.destroy({
        where: {
          userId,
          postId,
        },
      });
      res.json(deletedLike);
    } else {
      //없으면 등록
      const postedLike = await Like.create({
        userId,
        postId,
      });
      res.json(postedLike);
    }
  } catch (err) {
    res.status(500).json({ message: err.message });
  }
});

module.exports = router;

 

마지막으로 깃허브에 등록하고, 혼자서 작성하는 연습예정

 

 

 

728x90
반응형
728x90
반응형

post로 아이디, 비밀번호의 데이터 값을 반환했을때, undefined가 반환된다.

 

이럴때 사용하는 패키지가 body-parser

"클라이언트 POST request data의 body로부터 파라미터를 편리하게 추출합니다."

 

설치를 한 후,

app.use(bodyParser.json()); //json형태로 변경
app.use(bodyParser.urlencoded({ extended: true })); //한글,공백등 잘못나오는걸 방지

 

설치하고 미들웨어 등록하니

결과값이 잘 출력되었다.

728x90
반응형
728x90
반응형

Uncaught TypeError: Cannot read property 'addEventListener' of null

 

ejs에서 자바스크립트를 사용할때, 위와 같은 에러문구가 발생

문득 생각나서

<script src="/js/login.js" defer></script>

경로 뒤에 defer를 붙였다.

 

defer는 <script> 태그의 defer 속성은 페이지가 모두 로드된 후에 해당 외부 스크립트가 실행됨을 명시합니다.

728x90
반응형
728x90
반응형
app.set("views", "views");
또는
app.set("views", "./views");

app.set("view engine", "ejs");

이런식으로  사용한후 서버를 가동하였으나

Error: Failed to lookup view "login.ejs" in views directory "views"

Error: Failed to lookup view "login.ejs" in views directory "./views"

 

이런식으로 에러문구가 떴다.

어? 근데 문구가 계속 변경되네?

 

강의 또는 다른곳에서 계속 "views", "views"와 같이 사용하니 관례처럼 느껴졌는데

"views"를 고정해주는 역활을 하는 것이기에 뒤에 명확하게 폴더루트를 찾아야 했다.

 

루트 찾는건 require("./src......") 이런식으로 하다보면 에디터에서 자동으로 찾아주니까

위치를 찾아놓고 다음과 같이 경로 확인해주니 정상작동 되었다.

app.set("views", "./src/views");
app.set("view engine", "ejs");

const mainRoutes = require("./src/routes/main");
app.use("/", mainRoutes);

폴더구조과 다른 프로젝트랑 다르다보니 발생한 문제 같다.

하나 더 깨달음을 얻어서 다행이다.

728x90
반응형
728x90
반응형

app.js

const express = require("express");
const app = express();

app.set("views", "views");
app.set("view engine", "ejs");

const mainRoutes = require("./src/routes/main");

app.get("/", mainRoutes);
app.get("/login", mainRoutes);

app.listen(8000, (req, res) => {
  console.log("8000번 서버가동");
});

/routes/main.js

const express = require("express");
const router = express.Router();

router.get("/", (req, res) => {
  res.send("메인화면");
});

router.get("/login", (req, res) => {
  res.send("로그인");
});

module.exports = router;

 

위 상태에서 서버를 실행하면 

Route.get() requires a callback function but got a [object Undefined]

 

뭐가 문제지? 라우터를 내보냈는데 읽지 못하는 것 같다.

유심히 살펴보니

app.get이 아니라 미들웨어로써 사용하는 것이기 때문에

app.use로 바꿔주니 해결 되었다.

 

app.get("/", mainRoutes);
app.get("/login", mainRoutes);

 

이미 라우터에서 "/" , "/login"을 받고 있기 때문에

app.use("/", mainRoutes) 만 등록해주니 해결 완료!

 

728x90
반응형

+ Recent posts