Node 강의/숙련

1-6 Raw Query시작하기

kagan-draca 2024. 9. 6. 14:50

1. Raw Query란?

Raw Query 데이터베이스에 SQL(Structured Query Language)을 이용하여 직접 쿼리(Query)를 요청하는 것

 

2. Raw Query 시작하기

 

Raw Query를 사용하기 위해 폴더를 생성하고, 라이브러리 설치, 프로젝트 구성을 진행해봅시다.

 

Node.js에서 Raw Query를 사용하기 위해서는 AWS RDS에서 대여받은

MYSQL에 연결을 도와주는 데이터베이스 드라이버가 필요합니다.

 

이번에는 데이터베이스에 직접 SQL를 요청하여, 테이블을 생성하거나,

데이터를 삽입하는 다양한 API를 mysql2 라이브러리를 이용하여 구현해봅시다.

 

VScode에서

yarn add express

yarn add mysql2

 

를 입력해 MySQL 드라이버를 설치합니다.

 

우리가 만들 RAW Query API 명세서는

 

 

위와 같이 만들어 볼 예정 입니다.

 

3. 데이터 베이스 연결하기

VScode에서 서버와 데이터베이스를 연결하는 방법으로는

import express from "express";
import mysql from "mysql2";

const connect = mysql.createConnection({
  host: "AWS RDS 엔드포인트 주소", //AWS RDS 엔드포인트
  user: "admin 계정 아이디", // AWS RDS 계정명
  password: "비밀번호", // AWS RDS 비밀번호
  database: "데이터 베이스 이름", // 연결할 MySQL DB 이름
});

const app = express.Router();
const PORT = 3017;

app.use(express.json());
app.use(express.urlencoded({ extended: true }));

app.listen(PORT, () => {
  console.log(PORT, "포트로 서버가 열렸습니다!");
});

위와 같은 방식으로,

 

connect = mysql.createConnection({})

 

코드를 바탕으로 사용 가능합니다.

 

host : "AWS RDS 엔드 포인트 주소"

 

user : "admin 계정 아이디"

 

password : "비밀번호"

 

database : "데이터 베이스 이름"

 

을 넣어줘야 합니다. 이외에도,

 

timezone : 시간대 설정, ssl : SSL 인증서 설정

 

등 다양한 옵션이 있습니다.

 

4. 테이블 생성 API

 

첫 번째로 Raw Query를 이용하여 테이블을 생성하는 API를 만들어 보도록 하겠습니다.

 

 

테이블의 구조는 위와 같은 필드를 가지도록 작성할 예정입니다.

 

테이블 구조를 바탕으로 app.js 테이블 생성 API

 

app.post("/api/tables/", async (req, res, next) => {
  const { tableName } = req.body;

  // 콜백 함수가 정상 수행하면(promise) 되면
  await connect.promise().query(`
        CREATE TABLE ${tableName}
        (
            id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
            name VARCHAR(20) NOT NULL,
            createdAt DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
        )
    `); // DEAULT는 값을 주지 않아도 오른쪽에 할당된 값을 바로 넣어주는 문법
  // CURRENT_TIMESTAMP는 현재 시간을 제공하는 문법
  return res.status(201).json({ message: "테이블 생성에 성공하였습니다." });
});

위의 코드를 추가해줍니다.

connect는 비동기 함수이기 때문에

connect가 정상 수행 됐는지 확인하기 위해 promise()를 사용합니다.

 

CREATE TABLE ${tableName}로 Clinet가 입력한 테이블 이름으로,

테이블이 생성되게 만들어줍니다.

 

필드(field)에서 createdAtDATETIME으로 날짜 타입을 받을거고,

DEFAULT CURRENT_TIMESTAMP로 Clinet에게 날짜를 입력받지

않더라도 날짜가 자동으로 입력되게 만들어줍니다. 

 

이제 Insomnia에서 테이블을 생성해봅시다.

 

JSON 파일 형식으로 "tableName"을 지정해주고, SEND 하면

정상적으로 테이블이 만들어진걸 확인할 수 있습니다.

 

그리고, 해당 DB에 table이 생성된걸 볼 수 있습니다.

 

5. 테이블 목록 조회 API

 

테이블을 조회하는 명령어로는

 

SHOW TABLE

 

가 있습니다. 명령어로 현재까지 생성된

여러가지의 테이블을 확인할 수 있습니다.

 

app.js 테이블 목록 조회 API 구현해보기

 

