[TIL] 24-11-25
Raw Query
원시 쿼리라고 불리며, Raw Query로 Node.js에서 데이터베이스에 SQL을 이용해 직접 쿼리를 요청할 수 있다.
- 엄청나게 긴 쿼리를 수행하거나 트랜잭션을 직접적으로 관리하는 장점을 가지고 있다.
mysql2 라이브러리 설치
# yarn으로 프로젝트를 초기화합니다.
yarn init -y
# express와 mysql 드라이버를 설치합니다.
yarn add express mysql2
mysql2는 MySQl 데이터베이스를 Node.js에서 사용할 수 있게 도와주는 라이브러리, 데이터베이스 드라이버라는 이름으로 불림
Raw Query 사용법
mysql2 라이브러리에서 Raw Query는 connect.promise().query() 형식으로 사용합니다.
SHOW TABLES
를 통해 테이블을 조회할 수 있습니다.
Raw Query의 단점
-
엄청 많은 서비스와 연관되어 있는 경우 수정해야할 코드가 수백, 수천개가 되어버림
-
사용자의 입력을 그대로 데이터베이스에 요청하기 때문에 SQL 인젝션에 취약함
** ORM을 통해 Node.js에서 SQL을 직접 작성하지 않고, Javascript 만으로 데이터베이스를 조작할 수 있게 되어 코드의 유지보수성이 증가해, 더욱 객체지향적인 프로그래밍이 가능함**
ORM과 Prisma
Prisma는 ORM(Object Relational Mapping)으로써 Javascript 객체(Object)와 데이터베이스 관계(Relation)를 연결(Mapping) 해주는 도구
-
Node.js환경에는 TypeORM, Prisma, Sequelize 등 다양한 ORM이 존재
-
Prisma는 여러가지 관계형 데이터베이스(RDB)를 사용할 수 있음.
ORM 장단점
장점
-
프로덕션에서 사용하는 데이터베이스가 언제 바뀔지 알 수 없다
- Raw Query코드를 전부 고치는 것은 힘들지만, ORM의 경우 속성값만 바꾸면 된다.
-
데이터베이스에서 사용하는 DB 또는 Table 속성이 변경되었을 때 빠르게 수정이 가능
단점
-
극한의 성능을 요하는 상황에서는 Raw Query가 더 좋다
-
복잡한 쿼리를 작성할 때, ORM에 대해 깊이있게 알아야 한다.
Prisma 설치하기
# yarn 프로젝트를 초기화합니다.
yarn init -y
# express, prisma, @prisma/client 라이브러리를 설치합니다.
yarn add express prisma @prisma/client
# nodemon 라이브러리를 DevDependency로 설치합니다.
yarn add -D nodemon
# 설치한 prisma를 초기화 하여, prisma를 사용할 수 있는 구조를 생성합니다.
npx prisma init
-
prisma
는 Prisma를 터미널에서 사용할 수 있도록 도구를 설치하는 패키지- ex)
npx prisma init
- ex)
-
@prisma/client
는 Node.js에서 Prisma를 사용할 수 있게 해줌 -
nodemon
은 개발 코드가 변경되었을 때 자동으로 서버 재시작을 해주는 패키지
npx prisma init
을 통해 prisma 폴더 안에prisma.schema
파일 생성
* prisma.schema
파일은 Prisma가 사용할 데이터베이스를 설정하기 위한 파일이라 절대 지우지 말것
.env
파일이 생성됨
* 이 파일은 외부에 공유되어선 안되는 비밀 정보들이 저장된 파일
.gitignore
파일 생성
* .env
파일이 업로드 되지 않도록 설정되어 있음
여기서 생성된 폴더나 파일들을 절대로 임의로 옮기지 말것!
nodemon 라이브러리는?
파일을 저장할 때마다 변경 사항을 감지하고, 자동으로 서버를 재시작해주는 라이브러리
- 매번 코드를 수정하거나 서버에서 에러가 발생해 종료되었을 때, 매번 서버를 재시작시켜야 하는 문제를 해결해줌
nodemon
명령어
// 프로젝트 내에 nodemon이 설치되어 있으면 앞에 npx를 붙여서 작성할 것
nodemon <실행할 JavaScript 파일명>
nodemon app.js
package.json에 nodemon을 이용해 서버를 실행하는 스크립트를 등록한다면, 매번 명령어를 입력하지 않아도 된다
// package.json
"scripts": {
"dev": "nodemon app.js"
},
이제 터미널에서 yarn run dev
혹은 yarn dev
명령어를 실행하면 nodemon을 이용해 서버를 시작할 수 있음
schema.prisma
Prisma가 사용할 데이터베이스의 설정 정보를 정의하기 위해 사용하는 파일
Prisma를 가장 처음 초기화 했을때, schema.prisma
파일을 확인한다면, 2가지 구문이 작성된 것을 확인할 수 있다.
-
datasource
-
데이터베이스를 정의하기 위해 사용
-
Prisma가 어떤 데이터베이스 엔진을 사용할 것인지, 데이터베이스 위치(URL)은 어디인지의 정보를 정의하는데 사용
-
-
generator
- Prisma 클라이언트를 생성하는 방식을 설정하는 구문
datasource
설정하기
// schema.prisma
datasource db {
// MySQL 데이터베이스 엔진을 사용합니다.
provider = "mysql"
// 데이터베이스 연결 정보를 .env 파일의 DATABASE_URL 로부터 읽어옵니다.
url = env("DATABASE_URL")
}
url
부분에서 env("DATABASE_URL")
방식으로, 데이터베이스의 주소가 노출되지 않게 작성하는 dotenv
의 문법을 사용하고 있는데요.
env()
문법은 프로젝트의 root 폴더에 있는 .env
파일에 정의되어 있는 정보를 해당 schema.prisma
파일로 불러오는 것
여기서, dotenv
는 어플리케이션의 환경 변수(Environment Variables)를 관리하는 모듈입니다.
실제 코드에서는 민감한 정보를 노출시키지 않도록 보호해주고, 개발 환경에 따라 다르게 설정해야 하는 값을 별도의 파일에서 관리할 수 있게 해줌
.env
파일 확인하기
# .env
DATABASE_URL="postgresql://johndoe:randompassword@localhost:5432/mydb?schema=public"
.env
파일은 key-value의 형태로 구성되어 있고, DATABASE_URL
이라는 하나의 변수가 선언되어있는 것을 확인할 수 있다.
데이터베이스 URL
데이터베이스 URL은 Prisma가 어떤 데이터베이스와 어떻게 연결할지를 알려주는 중요한 정보
URL 내부에는 데이터베이스 엔진 유형, 사용자 아이디, 패스워드와 같은 정보가 포함
데이터베이스 URL은 크게 4가지로 나눠집니다.
-
Protocol
-
Prisma가 사용할 데이터베이스 엔진을 나타냅니다.
-
postgresql
,sqllite
,mysql
과 같은 데이터베이스 엔진을 정의합니다.
-
-
Base URL
-
데이터베이스의 엔드 포인트와 아이디, 패스워드, 포트 번호를 나타냅니다.
-
<Id>:<Password>@<RDS Endpoint>:<Port>
의 형태로 구성됩니다.
-
-
Path
- MySQL에서 사용할 데이터베이스 이름을 설정하는 구성 요소입니다.
-
Arguments
-
Prisma에서 데이터베이스 연결을 설정하는데 필요한 추가 옵션을 나타냅니다.
-
데이터베이스와 연결할 수 있는 최대 커넥션 갯수, 타임아웃 시간 등이 있습니다.
-
Prisma model
Prisma의 model
구문은 특정 Table과 Column의 속성값을 입력하여, 데이터베이스와 Express 프로젝트를 연결 (Mapping)시켜줌
-
modle
구문은 Prisma를 사용할 때 가장 많이 작성하게 될 구문이며, Prisma가 사용할 데이터베이스의 테이블 구조를 정의하기 위해 사용 -
schema.prisma
파일에서는model
에 작성된 정보를 바탕으로 Prisma Client를 통해 JavaScript에서 MySQL의 테이블을 조작할 수 있게 됨 -
model
구문은 Javascript에서 MySQL의 테이블을 사용하기 위한 다리 역할을 수행하며, MySQL과 실제 연결되어 사용할 수 있게 도와 줌
상품 테이블 예시
// schema.prisma
model Products {
productId Int @id @default(autoincrement()) @map("productId") // @id는 Primary KEY 지정, @default(autoincrement())는 기본 값(1씩증가)
productName String @unique @map("productName") // @map("productName")이 컬럼명이고 왼쪽에 있는 productName은 Node.js에서 쓰는 명
price Int @default(1000) @map("price") // @default(1000) 기본값으로 아무것도 입력하지 않았을때 1000으로 지정됨
info String? @map("info") @db.Text // 데이터 유형 뒤 '?'는 NULL을 허용하는 컬럼, @db.Text를 이용해서 db내에서 text라는 타입을 별도로 가질 수 있음
createdAt DateTime @default(now()) @map("createdAt")
updatedAt DateTime @updatedAt @map("updatedAt") // @updatedAt 자동 현재시간 반영
@@map("Products") // @@map("Products")을 사용하지 않으면 테이블명의 대문자는 전부 소문자로 치환 됨
}
Prisma DB, Table 생성
# schema.prisma 파일에 설정된 모델을 바탕으로 MySQL에 정보를 업로드
npx prisma db push
여러가지 Prisma CLI
-
prisma db push
-
schema.prisma 파일에 정의된 설정값을 실제 데이터베이스에 반영(push)
-
내부적으로 prisma generate가 실행
-
데이터베이스 구조를 변경하거나 새로운 테이블을 생성할 수 있음
-
-
prisma init
-
Prisma를 사용하기 위한 초기 설정을 생성
-
이 명령어를 실행하면 schema.prisma 파일과 같은 필요한 설정 파일들이 생성
-
-
prisma generate
-
Prisma Client를 생성하거나 업데이트
-
대표적으로, schema.prisma 파일에 변경 사항이 생겼거나, 데이터베이스 구조가 변경되었을 때, 이 명령어를 사용해 Prisma Client를 최신 상태로 유지할 수 있음
-
-
prisma db pull
-
현재 연결된 데이터베이스의 구조를 prisma.schema 파일로 가져옴(pull)
-
데이터베이스에서 구조 변경이 발생했을 때, 이 명령어를 사용하면 Prisma Schema를 최신 상태로 유지할 수 있음
-
이후 prisma generate 명령어를 사용해 변경 사항을 Prisma Client에 반영할 수 있음
-
Prisma Client
Prisma는 model을 generate하면, 해당 모델에 대한 정보가 node_modules폴더 내에 있는 Prisma Client에 전달됨
→ 이전에 사용한 prisma db push
도 내부적으로 generate
가 실행
Prisma Client는 Prisma Schema에 정의한 데이터베이스 모델(model)을 TypeScript 코드로 변환하여, 개발자가 데이터베이스와 상호작용할 수 있게 해줌
이러한 과정을 통해, 데이터베이스를 JavaScript에서 손쉽게 다룰 수 있게 되고, Prisma Schema와 동기화된 Prisma Client를 이용해 데이터베이스를 사용할 수 있게 되는 것입니다.
Prisma Method
Prisma는 mongoose와 동일하게, findMany(), findFirst(), findUnique() 등 다양한 메서드를 지원
mongoose를 사용했을 때는 Schema를 이용해 DB를 사용하였다면, Prisma에서는 Prisma Client를 이용해 MySQL의 데이터를 조작
쿠키와 세션
쿠키
-
쿠키는 사용자가 웹사이트를 방문할 때마다 이전에 방문했던 정보를 기억하는 데이터 파일
-
데이터를 여러 사이트에 공유할 수 있어 보안에 취약
-
쿠키는 문자열 형식으로 존재, 쿠키간에는 세미콜론으로 구분
세션
-
쿠키를 기반으로 구성된 기술
-
쿠키와 다르게 세션은 데이터를 서버에만 저장
-
보안성이 좋으나, 사용자가 많은 경우 서버에 많은 부하가 걸림
JWT
JWT는 웹 표준으로, 서버와 클라이언트 사이에서 정보를 안전하게 전송하기 위해 도움을 주는 웹 토큰
header.payload.signature
의 형식으로 3가지 데이터를 포함한다.
-
Header: 헤더는 어떤 암호화를 사용했는지와, 토큰의 타입이 정의되어 있다.
-
Payload: 페이로드는 실제 전달하려는 데이터를 담고 있다.
-
Signature: 서명은 헤더와 페이로드, 그리고 비밀키를 이용해 생성됨, 이 서명은 토큰이 변조되지 않은 정상적인 토큰인지 확인할 수 있게 도와줌
JWT 특징
-
비밀 키를 몰라도 복호화 가능
-
JWT를 가진 사람이라면 누구나 해당 토큰에 어떤 데이터가 있는지 확인 가능
-
변조만 불가능 할 뿐
-
-
민감한 정보(개인정보, 비밀번호 등)은 담지 말 것
-
JavaScript 이외에 다른 언어에서도 사용가능
- JWT는 단순히 데이터 형식일 뿐
JWT 사용법
# yarn을 이용해 프로젝트를 초기화합니다.
yarn init -y
# jsonwebtoken, express 라이브러리를 설치합니다.
yarn add jsonwebtoken express
JWT를 써야하는 이유!
-
JWT가 인증 서버에서 발급되었는지 위변조 여부를 확인할 수 있음
-
누구든지 JWT 내부에 들어있는 정보를 확인할 수 있음
인증, 인가
인증(Authentication)
인증(Authentication)은 서비스를 이용하려는 사용자가 인증된 신분을 가진 사람이 맞는지 검증하는 작업 (신분증 검사에 해당)
-
인증은 일반적인 사이트의 로그인 기능에 해당
-
로그인 기능은 일반적으로
id
,password
조합으로 이루어짐
인가(Authorization)
인가(Authorization)는 이미 인증된 사용자가 특정 리소스에 접근하거나 특정 작업을 수행할 권한이 있는지를 검증 (놀이공원 자유이용권 확인에 해당)
- 인증(로그인) 된 사용자가 게시글을 작성할 수 있는지 검증한다면, 이 과정을 인가 과정이라 부름
bcrypt
일반적으로, 사용자의 비밀번호를 데이터베이스에 저장할 때, 보안을 위해 비밀번호를 평문으로 저장하지 않고 암호화 하여 저장
- 개인정보보호법에서는 주민등록번호와 같은 정보는 암호화되어 저장되어야 함
bcrypt 모듈이란?
bcrypt 모듈은 입력받은 데이터를 특정 암호화 알고리즘을 이용하여 암호화 및 검증을 도와주는 모듈
- 문자열을 단방향 암호화함