TypeORM에서 제공하는 연결(Pooling) 기능을 사용하여, 데이터베이스에 Create, Read, Update, Delete 작업을 수행할 수 있는 API로 발전시켜 작은 프로젝트 앱을 완성하자
흰색박스는 비밀번호이다.
crud_express는 생성해놓은 데이터베이스 이름이다
👉나중에 알았지만 TYPEORM_DATABASE =
westagramcrud_express
.env.sample 파일
: 상단에 database_url을 작성한다
DATABASE_URL = "mysql://username:password@127.0.0.1:3306/database_name"
db
라는 폴더를 생성
db
라는 명칭
dbmate가 기본으로 migration/shema 파일이 저장되도록 설정한 디렉토리 명칭이다. 별도의 네이밍을 원한다면 공식문서를 참고하여 스스로 설정할 것.
dbmate 전역으로 설치:
npm install -g dbmate
👉 로컬로 설치하면 command not found 오류 발생!
$ dbmate new create_books_table
$ dbmate new create_authors_table
$ dbmate new create_book_authors_table
tree커맨드 설치: brew install tree
tree로 db에 생성된 파일 확인하기 tree db
각 테이블.sql파일의 구조
책 테이블을 생성하고, 내부 컬럼 필드, 데이터 속성을 정의하는 SQL문
작가의 테이블을 정의하는 SQL문
작가와 책을 연결하는 중간테이블을 정의하는 SQL문
-- migrate:up
테이블의 각 요소들을 정의한다.
-- migrate:down
down명령을 쓰면 모든 box의 테이블을 drop시켜 데이터베이스에서 삭제한다.
dbmate up
schema.sql
: migration이 정상 작동하며 데이터베이스에 준 모든 변화를 기록
// app.js
const http = require("http");
const express = require("express");
const cors = require("cors");
const morgan = require("morgan");
const dotenv = require("dotenv");
dotenv.config();
const {appendFile} = require("fs")
const { DataSource } = require("typeorm");
const myDataSource = new DataSource({
type: process.env.TYPEORM_CONNECTION,
host: process.env.TYPEORM_HOST,
port: process.env.TYPEORM_PORT,
username: process.env.TYPEORM_USERNAME,
password: process.env.TYPEORM_PASSWORD,
database: process.env.TYPEORM_DATABASE
})
myDataSource.initialize()
.then(() => {
console.log("Data Source has been initialized!")
})
.catch((err) => {
Console.error("Error during Data Source initialization", err)
myDataSource.destroy()
})
const app = express();
const PORT = process.env.PORT;
app.use(cors());
app.use(morgan('dev'));
app.use(express.json());
// health check
app.get("/ping", (req,res) => {
// 201을 200으로 바꿔서 통신되는지 확인하기!
res.status(201).json({ message : "pong" });
})
/*
앞으로
생성, 수정, 조회, 삭제 에 대한 구현을 할 것이다!
*/
const server = http.createServer(app);
const start = async () => {
try{
app.listen(PORT, () => console.log(`Server is listening on ${PORT}`));
} catch (err) {
console.error(err);
}
}
start();
상태코드 200 <-> 201 비교하기
// create a book
app.post("/books", async (req, res, next) => {
const { title, description, coverImage } = req.body
// console.log(req)
await myDataSource.query(
`INSERT INTO books(
title,
description,
cover_image
) VALUES (?, ?, ?);
`,
[ title, description, coverImage ]
);
res.status(201).json({ message : "successfullty created" });
})
설명
?
순서에 맞게 매칭되어 들어가게끔 잘 정의한다실행:
$ http -v POST 127.0.0.1:3000/books title="test title" description="test description" coverImage="test coverImage.url"
실행결과:
// Get all books
app.get('/books', async (req, res) => {
await myDataSource.manager.query(
`SELECT
b.id,
b.title,
b.description,
b.cover_image
FROM books b`
, (err, rows) => {
res.status(200).json(rows);
})
});
설명
books테이블에 데이터를 2개 더 추가, 실행했을 때:
http -v GET 127.0.0.1:3000/books
// Get all books along with authors
app.get('/books-with-authors', async (req, rea) => {
await myDataSource.manager.query(
`SELECT
books.id,
books.title,
books.description,
books.cover_image,
authors.first_name,
authors.last_name,
authors.age
FROM books_authors ba
INNER JOIN authors ON ba.author_id = authors.id
INNER JOIN books ON ba.book_id = books.id`
, (err, rows) => {
res.status(200).json(rows);
})
});
설명
authors 테이블에 test data 1개를 입력하고
books_authors 테이블에도 books와 tables를 잇는 test data 1개 입력
실행:
http -v GET 127.0.0.1:3000/books-with-authors
// Update a single book by its primary key
app.patch('/books', async(req, res) => {
const { title, description, coverImage, bookId } = req.body
await myDataSource.query(
`UPDATE books
SET
title = ?
description = ?
cover_image = ?
WHERE id = ?
`,
[ title, description, coverImage, bookId ]
);
res.status(201).json({ message : "successfully updated" })
});
실행
=
을 쓸 때 양옆에 띄어쓰기하면 안된다http -v PATCH 127.0.0.1:3000/books bookId='2' title='new title' description='new description' coverImage='new coverImage'
비교하기
:bookId
의 개념
클라이언트 선에서 뒷 부분에 책의 id값을 의도대로 기입할 수 있게 설정하는 방법
// Delete a book
app.delete('/books/:bookId', async(req,res)=>{
const { bookId } = req.params;
await myDataSource.query(
`DELETE FROM books
WHERE books.id = ${bookId}
`);
res.status(200).json({ message : "successfully deleted" }); // status 204의 사용도 권장함
});
설명
실행: id=3인 책을 삭제하시오
http -v DELETE 127.0.0.1:3000/books/3
비교하기
근데 삭제 시 상태코드는 204
가 추천된다
204
는 뒤에 작성한 json메시지가 전달되지 않는 특징이 있다(비워두기)
res.status(204).json();
실행: id=3인 책을 삭제하고 204 코드 확인하시오