Step1: 프로젝트 초기 설정
패키지 관리자는 yarn을 사용였습니다.
먼저 프로젝트에 대한 새 디렉토리를 만들고 해당 디렉토리로 이동 후 Yarn 프로젝트를 초기화합니다.
mkdir my-project
cd my-project
yarn init -y
Step2: 프로젝트 초기 설정
Node.js, TypeScript, Express, TypeORM 및 PostgreSQL에 대한 패키지를 설치합니다.
yarn add express typeorm reflect-metadata pg
yarn add -D typescript ts-node @types/node @types/express
1. 'yarn add express typeorm reflect-metadata pg'
이 명령어는 express, typeorm, reflect-metadata, pg 패키지를 설치합니다. 이 패키지들은 프로젝트의 런타임 의존성으로 설치됩니다.
- express: Node.js를 위한 빠르고 간단한 웹 프레임워크입니다. HTTP 서버를 쉽게 구축할 수 있게 해줍니다.
- typeorm: TypeScript와 JavaScript(ES7, ES6, ES5)를 위한 ORM(Object Relational Mapper)입니다. 데이터베이스와 상호작용을 쉽게 해줍니다.
- reflect-metadata: 메타데이터를 사용하여 객체지향 프로그래밍을 지원하는 데 필요한 라이브러리입니다. TypeORM에서 데코레이터 기능을 사용할 때 필요합니다.
- pg: PostgreSQL 데이터베이스와 상호작용하기 위한 PostgreSQL 클라이언트입니다.
2. 'yarn add -D typescript ts-node @types/node @types/express'
이 명령어는 typescript, ts-node, @types/node, @types/express 패키지를 개발 의존성으로 설치합니다. 즉, 이 패키지들은 개발 중에만 필요하며, 프로덕션 빌드에는 포함되지 않습니다.
- typescript: TypeScript 컴파일러입니다. TypeScript 코드를 JavaScript로 변환해줍니다.
- ts-node: TypeScript 실행 환경입니다. TypeScript 코드를 실행할 수 있게 해줍니다.
- @types/node: Node.js의 타입 정의 파일입니다. TypeScript에서 Node.js 내장 모듈을 사용할 때 타입 정보를 제공합니다.
- @types/express: Express의 타입 정의 파일입니다. TypeScript에서 Express를 사용할 때 타입 정보를 제공합니다.
Step3: TypeScript 설정
프로젝트 루트경로에 tsconfig.json 파일을 생성하고 TypeScript 설정을 구성합니다.
{
"compilerOptions": {
"target": "ES6",
"module": "commonjs",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"outDir": "./dist",
"emitDecoratorMetadata": true,
"experimentalDecorators": true
},
"include": ["src/**/*.ts"],
"exclude": ["node_modules"]
}
Step4: TypeORM 구성 설정
프로젝트 루트경로에 src/data-source.ts 파일을 생성하고 설정을 구성합니다.
import "reflect-metadata";
import { DataSource } from "typeorm";
import { User } from "./entity/User";
export const AppDataSource = new DataSource({
type: "postgres",
host: "localhost",
port: 5432,
username: "your-username",
password: "your-password",
database: "your-database",
synchronize: true,
logging: false,
entities: [User],
migrations: [],
subscribers: [],
});
'your-username', 'your-password', 'your-database'는 PostgreSQL 설치할때 설정 값으로 바꿉니다
Step:5 엔티티 생성
User 및 GenderStatistics 엔티티를 생성합니다.
User 엔티티
import { Entity, PrimaryGeneratedColumn, Column } from "typeorm";
@Entity()
export class User {
@PrimaryGeneratedColumn()
id!: number;
@Column()
firstName!: string;
@Column()
lastName!: string;
@Column()
age!: number;
}
GenderStatistics 엔티티
import { Entity, PrimaryGeneratedColumn, Column } from "typeorm";
@Entity()
export class GenderStatistics {
@PrimaryGeneratedColumn()
num!: number;
@Column({ nullable: true })
poll_id!: string;
@Column({ nullable: true })
trait!: string;
@Column({ nullable: true })
gender!: string;
@Column({ nullable: true })
gender_cnt!: number;
@Column("float", { nullable: true })
rate!: number;
}
rate 필드는 소수점 값으로 저장할 수 있도록 설정하였습니다.
Step6: 리포지토리 생성
위의서 만든 각 엔티티에 해당하는 리포지토리를 생성하여 데이터베이스 작업을 처리합니다.
userRepository.ts
import { AppDataSource } from "../data-source";
import { User } from "../entity/User";
const userRepository = AppDataSource.getRepository(User);
export const createUser = async (userData: Partial<User>): Promise<User> => {
const user = userRepository.create(userData);
return await userRepository.save(user);
};
export const getUserById = async (id: number): Promise<User | null> => {
return await userRepository.findOneBy({ id });
};
genderStatisticsRepository.ts
import { AppDataSource } from "../data-source";
import { GenderStatistics } from "../entity/GenderStatistics";
const genderStatisticsRepository = AppDataSource.getRepository(GenderStatistics);
export const createGenderStatistics = async (data: Partial<GenderStatistics>): Promise<GenderStatistics> => {
const genderStat = genderStatisticsRepository.create(data);
return await genderStatisticsRepository.save(genderStat);
};
export const getGenderStatisticsByNum = async (num: number): Promise<GenderStatistics | null> => {
return await genderStatisticsRepository.findOneBy({ num });
};
Step7: 컨트롤러 생성
컨트롤러를 생성하여 HTTP 요청을 처리합니다.
userController.ts
import { Request, Response } from "express";
import { createUser, getUserById } from "../repositories/userRepository";
export const createUserHandler = async (req: Request, res: Response) => {
try {
const user = await createUser(req.body);
res.status(201).json(user);
} catch (error) {
if (error instanceof Error) {
res.status(500).json({ message: error.message });
} else {
res.status(500).json({ message: "An unknown error occurred" });
}
}
};
export const getUserByIdHandler = async (req: Request, res: Response) => {
try {
const user = await getUserById(parseInt(req.params.id));
if (user) {
res.json(user);
} else {
res.status(404).json({ message: "User not found" });
}
} catch (error) {
if (error instanceof Error) {
res.status(500).json({ message: error.message });
} else {
res.status(500).json({ message: "An unknown error occurred" });
}
}
};
genderStatisticsController.ts
import { Request, Response } from "express";
import { createGenderStatistics, getGenderStatisticsByNum } from "../repositories/genderStatisticsRepository";
export const createGenderStatisticsHandler = async (req: Request, res: Response) => {
try {
const genderStat = await createGenderStatistics(req.body);
res.status(201).json(genderStat);
} catch (error) {
if (error instanceof Error) {
res.status(500).json({ message: error.message });
} else {
res.status(500).json({ message: "An unknown error occurred" });
}
}
};
export const getGenderStatisticsByNumHandler = async (req: Request, res: Response) => {
try {
const genderStat = await getGenderStatisticsByNum(parseInt(req.params.num));
if (genderStat) {
res.json(genderStat);
} else {
res.status(404).json({ message: "Gender statistics not found" });
}
} catch (error) {
if (error instanceof Error) {
res.status(500).json({ message: error.message });
} else {
res.status(500).json({ message: "An unknown error occurred" });
}
}
};
Step8: 라우트 설정
userRoutes.ts
import { Router } from "express";
import { createUserHandler, getUserByIdHandler } from "../controllers/userController";
const router = Router();
router.post("/users", createUserHandler);
router.get("/users/:id", getUserByIdHandler);
export default router;
genderStatisticsRoutes.ts
import { Router } from "express";
import { createGenderStatisticsHandler, getGenderStatisticsByNumHandler } from "../controllers/genderStatisticsController";
const router = Router();
router.post("/gender-statistics", createGenderStatisticsHandler);
router.get("/gender-statistics/:num", getGenderStatisticsByNumHandler);
export default router;
Step9: Express 서버 설정
index.ts
import "reflect-metadata";
import express from "express";
import { AppDataSource } from "./data-source";
import userRoutes from "./routes/userRoutes";
import genderStatisticsRoutes from "./routes/genderStatisticsRoutes";
AppDataSource.initialize().then(() => {
const app = express();
app.use(express.json());
app.use(userRoutes);
app.use(genderStatisticsRoutes);
const port = process.env.PORT || 3000;
app.listen(port, () => {
console.log(`Server is running on port ${port}`);
});
}).catch(error => console.log(error));
모두 작성 되었다면 yarn dev로 개발 서버를 실행합니다.
자바스크립트 계열은 자료를 찾다보면 작성자마다 구조와 형식이 달라 늘 어렵네요.
'개발라이프' 카테고리의 다른 글
자바스크립트 구조 분해 할당 - express url 매개변수 (1) | 2024.09.10 |
---|---|
docker-compose ps error - ConnectionRefusedError: [Errno 61] Connection refused (0) | 2024.08.13 |
JavaScript의 옵셔널 체이닝 연산자 (Optional Chaining Operator) (0) | 2024.07.25 |
PostgreSQL 소수점 타입 (0) | 2024.07.12 |
intellij - Cannot identify version of git executable: no response in 3 attempts (0) | 2023.04.27 |