TIL230920_ Express.js (미들웨어) 와 Prisma 세팅

박지은·2023년 9월 20일
0

TIL

목록 보기
27/36

배포를 위한 yarn 학습

# npm을 이용하여 전역 환경에 Yarn을 설치합니다!
npm install -g yarn

yarn -v 로 확인
yarn init : 새로운 프로젝트나 패키지 시작 (package.json)
yarn add 패키지명 -> yarn add express

Express.js 프레임워크

Express.js 프레임워크 -> 말그대로 웹서버 개발을 편리하게 만드는 틀/ 도구 - 가장 큰 특징은 미들웨어를 지원해준다는 점 (Auth, logging,에러처리핸들러 등 ➕ 클라이언트의 req를 받을 때, body에 있는 데이터를 분석할 수 있게 해줌 JSON형태로 body를 입력받을 수 있게 됨 )

  • 또 다른 웹프레임워크가 있는데, Nest.js는 Typescript와 함께 사용해서 쓴다

vs코드 폴더 오픈
app.js 파일 만들기
터미널 열어서 yarn init -y 로 package.json 생성 (알아서 프로젝트명이나 버전을 기본값으로 정해달라는 명령어)
package.json 파일에서 "type": "module" 추가 (이렇게 해야 ES6 모듈 사용가능)

{
	"name": "spa-shop",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "type": "module"
}

yarn add express (Express.js 설치)
여기까지 하면 폴더구조가 아래와 같음 - package.json에 들어가서 express 관련된 내용이 있으면 정상 설치 완료

➕ yarn.lock 이란? 어떤 패키지들이 어떤 버전으로 설치되었는지를 기록해놓은 파일 ( 왜 필요? 나중에 이 파일이 있으면 협업할 때 같은 환경으로 개발할 수 있게 도와줌)

➕ node_modules 란? yarn을 통해 설치된 패키지들에 대한 파일이 모여있는 폴더 ⭐️이 폴더는 공유하거나 배포할 때 포함되어서는 ❌!! 안됨!!

미들웨어의 기본개념

미들웨어 ?

  • 웹 서버에서 요청을 받을 때, 모든 요청에 대한 공통적인 처리를 하고 싶을 때, 필요한게 미들웨어
  • req- res 중간에 위치해 특정 기능을 수행하는 함수

전역 미들웨어로 등록하는 방법 -> app.use()
➕ app.use('/api', router); 코드 설명 - app.use 는 미들웨어를 사용하게 해주는 코드! 뒤의 경로로 접근하는 경우에만 json 미들웨어를 거친 뒤, router로 연결되도록 하는 것!

// app.js 
// Express에서 req.body에 접근하여 body 데이터를 사용할 수 있도록 설정합니다.
app.use(express.json());
app.use(express.urlencoded({ extended: true }));

이렇게 하면 Body Parser는 클라이언트의 요청 req 본문 데이터인 body를 쉽게 파싱할 수 있게 해주는 미들웨어임

app.use((req, res, next) => {
  // 필요한 코드
});

여기서 next(); 다음 스택으로 정의된 미들웨어 호출
하지만 미들웨어를 거치는 중간에 next() 가 실행되지 않으면 다음 미들웨어는 실행되지 않고, 클라이언트의 요청은 거기서 종료됩니다.

➕ 현재 미들웨어에서 응답을 보내는 경우, 즉 res.send()이나 res.json()등의 메서드를 호출하는 경우에는 next() 를 호출하면 안됩니다. 이렇게 하지 않으면 이미 요청이 종료된 상태에서 다른 미들웨어가 응답을 보내려고 하여 중복된 요청이 전달되는 문제가 발생하게됩니다.

라우터와 미들웨어의 차이

  • Router와 미들웨어는 서로 다른 방식처럼 보이지만 Router는 미들웨어 기반으로 구현된 객체이므로 미들웨어와 동일한 방식으로 작동됩니다.
  • 즉, Router는 미들웨어 함수를 특정 경로에 바인딩하는 역할을 하며, 요청이 들어온 URL 경로에 따라 서로 다른 미들웨어를 실행시킬 수 있게 도와줍니다.

에러처리 미들웨어

에러처리는 왜 해야할까?
원하지 않았던 비즈니스 로직이 수행되지 않게! 예상치 못한 문제를 미리 방지해 서버가 안정적으로 되도록

Express.json의 에러처리 미들웨어

app.use((err, req, res, next) => {
  console.error(err.stack);
  res.status(500).send('Something broke!');
});

에러처리 미들웨어에서 err, req, res, next 와 같이 에러, 요청, 응답, 다음 미들웨어를 호출하는 함수

err: 이전 미들웨어에서 발생한 에러를 전달받은 객체
req, res : HTTP 요청과 응답을 관리하는 객체
next: 다음 미들웨어를 실행하는 함수

// app.js

import ErrorHandlerMiddleware from './middlewares/error-handler.middleware.js';

...
//app.js

// /api 주소로 접근하였을 때, router와 TodosRouter로 클라이언트의 요청이 전달됩니다.
app.use('/api', [router, TodosRouter]);

