반응형
let { type } = req.params;

위의 코드는 구조 분해 할당 (Destructuring Assignment)을 사용한 것입니다. . 아래는 이에 대한 상세 설명입니다.

 

1. req.params:

  • 이 코드는 Express.js 애플리케이션에서 사용됩니다. 여기서 req는 **요청 객체(request object)**입니다.
  • req.params는 URL에서 **경로 매개변수(route parameters)**를 담고 있는 객체입니다. 이 매개변수들은 일반적으로 경로에서 : 기호로 정의됩니다. 예를 들어:
app.get('/user/:type', (req, res) => {
  // req.params.type은 ':type'의 값을 가집니다
});
  • 경로가 /user/:type일 경우, type은 경로 매개변수가 되며, req.params는 다음과 같은 객체가 됩니다
{ type: 'someValue' }

 

2. 구조 분해 할당 (Destructuring Assignment):

  • { type } 구문은 구조 분해 할당입니다. 이는 객체에서 속성을 추출하는 간편한 방법입니다.
  • 원래는 다음과 같이 작성될 수 있습니다:
let type = req.params.type;

이를 아래와 같이 간략하게 작성할 수 있습니다:

let { type } = req.params;
 
  • 이 코드는 req.params 객체에서 type 속성을 추출하여 새로운 변수 type에 할당합니다.

요약

let { type } = req.params;는 req.params 객체에서 type이라는 매개변수를 추출하여 type이라는 변수에 저장하는 코드입니다. 이는 주로 Express.js에서 URL 경로의 매개변수를 쉽게 접근하기 위해 사용됩니다.

728x90
반응형
반응형

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로 개발 서버를 실행합니다.

 

자바스크립트 계열은 자료를 찾다보면 작성자마다 구조와 형식이 달라 늘 어렵네요.

728x90
반응형
반응형

JavaScript의 옵셔널 체이닝(Optional Chaining) 연산자 ?.는 객체의 속성에 접근할 때, 해당 속성이 존재하지 않더라도 에러를 발생시키지 않고 undefined를 반환하는 유용한 문법입니다. 이는 깊게 중첩된 객체 구조에서 속성에 접근할 때 특히 유용하며, 코드의 가독성과 안전성을 크게 향상시켜줍니다.

왜 옵셔널 체이닝이 필요한가?

객체의 속성에 접근할 때, 종종 해당 속성이 존재하지 않을 가능성을 고려해야 합니다. 예를 들어, 서버로부터 받은 데이터가 항상 동일한 구조를 가지지 않거나, 어떤 필드가 조건에 따라 존재하지 않을 수 있습니다. 이러한 상황에서 안전하게 속성에 접근하기 위해서는 많은 방어적 코드를 작성해야 합니다.

let person = {}; // person 객체는 비어있습니다.

console.log(person.contactInfo.address); // TypeError: Cannot read property 'address' of undefined

 

위의 코드에서 user.address가 undefined이기 때문에 user.address.street에 접근하려고 하면 오류가 발생합니다. 이 문제를 해결하기 위해 보통 아래와 같은 방어적 코드를 작성합니다.

let person = {};

if (person && person.contactInfo && person.contactInfo.address) {
  console.log(person.contactInfo.address);
} else {
  console.log('주소가 없습니다.');
}

 

하지만 이러한 방어적 코드는 가독성을 떨어뜨리고 작성하기 번거로울 수 있습니다. 이를 해결하기 위해 등장한 것이 옵셔널 체이닝 연산자입니다.

옵셔널 체이닝의 사용법

옵셔널 체이닝 연산자를 사용하면 중첩된 객체의 속성에 안전하게 접근할 수 있습니다. 옵셔널 체이닝은 ?. 형태로 사용되며, 해당 속성이 존재하지 않을 경우 undefined를 반환합니다.

let person = {}; // person 객체는 여전히 비어있습니다.

console.log(person?.contactInfo?.address); // undefined

 

위의 코드에서 user.address가 undefined이더라도 오류가 발생하지 않고 undefined를 반환합니다.

옵셔널 체이닝의 다양한 사용 예

1. 객체 속성 접근

let person = {
  fullName: 'John Doe',
  contactInfo: {
    address: '456 Elm St'
  }
};

console.log(person?.contactInfo?.address); // '456 Elm St'
console.log(person?.employment?.position); // undefined

 

2. 함수 호출

옵셔널 체이닝은 함수 호출에도 사용할 수 있습니다. 함수가 존재하지 않을 경우 undefined를 반환합니다.

let person = {
  sayHello: function() {
    console.log('Hi there!');
  }
};

person.sayHello?.(); // 'Hi there!'
person.sayGoodbye?.(); // 아무 일도 일어나지 않음

 

3. 배열 요소 접근

옵셔널 체이닝은 배열의 요소 접근에도 사용할 수 있습니다.

let employees = [{ fullName: 'John Doe' }, { fullName: 'Jane Smith' }];

console.log(employees[0]?.fullName); // 'John Doe'
console.log(employees[3]?.fullName); // undefined

 

결론

옵셔널 체이닝 연산자는 객체의 속성에 안전하게 접근할 수 있게 해주는 강력한 도구입니다. 이를 통해 코드의 가독성을 높이고, 중첩된 객체 구조를 다룰 때 발생할 수 있는 오류를 예방할 수 있습니다. JavaScript 코드에서 옵셔널 체이닝을 적절히 활용하면 보다 안정적이고 유지보수하기 쉬운 코드를 작성할 수 있습니다.

728x90
반응형

+ Recent posts