Loading the catalog…
Loading the catalog…
Node.js를 사용한 3주차 실습 및 미션 코드 이번 3주차에서는 백엔드 서버가 직접 데이터베이스와 통신하여 데이터를 조회하고 조작하는 실제 API를 구현했습니다. 또한 DTO나 ORM 기술을 배제하고 오직 순수 SQL(Raw SQL)만을 사용해 서버를 구축했습니다. Spring 환경이 익숙하기에 이번 Wil은 Node.js(NestJS) 환경을 기준으로 진행하였고 일르 Spring과 비교하였습니다. 1. 데이터베이스 커넥션 풀 설정의 차이 애플리케이션이 데이터베이스와 통신하기 위해서는 연결 통로인 커넥션 풀(Connection Pool)을 구성해야 합니다. 이 초기 세팅 과정에서 두 프레임워크의 차이가 드러났습니다. Spring Boot: 자동 구성(Auto-Configuration) Spring Boot는 application.yml 파일에 데이터베이스 접속 정보만 작성해 두면, 서버 구동 시 내부적으로 HikariCP 커넥션 풀과 이를 제어하는 JdbcTemplate 객체를 스프링 컨테이너에 자동 생성합니다. 개발자는 별도의 설정 클래스를 작성할 필요 없이 즉시 의존성을 주입받아 사용할 수 있습니다. NestJS: 커스텀 Provider 직접 조립 반면 모듈화가 강조된 NestJS에서 순수 SQL 드라이버( mysql2 )를 사용할 때는, 개발자가 직접 커넥션 풀을 생성하고 컨테이너에 등록하는 커스텀 Provider를 작성해야 합니다. [NestJS: 데이터베이스 Provider 작성] // src/database.provider.ts import { ConfigService } from '@nestjs/config'; import * as mysql from 'mysql2/promise'; export const DATABASE_CONNECTION = 'DATABASE_CONNECTION'; export const databaseProviders = [ { provide: DATABASE_CONNECTION, inject: [ConfigService], useFactory: (configService: ConfigService) => { // .env 환경변수를 읽어와 커넥션 풀을 직접 생성합니다. return mysql.createPool({ host: configService.get<string>('DB_HOST', 'localhost'), port: configService.get<number>('DB_PORT', 3306), user: configService.get<string>('DB_USER', 'root'), password: configService.get<string>('DB_PASSWORD', ''), database: configService.get<string>('DB_NAME', 'study'), waitForConnections: true, connectionLimit: 10, queueLimit: 0, }); }, }, ]; 작성한 Provider는 app.module.ts 의 providers 와 exports 배열에 등록해야만 전체 애플리케이션에서 주입받아 사용할 수 있습니다. 2. 3계층 아키텍처와 의존성 주입(DI) 방식 비교 Controller, Service, Repository로 역할을 분리하는 3계층 아키텍처의 기본 개념은 동일하지만, 계층을 선언하고 의존성을 주입하는 방식에 차이가 있습니다. 계층 선언 데코레이터/어노테이션 : Spring은 역할에 따라 @RestController , @Service , @Repository 로 세분화하여 명시합니다. NestJS는 @Controller() 를 제외한 Service와 Repository 모두 범용적인 @Injectable() 데코레이터를 사용하여 주입 가능한 클래스임을 명시합니다. 의존성 주입 방식 : Spring은 주로 Lombok의 @RequiredArgsConstructor 를 사용하여 private final 필드에 대한 생성자 주입을 자동으로 처리합니다. NestJS는 TypeScript의 생성자(Constructor) 문법을 통해 명시적으로 주입합니다. 특히 앞서 직접 만든 커넥션 풀과 같은 커스텀 Provider를 주입받을 때는 반드시 @Inject() 데코레이터를 지정해야 합니다. 3. API 구현 실습 1) 특정 카테고리 도서 목록 조회 API (GET) Path Variable을 통해 카테고리 ID를 전달받아 해당 카테고리의 도서를 조회하는 기능입니다. [NestJS: Repository 및 Controller 구현] // src/book.repository.ts import { Injectable, Inject } from '@nestjs/common'; import type { Pool } from 'mysql2/promise'; import { DATABASE_CONNECTION } from './database.provider'; @Injectable() export class BookRepository { constructor(@Inject(DATABASE_CONNECTION) private readonly pool: Pool) {} async findByCategoryId(categoryId: number): Promise<any> { const sql = 'SELECT * FROM book WHERE category_id = ?'; // 구조 분해 할당으로 순수 행 데이터만 추출 const [rows] = await this.pool.query(sql, [categoryId]); return rows; } } // src/book.controller.ts import { Controller, Get, Param } from '@nestjs/common'; @Controller('books') export class BookController { constructor(private readonly bookService: BookService) {} @Get('category/:categoryId') async getBooksByCategory(@Param('categoryId') categoryId: number): Promise<any> { return await this.bookService.getBooksByCategory(categoryId); } } 조회 쿼리 실행 차이 : Spring의 jdbcTemplate.queryForList() 는 곧바로 리스트 형태의 데이터를 반환하지만, NestJS의 pool.query() 는 결과 데이터와 메타데이터 필드를 배열 형태로 반환하므로 [rows] 와 같이 구조 분해 할당을 통해 실제 데이터만 추출해야 합니다. 경로 변수 처리 : Spring은 @PathVariable 을 사용하며, NestJS는 @Param() 을 사용하여 URL 경로의 값을 추출합니다. 2) 도서 대여 기록 생성 (POST) 및 반납 처리 (PATCH) SQL Injection 공격을 방어하기 위해 파라미터 바인딩 기법을 적용하여 데이터를 삽입하고 수정하는 과정입니다. [NestJS: Repository 구현] // src/rental.repository.ts @Injectable() export class RentalRepository { constructor(@Inject(DATABASE_CONNECTION) private readonly pool: Pool) {} // 미션 2: 신규 도서 대여 기록 생성 async createRental(body: Record<string, any>): Promise<any> { const sql = ` INSERT INTO rental (user_id, book_id, rented_at, due_at, returned_at) VALUES (?, ?, NOW(), DATE_ADD(NOW(), INTERVAL 7 DAY), NULL) `; // 파라미터 배열 바인딩 const [result] = await this.pool.execute(sql, [body.userId, body.bookId]); return result; } // 선택 미션: 도서 반납 처리 async returnBook(rentalId: number): Promise<any> { const sql = 'UPDATE rental SET returned_at = NOW() WHERE rental_id = ?'; const [result] = await this.pool.execute(sql, [rentalId]); return result; } } 데이터 조작 쿼리 실행 차이 : Spring은 jdbcTemplate.update() 메서드에 파라미터를 가변 인자로 나열하여 전달합니다. 반면 NestJS는 보안과 성능을 위해 pool.execute() 메서드를 사용하며, 치환될 파라미터들을 두 번째 인자로 배열 형태로 묶어서 전달합니다. 요청 본문 처리 : 클라이언트의 JSON Body를 받을 때 Spring은 @RequestBody Map<String, Object> 를 사용하는 반면, NestJS는 @Body() Record<string, any> 타입을 사용하여 처리했습니다. 4. 한계 확인 이번 실습에서는 DTO 설정 없이 클라이언트의 요청( Record<string, any> )을 그대로 받아 데이터베이스에 삽입했습니다. 이 과정을 직접 수행해 보며 다음과 같은 치명적인 한계를 확인할 수 있었습니다. 타입 안정성의 부재 : 클라이언트 측에서 userId 를 오타로 잘못 입력하여 전송하더라도, TypeScript 컴파일러나 프레임워크 레벨에서 이를 사전에 차단하지 못했습니다. 결국 잘못된 키워드가 그대로 쿼리에 매핑되어 런타임 SQL 에러가 발생했습니다. 하드코딩으로 인한 유지보수 저하 : INSERT INTO 구문에 들어갈 물음표의 순서와 매핑될 파라미터 배열의 순서를 눈으로 확인하며 맞춰야 했습니다. 테이블의 컬럼이 늘어날수록 치명적인 버그를 유발하기 쉬운 구조입니다. Node.js 환경에서의 수동적인 설정 과정과 순수 SQL 작성의 불편함을 경험해 봄으로써, 다음주에 배울 ORM, DTO의 필요성을 체감할 수 있었습니다.
What RADAR observed and classified to build this opportunity. It is what the source published, not a verification that the offer is still active.
2026-2 UMC 스터디 3주차 Backend WIL. Node.js를 사용한 3주차 실습 및 미션 코드 이번 3주차에서는 백엔드 서버가 직접 데이터베이스와 통신하여 데이터를 조회하고 조작하는 실제 API를 구현했습니다. 또한 DTO나 ORM 기술을 배제하고 오직 순수 SQL(Raw SQL)만을 사용해 서버를 구축했습니다. Spring 환경이 익숙하기에 이번 Wil은 Node.js(NestJS) 환경을 기준으로 진행하였고 일르 Spring과 비교하였습니다. 1. 데이터베이스 커넥션 풀 설정의 차이 애플리케이션이 데이터베이스와 통신하기 위해서는 연결 통로인 커넥션 풀(Connection Pool)을 구성해야 합니다. 이 초기 세팅 과정에서 두 프레임워크의 차이가 드러났습니다. Spring Boot: 자동…
Open source