TIL.2023.06.23

이얏호·2023년 6월 23일
0
post-custom-banner

간략하게 프로젝트 하면서 기록해두고 싶었던 것들을
두서 없이 적을 예정입니다...

	npm i express, cokie-parser, jsonwebtoken,
    
    +
    
    (몽고db => mongoose, mySQL => mysql2, sequelize => sequelize, sequelize-cli(devDependencies로 설치))
// app.js
	const express = require("express");
    const app = express();
    
    app.use("/기본주소", [Router1, Router2 ...]);
    + 사용하기 좋은 것들
    app.use(express.json());
    app.user(express.urlencoded({extended: false}));

express 선언 후 app에 받아주고 app.use로 모든 router들이 거쳐서 지나갈 수 있도록 설정
+json, urlencoded, cokiParser 등 ...

몽고DB의 경우...

Schema의 index.js에서 주소 설정

const mongoose = require("mongoose");

const connect = () => {
  mongoose
    .connect("mongodb://localhost:27017/주소")
    .catch((err) => console.log(err));
};

mongoose.connection.on("error", (err) => {
  console.error("몽고디비 연결 에러", err);
});

module.exports = connect;

위의 app.js에서

const connect = require("./schemas/index.js(index.js경로)");
connect();

로 받아줌

이후에 Schema 작성

//postSchema
const mongoose = require("mongoose");

const postsSchema = new mongoose.Schema({
  userId: {
    type: String,
    required: true,
  },
  nickname: {
    type: String,
    required: true,
  },
});

postsSchema.virtual("postId").get(function () {
  return this._id.toHexString();
});

postsSchema.set("toJSON", {
  virtuals: true,
});

module.exports = mongoose.model("posts", postsSchema);

postsSchema 안에서 스키마의 형태를 지정해줌
required(필수 값인지?)
unique(유일해야 하는지?)

virtual ~ 부분은 실제 노출되지 않는 부분을 toJSON으로 불러 올때
보이도록 해줌
이를 통해서 post의 _id값을 가진 comment를 만든다거나 할 때 용이함.

아까 작성했던 app.js의 router 부분 작성.

//postsRouter
const express = require("express"); 
const router = express.Router(); 
const Posts = require("../schemas/post.js");

이후 get, post, put, delete 등 api 통신 관련 코드 작성

module.exports = router; //으로 내보내줌

++ 추가사항 미들웨어를 통해서 공통적으로 적용시켜야하는 부분에 대해서
편하게 작성이 가능하다.
예를 들어 middleware.js를 만들고
해당 부분에 로그인 인증 기능을 작성하면

const Middleware = require("middleware경로");

router.get("/주소경로", Middleware, async(req, res) => {
	const {userId} == middleware에서 export한 값
	내용~
}

의 방식으로 미들웨어를 통해 공통적인 인증 사항을 진행 할 수 있음
(완전 편리)

jsonwebtoken
== jwt

cookie에 로그인 정보 등을 바로 부여할 경우, 사용자가 조작하거나 할 수 있는
위험성 존재
따라서 사용자에게는 열쇠만 쥐어주고 필요값은 서버에서 받음

const jwt = require("jsonwebtoken");

//암호화(키생성)
const token = jwt.sign({"이름":"값"}, "비밀 키");

//쿠키로 보냄(authorization의 이름으로 Bearer 타입의 토큰을 보냄)
res.cookie("authorization", `Bearer ${token}`);

으로 사용자에게 보내고

const jwt = require("jsonwebtoken");

module.exports = async (req, res, next) => {
	//쿠키 받아옴
	const {authorization} = req.cookies;
    
    const [authType, authToken] = (authorization ?? "").split(" ");
    if(Bearer토큰인지 확인 등 유효성 검사 진행 ...){
    	res.status(400).json({})
    }
    
    const {"이름"} = jwt.veerify(authToken, "비밀 키")
}

이런식으로 cookie 값을 이용해서 확인 가능
(req.cookies는 cookie-parser를 사용해야만 사용가능)



mySQL sequelize 사용!

npx sequelize init 명령어로 sequelize 기본 구조 작성

config에서 유저 이름, 비밀번호, 데이터베이스 이름, host 값 등을 정해줌
npx sequelize db:create 명령어로 db 생성

몽고 db와는 다르게 migrations과 models 을 사용

예시)
npx sequelize model:generate --name (이름) --attributes (컬럼이름):string,content:string,password:string