// 테이블 조회 API
app.get("/api/tables", async (req, res, next) => {
  const [tableList] = await connect.promise().query(`SHOW TABLES`);
  // ShOWTABLE 이라는 명령어를 사용해서 DB에 있는 전체 Table을 배열형식으로 가져온다.
  const tableNames = tableList.map(table => Object.values(table)[0]);

  return res.status(200).json({ tableList: tableNames });
});

 

여기서

 

const [tableList] = await connect.promise().query(`SHOW TABLES`);

 

로 DB에 있는 테이블 전체 목록을 배열형식으로 가져옵니다.

 

Insomnia에서 tableList를 확인해보면

 Tables_in_express_db(express_db 안 Table로는) : "rawQueryTable" 이 있다는 걸 확인할 수 있습니다.

그리고, 결과가 객체반환된걸 확인할 수 있습니다.

 

그래서,

 

  const tableNames = tableList.map(table => Object.values(table)[0]);

 

map(table =>

 

tableList안에 있는 요소에 접근하고,

 

Object.values(table)

 

요소의 객체에 해당하는 value만 가져온 뒤

 

[0]

 

으로 가져오고 싶은 테이블을 가져옵니다.

 

(가져오고 싶은 테이블이 다르다면 [index]로 가져올 수 있습니다)

 

return res.status(200).json({ tableNames });

 

마지막으로, res(response) json 형식으로

원하는 테이블을 Clinet에게 응답해줍니다.

 

Insomnia에서 tableName를 확인해보면

으로 원하는 Table이 Clinet에게 응답으로 온 것을 확인할 수 있습니다.

 

6. 데이터 삽입 API

INSERT INTO 문법을 사용해서 특정 테이블Values를 넣어봅시다.

 

// 데이터 삽입 API
app.post("/api/tables/:tableName/items", async (req, res, next) => {
  //필요한 정보 : 테이블 이름, value들

  const { tableName } = req.params;
  // 사용할 table은 params(URL)로 전달 받을 예정
  const { name } = req.body;
  // table에 이름을 받아오기 때문에 name 사용

  await connect.promise().query(`
        INSERT INTO ${tableName}(name) VALUES('${name}')
    `);
  //INSERT INTO 사용할 테이블(필요한 Fields) VALUES(넣을 값)

  res.status(201).json({ message: '데이터 생성에 성공했습니다.' });
});

 

query문 안에

 

` INSERT INTO ${tableName}(name) VALUES('${name}')`

으로 Client가 입력한 테이블 이름에 name 값을 가져와

테이블 안에 넣어줍니다.

 

Insomnia에서 테이블에 데이터 넣기

 

 

7. 데이터 조회 API

 

SELECT 문법을 query 안에 작성해 조회해보겠습니다.

 

// 데이터 조회 API
app.get('/api/tables/:tableName/items', async (req,res,next)=>{
    const {tableName} = req.params;
    const [itemList] = await connect.promise().query(`
        SELECT name,createAt FROM ${tableName}
    `)
    // 데이터들이 배열 형식으로 조회되기 때문에
    // [itemList] 로 검색된 결과를 배열로 받아준다.
    return res.status(200).json({itemList});
    // 결과를 Client에게 전달한다.
})

 

 

Insomnia에서 데이터를 조회해보면

 

7. Raw Query의 단점

 

1. 만약 저희가 구현한 API의 테이블 컬럼(필드)를 수정하게 되었을 때, 어떤 문제가 발생할까요?

 

createdAt이라는 컬럼createDate 라는 이름으로 변경한다면 관련된 모든 코드를 수정해야 합니다...

 

현재 createAt을 사용하는 API가 1, 2개라 괜찮지만, API가 수백, 수천일 경우

하나라도 누락하게 된다면 서버가 깨져버리는 문제가 발생하게 됩니다...

 

2. 사용자가 전달한 데이터를 데이터베이스에 직접 요청하게 되므로 사용자가 악의적인 퀴리로 서버에 접속하여

관리자의 계정을 탈취하거나 다른 사용자들의 정보를 탈취하는 것과 같이 모든 웹 사이트 해킹 기법 중 가장 많은

문제를 야기하는 SQL 인젝션의 취약점을 가지게 될 수 있습니다.

 

 

이러한 문제를 해결하기 위해, ORM이라는 기술

 

ORM을 통해 Node.js에서 SQL을 직접 작성하지 않고,

JavaScript만으로 데이터베이스를 조작할 수 있게 돼

코드의 유지보수성이 증가하게 되고, 최종적으로 객체지향적인

프로그래밍을 가능하게 만들 수 있습니다.