// 에러 핸들링 미들웨어를 등록합니다.
app.use(ErrorHandlerMiddleware);

⭐️에러처리 미들웨어는 하단에 등록! 왜냐하면, 미들웨어는 등록된 순서대로 실행되기 때문!! 순서가 TodoRouter에서 비즈니스 로직을 수행한 후 발생한 에러를 다음 미들웨어로 전달되기 때문에

➕ app.js 파일의 역할

  • 전체 어플리케이션의 시작점
  • 미들웨어와 라우터를 등록하고, 서버를 시작하는 역할을 담당

ORM 과 Prisma

📢 입문주차에는 noSQL 인 mongoDB를 사용했으나, 이번에는 RDBMS인 mySQL을 사용
여기서 mongoDB는 moongoose를 사용해서 (ODM - Object Document Mapping) 으로 Javascript 객체와 데이터베이스 관계를 매핑mapping(연결) 해주는 도구를 사용했으나,
mySQL에서는 Prisma를 사용하여 ORM (Object Relational Mapping)으로 Javascript 객체와 데이터베이스의 관계 relation을 연결해주는 차이가 있음

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를 실행할 수 있도록 도구를 설치하는 명령어
@prisma/client: 우리가 node.js 에서 Prisma를 사용할 수 있게 해줌
nodemon: 개발코드가 변경되었을 때, 자동으로 서버를 재시작해주는 패키지
➕ package.json에 아래와 같은 내용 추가

// package.json

...

"scripts": {
	"dev": "nodemon app.js"
},

이렇게 하면 yarn run dev 라고 하면 nodemon 실행

npx prisma init : 아래와 같은 directory structure

내 프로젝트 폴더 이름
├── prisma
│   └── schema.prisma
├── .env
├── .gitignore
├── package.json
└── yarn.lock

schema.prisma

datasource 설정하기 : Prisma가 데이터베이스를 연결할 수 있도록 설정, 관리하는데 필요한 정보를 설정

// schema.prisma

datasource db {
  // MySQL 데이터베이스 엔진을 사용합니다. /즉, 관계형 데이터베이스 엔진이 무엇인지 알려줌
  provider = "mysql"
  // 데이터베이스 연결 정보를 .env 파일의 DATABASE_URL 로부터 읽어옵니다.
  url      = env("DATABASE_URL")
}

Prisma model 설정하기

궁금했던 거

  • 데이터 유형 뒤에 ?가 붙게 된다면, NULL을 허용하는 컬럼이 됩니다.

  • @@map("Products")Products 테이블을 MySQL에서도 Products란 이름으로 사용하겠다는 뜻입니다. @@ 테이블 명을 정의하기 위해 사용됨

    @@map() 을 작성하지 않으면, 테이블명의 대문자는 전부 소문자로 치환된답니다. 🥲 실제 데이터 베이스에 있는 테이블명을 대문자로 사용하기 위해서 이렇게 사용함

 # schema.prisma 파일에 설정된 모델을 바탕으로 MySQL에 정보를 업로드합니다.(여러분들의 실제 데이터 베이스에 반영이 된다. )
npx prisma db push

npx prisma db push 는 내부적으로 prisma generate가 실행됩니다.

npx prisma generate
  • Prisma Client를 생성하거나 업데이트
  • 대표적으로, schema.prisma 파일에 변경 사항이 생겼거나, 데이터베이스 구조가 변경되었을 때, 이 명령어를 사용해 Prisma Client를 최신 상태로 유지할 수 있습니다.

Prisma 리팩토링

PrismaClient 는 Prisma를 사용하여 실제 데이터베이스와의 연결을 관리하는 객체입니다.
new PrismaClient()를 이용해 JavaScript에서 Prisma를 사용할 수 있도록 인스턴스를 생성하게됩니다.

// 이건 Prisma Client 인스턴스를 생성한다는 내용 
const prisma = new PrismaClient();

그러나 각 라우터마다 연결하는 건 비효율적
최대한 데이터베이스의 연결을 줄이는 것이 효율적

이런 문제를 해결하기 위해 저희는 /utils/prisma/index.js 파일을 구현하여, 하나의 파일에서 데이터베이스 커넥션을 관리하여 최초로 1번만 MySQL과 커넥션을 생성하도록 코드를 구현하면 된답니다!

utils/prisma/index.js Prisma 리팩토링

// utils/prisma/index.js

import { PrismaClient } from '@prisma/client';

export const prisma = new PrismaClient({
  // Prisma를 이용해 데이터베이스를 접근할 때, SQL을 출력해줍니다.
  log: ['query', 'info', 'warn', 'error'],

  // 에러 메시지를 평문이 아닌, 개발자가 읽기 쉬운 형태로 출력해줍니다.
  errorFormat: 'pretty',
}); // PrismaClient 인스턴스를 생성합니다.

routes/posts.router.js Prisma 리팩토링
⭐️⚠️ 꼭! 상단의const prisma = new PrismaClient() 구문은 삭제해주세요!

// routes/posts.router.js

import { prisma } from '../utils/prisma/index.js';
profile
성장하는뿅아리

0개의 댓글

관련 채용 정보