아래는 간략한 구조

//migrations

"use strict";
/** @type {import('sequelize-cli').Migration} */
module.exports = {
  async up(queryInterface, Sequelize) {
    await queryInterface.createTable("Posts", {
      postId: {
        allowNull: false, // null값 허용 x
        autoIncrement: true, // 자동으로 1씩 증가
        primaryKey: true, // 기본 키값으로 사용 unique가 자동으로 true
        type: Sequelize.INTEGER, // 타입 설정
      },
      UserId: {
        allowNull: false,
        type: Sequelize.INTEGER,
        references: {    // 참조 
          model: "Users", // 어느 모델에서? "Users"
          key: "userId", // 어떤 값을 기준으로? "userId"
        },
        onDelete: "CASCADE", // "CASCADE"의 경우 Users의 일치하는 userId가 삭제될 경우 같이 삭제된다.
      },
      createdAt: {
        allowNull: false,
        type: Sequelize.DATE,
        defaultValue: Sequelize.fn("now"), // 현재 시간을 자동으로 저장
      },
    });
  },
  async down(queryInterface, Sequelize) {
    await queryInterface.dropTable("Posts");
  },
};
//models
"use strict";
const { Model } = require("sequelize");
module.exports = (sequelize, DataTypes) => {
  class Posts extends Model {
    /**
     * Helper method for defining associations.
     * This method is not a part of Sequelize lifecycle.
     * The `models/index` file will call this method automatically.
     */
    static associate(models) {
      // define association here
	// 현재 모델(Posts)에서 Users 모델에게 다 대 일 관계 설정
      this.belongsTo(models.Users, {
        targetKey: "userId",  // Users 모델 내부의 userId 컬럼과
        foreignKey: "UserId", // Posts 모델의 UserId 컬럼을 연결해줌.
        //migrations에서 설정을 해주어야합니다.
      });
    }
  }

  Posts.init(
    {
      postId: {
        allowNull: false,
        autoIncrement: true,
        primaryKey: true,
        type: DataTypes.INTEGER,
      },
      UserId: {
        allowNull: false,
        type: DataTypes.INTEGER,
      },
      createdAt: {
        allowNull: false,
        type: DataTypes.DATE,
        defaultValue: DataTypes.NOW,
      },
    },
    {
      sequelize,
      modelName: "Posts",
    }
  );
  return Posts;
};

다 작성 후
npx sequelize db:migrate 명령어로 migrate
얼추 기존 몽고디비 사용 때와 비슷하지만
결정적으로 find문들의 사용 방법이 다르다!
쿼리를 날리 때 처럼 where절을 사용

예시

await Users.findOne({where: {nickname}});

//생성때도...
await Users.create({nickname});

//join! 아니.. include
await Users.findOne({
	attributes: ["보여주고싶은거1", "보여주고싶은거2"],
    include:[
    	{
        	model: Users,
            attributes: ["보여주고싶은거1", "보여주고싶은거2"]
        }
    ],
    where: {postId}
});

여기서의 where절은 include에 해당하는 것이 아니라
자기 자신의 findOne에 해당하는 것이고,
include 시의 참조 값은 앞서서
migrations와 models에서 관계 설정을 이미 끝마쳤음!!

즉 전체적인 골자는 비슷하고
다만 몽고디비의 명령어인가 아니면 sequelize의 명령어인가 하는
약간의 차이만 존재했다.

profile
열심히 신나게 화이팅!
post-custom-banner

0개의 댓글