2022. 4. 10. 01:45ใProgramming Project ์์ ์ค/๋ด์ฉ ์ ๋ฆฌ
Project Git Hub
๐ ๋ชฉ์ฐจ
โ [BackEnd][Node.js][Nest.js] ์ฌ๋ด ๊ฐ๋ฐ์ ์ปค๋ฎค๋ํฐ ์๋น์ค - ํ์ ๊ฐ์
โ [BackEnd][Node.js][Nest.js] ์ฌ๋ด ๊ฐ๋ฐ์ ์ปค๋ฎค๋ํฐ ์๋น์ค - JWT๋ฅผ ์ด์ฉํ Login
โ [BackEnd][Node.js][Nest.js] ์ฌ๋ด ๊ฐ๋ฐ์ ์ปค๋ฎค๋ํฐ ์๋น์ค - Custom Decorator
๐ ๋ถ๋ก
โ [Node.js] Node.js ๊ธฐ์ด
โ [JavaScript] ๊ธฐ๋ณธ ๋ฌธ๋ฒ
โ [BackEnd][Node.js] ์ฌ๋ด ๊ฐ๋ฐ์ ์ปค๋ฎค๋ํฐ ์๋น์ค - ์ด๊ธฐ ๊ตฌ์ฑ
โ [BackEnd][Node.js] ์ฌ๋ด ๊ฐ๋ฐ์ ์ปค๋ฎค๋ํฐ ์๋น์ค - ์ด๊ธฐ ๊ตฌ์ฑ : DB ์ฐ๊ฒฐ
โ [BackEnd][Node.js] ์ฌ๋ด ๊ฐ๋ฐ์ ์ปค๋ฎค๋ํฐ ์๋น์ค - ์ด๊ธฐ ๊ตฌ์ฑ : DB ์ฐ๊ฒฐ(Sequelize)
โ [Web] URL์ ์ดํด
โ [Spring] Spring์ด๋?
โ[Node.js][Nest.js] ์ ํจ์ฑ ๊ฒ์ฌ์ Data ํ์ ๋ณํํ๊ธฐ - Pipe
โ[Node.js][Nest.js] Configuration (์ค์ )
โ[Node.js][Nest.js]TypeORM
โ [Node.js][Nest.js] Logger ๊ธฐ๋ฅ
โ[JavaScript] Promise์ async ๊ทธ๋ฆฌ๊ณ await
โ [Nest.js] API ์ค๊ณ - ์์ฒญ, ์๋ต ๊ฐ์ฒด (Request, Response Object)
โ [์ ๋ณด๋ณด์] JWT(JSON Web Token) ์ด๋?
โ [Nest.js] Middle Ware(๋ฏธ๋ค์จ์ด)
๐ค ๋ด๊ฐ ๋ง๋ Error
โ [Node.js][Error] Cannot find module '.dotenv'
๐ ๊ฒ์ํ ๋ง๋ค๊ธฐ
๐ฝ ์ ๋ฆฌํ๊ธฐ
src ๋ฐ์ ์๋์ผ๋ก ์์ฑ๋ `app.controller.spec.ts`, `app.controller.ts`, `app.service.ts`๋ ์ ๊ฑฐํด ์ฃผ๋๋ก ํ ๊ฒ์ด์์.
์ง์ด File๋ค๋ก ์ธํด `Exception`์ด ๋ฐ์ํ ๊ฒ์ด์์. ์ด ๊ณณ๋ ์ ๋ฆฌ ํด ์ฃผ๋๋ก ํ ๊ฒ์ด์์.
๐ฝ Module ๋ง๋ค๊ธฐ
๐ฆ devInquery.module.ts
`Node.js`๋ ๋๋ถ๋ถ ์ง์ File์ ๋ง๋ค๊ธฐ ๋ณด๋ค ๋ช ๋ น์ด๋ฅผ ํตํด ์๋์ผ๋ก ์์ฑํ๋ ๊ฒ์ ์ข์ํ๋ ๊ฒ ๊ฐ์ ๊ฒ์ด์์.
๋ช ๋ น์ด
nest g module {Module-name}
๐ก ์ฐธ๊ณ ์ฌํญ
๋ช ๋ น์ด ์ ๋ฆฌ
โ nest : nestcli๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํด ์ ์ธ.
โ g : generate(์์ฑํ๋ค) ์ฆ, Module์ ๋ง๋ค๊ธฐ ์ํด ์ฌ์ฉํ๋ Option.
โ module : Module์ ๋ง๋ค๊ฒ ๋ค๊ณ ์ ์ธ.
โ {Module-name} : ๋ง๋ค๊ณ ์ถ์ Module ์ด๋ฆ ์ ์ธ.
์์ ๋ช ๋ น์ด๋ฅผ ์ ๋ ฅํ๋ ์๋ File์ด ์์ฑ๋ ๊ฒ์ด์์.
์์ ๋ง๋ Module์ ์ฌ์ฉํ๊ธฐ ์ํด์๋ `Root` Module์ธ `app.module.ts`์ ๋ฑ๋กํด์ฃผ์ด์ผ ํ๋ ๊ฒ์ด์์. ์ด ๋ถ๋ถ์ ๋ช ๋ น์ด๋ฅผ ํตํด Module์ ๋ง๋ค ๋ ์๋์ผ๋ก ์ ์ธ๋ฉ๋๋ค.
์ ๋ง๋ค์ด์ก๋ ํ์ธํ๊ธฐ ์ํด Server๋ฅผ ์ฌ๋ ค ๋ณผ๊ฒ์ด์์.
Server๊ฐ ์ ์์ ์ผ๋ก ์คํ ์ค์ธ ๊ฒ์ด์์.
๐ฝ Controller ๋ง๋ค๊ธฐ
`Contoller`๋ `Client` ์ธก์์ ๋ณด๋ธ `Request(์์ฒญ)`์ ์ฒ๋ฆฌํ๊ณ , ์๋ต์ ๋ฐํํ๋ ์ผ์ ํ๋๋ฐ, Route์ ์ญํ ์ ํ๋ ๊ฒ์ด์์.
๋ช ๋ น์ด
nest g controller {controller-name} {--no-spec}
์์ ๋ช ๋ น์ด์์ `--no-spec`์ ์ ํ์ฌํญ์ธ๋ฐ, ์์ ๊ฐ์ด ์ ๋ ฅํ๋ฉด `Test Code`๋ฅผ ์๋์ผ๋ก ๋ง๋ค์ง ์๋ ๊ฒ์ด์์.
์ ๋ช ๋ น์ด๋ฅผ ์ ๋ ฅํ๋ฉด `Controller`๊ฐ ์๋์ผ๋ก ๋ง๋ค์ด ์ง๋ ๊ฒ์ด์์.
๐ก ์ฐธ๊ณ ์ฌํญ
CLI๋ฅผ ํตํด Controller๊ฐ ๋ง๋ค์ด์ง๋ ์์
โ ์ต์ด CLI๋ ๋ช ๋ น์ด๋ก ์ ๋ ฅ๋ ์ด๋ฆ์ ํด๋นํ๋ Directory๊ฐ ์๋์ง ์ฐพ๊ณ , ์์ผ๋ฉด ๊ทธ ์์ ๋ง๋ค๊ณ , ์์ผ๋ฉด Directory ์์ฑ ๋ค ๊ทธ ์์ ๋ง๋ ๋ค.
โ ํด๋น Directory์ Module์ ์ฐพ๊ณ , Module์์ Controller์ ๋ํ ๋ด์ฉ์ ๋ฃ์ด์ค๋ค.
๐ฝ Providers, Service ๋ง๋ค๊ธฐ
๐ฆ ๊ฐ์
โบ Providers๋? `Nest.js`์ ๊ธฐ๋ณธ ๊ฐ๋ ์ผ๋ก ๋๋ถ๋ถ์ ๊ธฐ๋ณธ `Nest.js` Class๋ `Service`, `Repository`, `Factory`, `Helper` ๋ฑ `Provider`๋ก ์ทจ๊ธ ๋ ์ ์๋ ๊ฒ์ด์์. `Provider`์ ์ฃผ์ Idea๋ `์์กด๊ด๊ณ(์ข ์์ฑ) ์ฃผ์ (Dependency Injection - DI)`์ ํ ์ ์๋ค๋ ๊ฒ์ด์์. `Spring Boot`๋ฅผ ์ฌ์ฉํด ๋ณด์ ๋ถ๋ค์ ์์ฃผ ์ต์ํ ์ฉ์ด ์ธ ๊ฒ์ด์์.
์ฆ, ๊ฐ์ฒด๋ ์๋ก ๋ค์ํ ๊ด๊ณ๋ฅผ ๋ง๋ค ์ ์๋๋ฐ, ์ธ์คํด์ค๋ฅผ ์ฐ๊ฒฐํ๋ ๊ธฐ๋ฅ์ ๋๋ถ๋ถ `Nest.js` Runtime System์ ์์๋ ์ ์๋ ๊ฒ์ด์์.
`Controller`๋ ์ฌ๋ฌ `Service`๋ฅผ DIํ์ฌ ํด๋น Service์ Method๋ฅผ ํธ์ถํด์ ๋น์ฆ๋์ค ๋ก์ง ์ฒ๋ฆฌ๋ฅผ ๋ถํํ๋ ๊ฒ์ด์์.
โบ Service๋? ๋น์ฆ๋์ค ๋ก์ง์ ๋ด๋นํ๋ `Service`๋ `Spring`์๋ ํ์์ ์ผ๋ก ์ฌ์ฉ๋๋ ๊ฐ๋ ์ธ ๊ฒ์ด์์. `Nest.js`์์๋ `@Injectable` Decorator๋ก ๊ฐ์ธ์ ธ Module์ ์ ๊ณต๋๊ณ , ์ด `Service` ์ธ์คํด์ค๋ Application ์ ์ฒด์์ ์ด์ฉ๋ ์ ์๋ ๊ฒ์ด์์.
`Service`๋ `Controller`์์ Data์ ์ ํจ์ฑ ๊ฒ์ฌ๋ฅผ ํ๊ฑฐ๋, Data Base์ Item ์์ฑ ๋ฑ์ ํ๊ธฐ ์ํด `Repository`์๊ฒ ์์ ์ ์์ํ๋ ๋ฑ์ ๋น์ฆ๋์ค ๋ก์ง์ ์ฒ๋ฆฌํ๋ ๊ฒ์ด์์.
๐ฆ ์์ฑํ๊ธฐ
๋ช ๋ น์ด
nest g service {service-name} {--no-spec}
๋ช ๋ น์ด์ ๋ํ ์ค๋ช ์ ์์ ํ์ผ๋ ์๋ตํ ๊ฒ์ด์์.
`Service`๊ฐ ์ ์์ ์ผ๋ก ๋ง๋ค์ด ์ง ๊ฒ์ด์์.
๋ํ, Module์ ํ์ธํด ๋ณด๋ฉด ์๋์ผ๋ก `Controller`์ `providers`๋ผ๊ณ ๋ช ๋ช ๋ `Service`๊ฐ ๋ฑ๋ก๋์ด ์๋ ๊ฒ์ด์์.
`Service` class ์์ ์ดํด๋ณด๋ฉด `@Injectable()`์ด ์๋ ๊ฒ์ด์์. `Nest.js`๋ ์ด๊ฒ์ ์ด์ฉํด์ ๋ค๋ฅธ `Component`์์ ํด๋น `Service`๋ฅผ ์ด์ฉํ ์ ์๊ฒ (Injectable) ๋ง๋ค์ด ์ฃผ๋ ๊ฒ์ด์์.
๐ฆ ์์กด๊ด๊ณ ์ฃผ์ (DI)
`Controller`์์ `Service`๊ฐ ์ด์ฉ๋ ์ ์๊ฒ DI(Dependency Injection)์ ํด ์ค ๊ฒ์ด์์.
`Spring Boot`์์๋ `Contorller`์์ `Service`๋ฅผ DIํ๊ธฐ ์ํด Member ๋ณ์๋ก `Service` ๊ฐ์ฒด ์๋ฃํ ํ์ ๋ณ์๋ฅผ ์ ์ธํ๊ณ , ์ด๋ฅผ ์์ฑ์๋ฅผ ํตํด `this.{service-name} = {service-name}`์ ํ์ฌ DI๋ฅผ ํ๊ฑฐ๋, `final`๋ก ์ ์ธํ์ฌ `@RequireArgsConstructor`๋ฅผ ์ด์ฉํ๋ ๋ฑ์ ๋ฐฉ์์ ์ผ์๋๋ฐ, `Nest.js`๋ ์ด๋ ๊ฒ `constructor`๋ผ๋ Keyword๋ฅผ ํตํด ์์ฑ์๋ฅผ ๋ง๋ค๊ณ , `private`์ด๋ผ๋ ์ ๊ทผ ์ ํ์๋ฅผ ์ ์ธํด์ `Service` ๊ฐ์ฒด๋ฅผ ์ ์ธํด์ฃผ๋ฉด ๋๋ ๊ฒ์ด์์.
์์ ๊ฐ์ Code๋ ๋ฐ๋ก `TypeScript`๊ฐ ๋์์ฃผ๊ธฐ ๋๋ฌธ์ ๊ฐ๋ฅํ ๋ฌธ๋ฒ์ธ๋ฐ, `JavaScript`์์๋ `private`์ ๊ฐ์ ์ ๊ทผ ์ ํ์(Access Modifier)๋ฅผ ์ด์ฉํ ์ ์์ง๋ง, `TypeScript`์์๋ ์ด์ฉ์ด ๊ฐ๋ฅํ ๊ฒ์ด์์.
๋ง์ฝ 6๋ฒ์งธ ์ค์ `private`์ ์ ์ธํ์ง ์๋๋ค๋ฉด ์๋์ ๊ฐ์ด ์ ์ธ์ ํด์ค์ผ ํ ๊ฒ์ด์์.
์ด๊ฑด ๋ง์น Annotation์ ์ฐ์ง์๊ณ , ์์ฑ์ DI๋ฅผ ํ๋ `Spring Boot`์ ๋ชจ์ต์ด ํก์ฌํ๋ค์. ๋ฌผ๋ก `Spring Boot`์์ ์์ ๊ฐ์ด ํ๋ ค๊ณ ํ๋คํด๋ `@Autowired` ๊ฐ์ Annotaion์ ์์ฑ์ํํ ๋ถํ์ค์ผ ํ์ง๋ง ๋ง์ด์์.
์ Code๋ฅผ ๋ถ์ํด ๋ณด๋ฉด 9๋ฒ์งธ ์ค์ `devInqueryService` Parameter์ `DevInqueryService` ๊ฐ์ฒด๋ฅผ ์๋ฃํ Type์ผ๋ก ์ง์ ํด ์ฃผ๋ ๊ฒ์ด์์. JAVA์ ๋น๊ตํ๋ฉด ์ ๋ค๊ฐ ๋ฐ๋ ๋ชจ์ต์ธ ๊ฒ์ด์์.
11๋ฒ์งธ ์ค์ `devInqueryService` Parameter๋ฅผ `DevInqueryController`์์ ์ด์ฉํ ์ ์๊ฒ `this.devInqueryService Property`์ `devInqueryService` Parameter๋ฅผ ํ ๋นํด ์ฃผ๋ ๊ฒ์ด์์.
๊ทธ๋ฐ ๋ค 7๋ฒ์งธ ์ค์ `TypeScript`์์๋ ์ ์ธํ ๊ฐ๋ง ๊ฐ์ฒด์ `Property`๋ก ์ฌ์ฉํ ์ ์๊ธฐ ๋๋ฌธ์ ์์ ๊ฐ์ด ์ ์ธํด ์ค ๊ฒ์ด์์.
์ด๋ ๊ฒ ์ป์ด์จ `devInqueryService Property`๋ฅผ ์ด์ฉํ์ฌ `DevInqueryController` Class ์์์ ์ด์ฉํ ์ ์๋ ๊ฒ์ด๋๋๋ค.
์ฐธ๊ณ ๋ก `private`์ ์ ์ธํ๋ฉด `devInqueryService Property`๋ `DevInqueryController` Class์์๋ง ์ด์ฉ ๊ฐ๋ฅํ ๊ฒ์ด์์.
๐ฝ Model ๋ง๋ค๊ธฐ
`Spring Boot JPA`์์๋ `Entity` Class๋ฅผ `Interface`๋ก ๋ง๋ค์ง ์์ง๋ง, `Nest.js`์์๋ `Interface`๋ก ๊ตฌํํด๋ ๋๋ ๊ฒ์ด์์.
ํด๋น ๊ฒ์๊ธ ๊ธฐ๋ฅ์๋ ๋น๋ฐ๊ธ ๊ธฐ๋ฅ์ด ์๋ ๊ฒ์ด์์. ๋น๋ฐ๊ธ์ `enum` Class๋ฅผ ์ด์ฉํด์ ์์ ๊ฐ์ด ๋ง๋ค์ด ์ค ๊ฒ์ด์์.
์ฆ, `secretAt(๋น๋ฐ๊ธ ์ฌ๋ถ)`์๋ `String` Type 'N'๊ณผ 'Y'๋ง ์ ๋ ฅ๋ ์ ์๋ ๊ฒ์ด์์.
๐ก ์ฐธ๊ณ ์ฌํญ
Decorator ์ค๋ช
โ @Entity() : ํด๋น Class๊ฐ Entity์์ ํํ. Data Base DDL 'CREATE TABLE {Table-name}'์ ํด๋น.
โ PrimaryGeneratedColumn() : ํด๋น Property (JAVA: Memeber ๋ณ์)๊ฐ ํด๋น Entity์ Primary Key ๊ฐ์์ ํํ.
โ @Column() : Data Base ๊ธฐ์ค Table์ ๊ฐ ์ด์ ํํ.
๐ฝ Repository ๋ง๋ค๊ธฐ
โบRepository๋?
`Repository`๋ `Entity` ๊ฐ์ฒด์ ํจ๊ป ์๋ํ๋ฉฐ, ์ค์ Data Base์ ์ฐ๊ฒฐ๋์ด SQL๋ฌธ์ ๋์ง๋ ์ญํ ์ ํ๋ ๊ฒ์ด์์.
๋จผ์ ์ฃผ๋ํ๋์ ์์ ๊ฐ์ด `dev-inquery.repository`๋ฅผ ๋ง๋ค์ด ์ค ๊ฒ์ด์์.
์ ๋ง `JPA`์ ๊ฑฐ์ ๋๊ฐ์ ๊ฒ์ด์์. ์ฐจ์ด๊ฐ ์๋ค๋ฉด `JPA`๋ `Interface`๋ก ๊ตฌํํ๋๋ฐ, `TypeORM`์ Class๋ก ๋ง๋๋ ๊ฒ์ด์์.
์์ฑ ์ `Repository` Class๋ฅผ `Extense` ํด์ฃผ๋๋ฐ, ์ด๋ฅผ ํตํด `Find`, `Insert`, `Delete` ๋ฑ๊ณผ ๊ฐ์ Method๋ฅผ ํตํด `Entity`๋ฅผ Control ํด์ค ์ ์๋ ๊ฒ์ด์์.
`@EntityRepository()`๋ Class๋ฅผ ์ด์ฉ์ ์ ์(Custom) ์ ์ฅ์๋ก ์ ์ธํ๋๋ฐ ์ด์ฉ๋๋ ๊ฒ์ด์์. ์ด์ฉ์ ์ง์ ์ ์ฅ์๋ ์ผ๋ถ ํน์ `Entity`๋ฅผ ๊ด๋ฆฌํ๊ฑฐ๋, ์ผ๋ฐ ์ ์ฅ์ ์ผ ์ ์๋ ๊ฒ์ด์์.
์ `Repository`๋ฅผ ๋ค๋ฅธ ๊ณณ์์๋ ์ด์ฉ ๊ฐ๋ฅํ๊ฒ ํ๊ธฐ ์ํด (Injectable) `dev-inquery.module.ts`์์ `import`ํด์ค์ผ ํ๋ ๊ฒ์ด์์.
21๋ฒ์งธ ์ค์ `Repository`๋ฅผ `import` ํด์ค ๊ฒ์ด์์.
๋ง์ง๋ง์ผ๋ก `app.module.ts`์ `TypeORM`์ ๋ํ ์ค์ File์ `imports` ์์ผ์ค์ผ ํ๋ ๊ฒ์ด์์.
์์ ๋ํ `Exception` ๋ด์ฉ์ `์ด ๊ณณ`์ ์ ๋ฆฌ ํด์ ์ค๋นํด ๋๊ฒ์!
์ด์ ๊ธฐ๋ณธ ์ค๋น๋ ๋๋ ๊ฒ์ด์์.
๋ค์ ํฌ์คํ ์์ ๋ณธ๊ฒฉ์ ์ผ๋ก ๊ฒ์ํ ๊ธฐ๋ฅ ๊ตฌํ์ ํด ๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค!
์ด์ ๊ธ : [BackEnd][Node.js][Nest.js] ์ฌ๋ด ๊ฐ๋ฐ์ ์ปค๋ฎค๋ํฐ ์๋น์ค - Custom Decorator