-
ํด๊ฒฐ๋ฐฉ๋ฒ 1 (nest js @9.2.1 ์ดํ์ธ ๊ฒฝ์ฐ)
-
ํด๊ฒฐ๋ฐฉ๋ฒ 2 (nestjs @9.2.1 ์ด์)
-
Nest Js 9.2.1 ํจ์น ๋ด์ฉ
-
๋ฌธ์ ํด๊ฒฐ ๊ณผ์
-
์๋ 1: create ๋ฉ์๋๋ฅผ ํตํด ๊ฐ์ฒด๋ฅผ ๋ฐํ
-
์๋ 2: ํ์ ์ ์์๋ก ์ง์
-
์๋ 3: ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋ฒ์ ์ ๊ณต์ ๋ฌธ์ ๊ธฐ์ค์ผ๋ก ๋ง์ถฐ๋ณด๊ธฐ
-
์๋ 4: spread ์ฐ์ฐ์ ์ฌ์ฉํด์ ์ธํฐํ์ด์ค ๋ ธ์ถ์ํค๋ ๋ฐฉ๋ฒ
-
์๋ 5: ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ฌ์ฉ
-
์๋ฌ ์ด์ ๋ถ์ ๋ฐ ๊ฒฐ๋ก
-
์๋ฌ ์ด์ ๋ถ์
-
๊ฒฐ๋ก

์์ฑ์ผ : 2023.1.13.
์ถ๊ฐ ์์ ์ผ: 2023.1.20. (ํด๊ฒฐ๋ฐฉ๋ฒ 1 ๋ฉ์๋ ์ฌ์ฉ ๊ด๋ จ ์ค๋ช
์ถ๊ฐ, ํด๊ฒฐ ๋ฐฉ๋ฒ 2 ์ถ๊ฐ)
๊ฐ์
Redis๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํด์ ๊ณต์๋ฌธ์ ๋๋ก ๋ฐ๋ผ ํ๋๋ฐ๋, ๊ณ์ ์๋ฌ๊ฐ ๋ฐ์ํ์๋ค.
Nest ๊ณต์๋ฌธ์์์๋ redis๊ฐ ๋ฒ์ ์
๋๋ฉด์ ์ค๋ฅ๊ฐ ๋๋ค๊ณ ์ฃผ์ ํ์๋ฅผ ํด๋๋ค.
๊ณต์๋ฌธ์์ ๋ช
์๋ ๋๋ก redis ๊ด๋ จ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ๋ฎ์ ๋ฒ์ ์ผ๋ก ์ค์น๋ฅผ ํ์๋๋ฐ๋ ์ฌ์ ํ ์๋ฌ๊ฐ ๋ฐ์ํ์ฌ์ ๊ณต์๋ฌธ์๊ฐ ์ ํ ๋์์ด ์๋์๋ค.
NestJs Caching With Redis - Code with Vlad (22๋
5์ ๋ฌธ์)
How to add Redis cache to a NestJS app - LogRocket Blog (22๋
7์ ๋ฌธ์)
๊ทธ๋์ ์ ์ ๋ฌธ์๋ฅผ ์ฐธ๊ณ ํ๋ฉด์ ํด๋ดค๋๋ฐ๋ ์ฌ์ ํ ์ค๋ฅ๊ฐ ๋ฌ๋ค.
์ด๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด์ ์๋ํ๋ ๊ณผ์ ๊ณผ ์๋ก ์๊ฒ ๋ ๊ฒ์ ๋ํด์ ๊ธฐ๋กํด๋ณด๊ณ ์ ํ๋ค.
์๋ฌ ๋ฐ์
- ํ์ ์ค๋ฅ ๋ก๊ทธ
cache-manager.interface.d.ts(63, 5):
The expected type comes from property 'store'
which is declared here on type
'CacheModuleOptions<{
store: (
config: RedisClientOptions<RedisModules, RedisFunctions, RedisScripts>
& Config) => Promise<...>;
host: string;
port: number;
}>'
Type 'RedisStore' is not comparable to type 'CacheStore'
'CacheModuleAsyncOptions<
RedisClientOptions<RedisModules, RedisFunctions, RedisScripts>>'
์ฌ๋ฌ ์๋๋ฅผ ํด๋ด๋ ์ด๋ฐ ํ์
์ค๋ฅ๊ฐ ๋ฐ์ํ์๋ค.
- redis ๋ด ๋ฉ์๋ ์ฌ์ฉ ์ค๋ฅ ๋ก๊ทธ
[Nest] 24171 - 01/12/2023, 3:58:21 PM ERROR [ExceptionsHandler]
this.cacheManager.set is not a function
์ดํ ํ์
๊ด๋ จ ์ค๋ฅ๋ฅผ ํด๊ฒฐํ๊ณ ๋์ ์คํํด๋ณด๋ redis cacheManager ๊ฐ ์ ๋๋ก ์๋ํ์ง ์์๋ค.
(๋๋ฒ๊น
ํด๋ณด๋๊น driver๊ฐ postgre๋ก ์ฐํ์๊ณ , ํธ์ถํ ๋ฉ์๋๋ค์ด ๋ชจ๋ undefined๋ก ๋์์์๋ค.)
ํด๊ฒฐ๋ฐฉ๋ฒ 1 (nest js @9.2.1 ์ดํ์ธ ๊ฒฝ์ฐ)
2023.1.20. (๋ฉ์๋ ๊ด๋ จ ๋ด์ฉ ์ถ๊ฐ)
import { Global, Module } from '@nestjs/common'; | |
import { ConfigModule, ConfigService } from '@nestjs/config'; | |
import { redisStore } from 'cache-manager-redis-store'; | |
export const REDIS_CACHE = 'REDIS_CACHE'; | |
@Global() | |
@Module({ | |
imports: [ConfigModule], | |
providers: [ | |
{ | |
provide: REDIS_CACHE, | |
useFactory: async (configService: ConfigService) => | |
await redisStore({ | |
socket: { | |
host: configService.get<string>('REDIS_HOST'), | |
port: configService.get<number>('REDIS_PORT'), | |
}, | |
ttl: 10, | |
}), | |
inject: [ConfigService], | |
}, | |
], | |
exports: [REDIS_CACHE], | |
}) | |
export class RedisCacheModule {} |
์ด๋ ๊ฒ ๋ฐ๋ก ๊ธ๋ก๋ฒ ๋ชจ๋ ํ์ผ์ ๋ง๋ค์ด์ฃผ์๋ค.
ํด๋น ๋ชจ๋์ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ ์ด๋ ๊ฒ ์์ฑ์ ์ฃผ์
์ ํด์ฃผ๋ฉด ๋๋ค.
import { REDIS_CACHE } from './redis.module'; | |
import { Cache } from 'cache-manager'; | |
@Injectable() | |
export class RedisService { | |
constructor(@Inject(REDIS_CACHE) private cacheManager: Cache) {} | |
async getKeys(key: string): Promise<any> { | |
return await this.cache.store.keys(key); | |
} | |
async getValue(key: string): Promise<string> { | |
return await this.cache.get(key); | |
} | |
async save(key: string, value: any, ttl: number): Promise<any> { | |
return await this.cache.set(key, value, { | |
ttl: ttl, | |
}); | |
} | |
async delete(key: string): Promise<void> { | |
return await this.cache.del(key); | |
} | |
async getMultipleKeydata(key: string): Promise<any> { | |
const redisKeys = await this.getKeys(key); | |
const data: { [key: string]: any } = {}; | |
for (const key of redisKeys) { | |
data[key] = await this.getValue(key); | |
} | |
return allData; | |
} | |
} |
๋ฉ์๋ ์ฌ์ฉํ ๋ ๋ ๊ณต์๋ฌธ์๋ ๋ค๋ฅด๊ฒ ํด์ฃผ์ด์ผํ๋ค. ๋ฉ์๋ ์ฌ์ฉ ๊ด๋ จํด์๋ ํด๋น ๊ธ์ ์ฐธ๊ณ ํ์๋ค.
package.json ๋ฒ์ ์ ๋ค์๊ณผ ๊ฐ๋ค.
(์ด ๋ฐฉ๋ฒ์ ๋ฌธ์ ๋์์๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ค ๋ฒ์ ํจ์น๊น์ง ๊ผผ๊ผผํ ๋ฐ์ง ํ์ ์์ด ์ ๋นํ yarn, npm ๊ฐ์ง๊ณ ์ต์ ๋ฒ์ ์ผ๋ก ์ ์งํด์ค๋ ๋๋ค.)
"dependencies": {
"@nestjs/common": "^9.2.0",
"@nestjs/config": "^2.2.0",
"@nestjs/core": "^9.0.0",
"cache-manager": "^5.1.4",
"cache-manager-redis-store": "^3.0.1",
"redis": "^4.3.1",
},
"devDependencies": {
"@nestjs/cli": "^9.0.0",
"@types/cache-manager": "^4.0.2",
"@types/express": "^4.17.13",
"@types/node": "^16.0.0",
},
ํด๊ฒฐ๋ฐฉ๋ฒ 2 (nestjs @9.2.1 ์ด์)
2023.1.20. (์ถ๊ฐ):
์ก์๋ฆฌ: ํด๊ฒฐ๋ฐฉ๋ฒ 1 ๊ธฐ์ค์ผ๋ก ๋ฉ์๋ ์ฌ์ฉ ๊ด๋ จํด์ ๋ฌธ์ ๊ฐ ์๊ฒจ์ ์ถ๊ฐ์ ์ผ๋ก ์ฐพ์๋ณด๋ค๊ฐ ์ ๋ง ์ต๊ทผ์ (4์ผ์ ) ์ฌ๋ผ์จ ๊ด์ฐฎ์ ๋ณด์ด๋ ํด๊ฒฐ๋ฒ์ ์ฐพ์์ ์ถ๊ฐ๋ก ์ ๋ฆฌํ์๋ค.
ํด๊ฒฐ ๋ฐฉ๋ฒ 1 ์ปค์คํ
๋ชจ๋์ ๋ง๋๋ ๊ฒ๋ณด๋ค ์ด ๋ฐฉ๋ฒ์ด ์ข ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๊ตฌ์กฐ๋๋ก ์ ๋ฐ๋ฅด๋ ๊ฒ ๊ฐ์์ ์ด ๋ฐฉ๋ฒ์ ์ ์ฉํ์๋ค.
cache-manager-redis-yet ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ค์นํด์ค๋ค.
yarn add cache-manager
yarn add cache-manager-redis-store-yet redis
yarn add -D @types/cache-manager
import { CacheModule, Module } from '@nestjs/common'; | |
import { AppController } from './app.controller'; | |
import { AppService } from './app.service'; | |
import { redisStore } from 'cache-manager-redis-yet'; | |
@Module({ | |
imports: [ | |
CacheModule.registerAsync({ | |
imports: [ConfigModule], | |
useFactory: async (configService: ConfigService) => ({ | |
store: await redisStore({ | |
socket: { | |
host: configService.get<string>('REDIS_HOST'), | |
port: configService.get<number>('REDIS_PORT'), | |
}, | |
ttl: 5000, | |
}), | |
}), | |
inject: [ConfigService], | |
isGlobal: true, | |
}), | |
], | |
controllers: [AppController], | |
providers: [AppService], | |
}) | |
export class AppModule {} |
* ์ฃผ์: nest js default ttl ๊ฐ (5์ด)์ด ์๋์ผ๋ก ์ ์ฉ์ด ์๋๋ฏ๋ก, ttl ์ค์ ์ ๋ฐ๋์ ํด์ฃผ์ด์ผํ๋ค.
* ์ฃผ์: @CacheTTL(x) ๊ธ๋ก๋ฒ ttl ์ค๋ฒ๋ผ์ด๋ฉํ๋๊ฑฐ ์ ๋๋ก ์๋์๋จ
(cache-manager ๋ฒ์ ์ด 5๋ก ์ฌ๋ผ๊ฐ๋ฉด์ ๋ ๋ญ๊ฐ ์ด์๊ฐ ์๊น..) ์ฌ๊ธฐ ๋ฌธ์ ์ฐธ๊ณ ํ๋ฉด ๋๋ค.
* ๋ฐ๋์ nest Js 9.2.1 ๋ฒ์ ์ด์์ด์ด์ผ ํ๋ค.
(์ ๊ทธ๋ ๋๋ฉด nestJs ํจ์น ๋ฒ์ ๊ธฐ๋ก์ ํ์ธํด๋ณด๋ฉด 9.2.1 ํจ์น ๋ ๊ด๋ จ ๋ฒ๊ทธ๊ฐ ํด๊ฒฐ๋์๊ธฐ ๋๋ฌธ์ด๋ค.)
* ๊ณต์๋ฌธ์์์๋ ttl์ด sec ๋จ์๋ผ๊ณ ํ์ง๋ง, cache-manager ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ 5๋ก ์
๊ธ๋๋ฉด์ ms ๋จ์๋ก ๋ฐ๋์๋ค.
* ๋๋จธ์ง ์ฌ์ฉ๋ฒ์ด๋, ์ค์ ์ ๊ณต์๋ฌธ์ ๋๋ก ์ค์ ํด์ฃผ๋ฉด ๋๋ค. (keys ์ด๋ฐ ๋ฉ์๋ ์ฐ๊ณ ์ถ์ผ๋ฉด .store ๋ถ๋ฌ์ ์ฐ๋ฉด ๋จ)
์์กด์ฑ ๊ด๋ จ package.json ๋ฒ์ ๋ฐ ๋ค์คํธ ๋ฒ์ ์ ๋ค์๊ณผ ๊ฐ๋ค.

# dependencies
"cache-manager": "^5.1.4",
"cache-manager-redis-yet": "^4.1.0",
"redis": "^4.5.1",
# devDependencies
"@types/cache-manager": "^4.0.2",
์ฐธ๊ณ ๋ฌธ์: https://github.com/dabroek/node-cache-manager-redis-store/issues/40#issuecomment-1383193211
Nest Js 9.2.1 ํจ์น ๋ด์ฉ

fix(cache): use passed store object by Leichtwind ยท Pull Request #10591 ยท nestjs/nest (github.com)
๋๋ Nest๋ฅผ cli ๋ฅผ ์ฌ์ฉํ์ฌ ์
๋ฐ์ดํธ๋ฅผ ํ์๋๋ฐ, ํด๋น ๋ฒ๊ทธ๋ฅผ ์์ ํ ํจ์น๊ฐ ์ ์ฉ์ด ์๋ 9.2.0 ๋ก ์
๋ฐ์ดํธ๊ฐ ๋์ด์์๋ค.
๋น์ฐํ ๊ฐ์ฅ ์ต๊ทผ ๋ฒ์ ์ผ๋ก ํจ์น๋ ์ค ์์๋๋ฐ ์๋์๋ค.
package.json์ผ๋ก ๋ฒ์ ํ์คํ๊ฒ ๋ช
์ํด์ ์
๋ํ๊ธธ ์ถ์ฒ..

Comparing 37764e717b400f3aa523f3755d83fea01263c9f7..3be19e694fc7491d45dd7b3c541c91fd9171014e ยท nestjs/nest (github.com)
ํด๋น ์ปค๋ฐ์ ๋ณด๋ฉด ์ด๋ ๊ฒ ์์ ๋์๋ค.
๊ทผ๋ฐ ์ฌ์ ํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ํธํ๋ฌธ์ ์ ๋์ํด์ ์ ๋๋ก ์์ ๋์ง ๋ชปํ ๊ฒ ๊ฐ๋ค.
๋ฌธ์ ํด๊ฒฐ ๊ณผ์
์ฝ์งํ๋ฉด์ ์๊ฒ ๋ ์ ๋ณด๋ฅผ ์ ๋ฆฌํด๋ณด๋ ค ํ๋ค.
(์๋ฌ ๋ฌด์ํ๊ฒ ํ๋ ์ฃผ์์ ์ถ๊ฐํ๋ ๋ฐฉ๋ฒ์ ์ฌ์ด๋ ์ดํํธ๊ฐ ํด ๊ฒ ๊ฐ์์ ์๋ํ์ง ์์๋ค.)
์๋ 1: create ๋ฉ์๋๋ฅผ ํตํด ๊ฐ์ฒด๋ฅผ ๋ฐํ
CacheModule ๋ด ์ค์ ์ ๋ค์๊ณผ ๊ฐ์ด ์ ์ด์ฃผ์๋ค.
// app module ๋ด import ์ ์ ์ด์ค๋ค. | |
CacheModule.registerAsync<RedisClientOptions>({ | |
imports: [ConfigModule], | |
useFactory: async (configService: ConfigService) => { | |
const store = await redisStore({ | |
socket: { | |
host: configService.get<string>('REDIS_HOST'), | |
port: configService.get<number>('REDIS_PORT'), | |
}, | |
}); | |
return { | |
store: { | |
create: () => store, | |
}, | |
}; | |
}, | |
inject: [ConfigService], | |
}) |
์ด๋ ๊ฒ ์๋ํ ์ด์ ๋ Nest ์์ store ํ๋กํผํฐ๋ฅผ ํ์
๋ณ๋ก ๋ค๋ฅด๊ฒ ์ฒ๋ฆฌํ๋๋ฐ, ๋ผ์ด๋ธ๋ฌ๋ฆฌ์์ ์ฃผ๋ ๊ฐ์ฒด๋ฅผ ์ ๋๋ก ์ฝ์ด์ค๊ฒ๋ ๋ฐํํ์
์ ๋ง์ถ์ด์ฃผ๊ธฐ ์ํด์์๋ค.
์ถ๊ฐ: ๊นํ๋ธ ๋์๋ค๋๋ค๊ฐ ๋ค๋ฅธ ์ฌ๋ ์ฝ๋ ๋ดค๋๋ฐ (CacheModule.registerAsync<RedisClientOptions | any>({ ... }) ) ์ด๋ ๊ฒ ์จ๋ ๋์๊ฐ๊ธด ํ๋ ๊ฒ ๊ฐ๋ค.
๋ ์์ธํ ์ค๋ช
ํ์๋ฉด, ๋ผ์ด๋ธ๋ฌ๋ฆฌ์์ ์๋กญ๊ฒ ์
๋ฐ์ดํธ๋๋ฉด์
- ํด๋น ์ฝ๋๋ฅผ
cache-manager-redis-store
๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ์ ๋ฐ์ดํธ ๋๋ฉด์ redisStore() ๋น๋๊ธฐ ํจ์๋ฅผ ๊ฐ์ ธ์์ ์์ฒด์ ์ผ๋ก ์ค๋ธ์ ํธ๋ฅผ ๋ง๋ ๋ค. (๊ฑฐ๊ธฐ์ config ๊ฐ๋ socket ๋ด์์ ์ค์ ํ๋ ๊ฒ์ผ๋ก ์ ๋ฐ์ดํธ๋์๋ค.)
export function redisStore(config: RedisClientOptions & StoreConfig): Promise<RedisStore>;
- redisStore ํจ์์ ์ธ์ ๊ฐ์ผ๋ก ์ค์ ์ต์
๋ค์ ๋ฃ๊ณ
redisStore๋ผ๋
์์ฒด ์ค๋ธ์ ํธ๋ฅผ ๋ฐํํ๋ค.
๊ทธ๋ฐ๋ฐ ์ด๋ nest์์๋
- store ๊ฐ object์ผ ๊ฒฝ์ฐ, store ๊ฐ์ฒด ๋ด create๋ผ๋ function ์ด ์กด์ฌํ๋์ง ํ์ธํ๋ค.
- ์ด๋ฅผ ์ํด์ nestjs ๊ฐ ์ธ์ํ ์ ์๊ฒ๋ ํ์ ์ ๋ง์ถ์ด ์ฃผ์๋ค.
nest js ํ๋ ์์ํฌ๊ฐ ์ค์ ๋ก ์ด๋ป๊ฒ ์ฒ๋ฆฌํ๋์ง ์๋ ์ฝ๋์ ์ค๋ช ์ ํจ๊ป ๋ณธ๋ค๋ฉด ๋ ์ดํดํ๊ธฐ ์ฌ์ธ ๊ฒ์ด๋ค.
- packages/common/cache/cache.providers.ts This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
// packages/common/cache/cache.providers.ts let cache: string | Function = 'memory'; defaultCacheOptions.ttl *= 1000; if (typeof store === 'object' && 'create' in store) { cache = store.create; } else if (typeof store === 'function') { cache = store; }
store ๊ฐ object์ผ ๊ฒฝ์ฐ, store ๊ฐ์ฒด ๋ด create ๋ผ๋ function ์ด ์กด์ฌํ๋์ง ํ์ธํ๋ค.
๊ทธ๋ฆฌ๊ณ ํด๋น ๊ฐ์ฒด ๋ด์ ์๋ create ๋ฉ์๋๋ฅผ ํตํด์ ๊ฐ์ ์ฝ๋๋ค๋ ๊ฒ์ ์ ์ ์๋ค.
- packages/common/cache/interfaces/cache-module.interface.ts This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
//packages/common/cache/interfaces/cache-module.interface.ts export interface CacheStoreFactory { /** * Return a configured cache store. * * @param args Cache manager options received from `CacheModule.register()` * or `CacheModule.registerAsync()` */ create(args: LiteralObject): CacheStore; } /** * Interface defining Cache Manager configuration options. * * @publicApi */ export interface CacheManagerOptions { /** * Cache storage manager. Default is `'memory'` (in-memory store). See * [Different stores](https://docs.nestjs.com/techniques/caching#different-stores) * for more info. */ store?: string | CacheStoreFactory | CacheStore; /** * Time to live - amount of time that a response is cached before it * is deleted. Subsequent request will call through the route handler and refresh * the cache. Defaults to 5 seconds. In `cache-manager@^4` this value is in seconds. * In `cache-manager@^5` this value is in milliseconds. */ ttl?: number; /** * Maximum number of responses to store in the cache. Defaults to 100. */ max?: number; isCacheableValue?: (value: any) => boolean; }
CacheStoreFactory๋ผ๋ interface๋ฅผ ํ์ธํด ๋ณด๋ฉด, ์ด๋ ๊ฒ ๊ตฌํ๋์ด ์๋ค.
(๊ฒฐ๋ก ํํธ์์ ํ์ ํ๊ฒ ์ง๋ง, cache-manager-redis-store ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ๋ฒ์ 3์ผ๋ก ์
๋ฐ์ดํธ๋๋ฉด์, ๋ ์ด์ factory method๋ฅผ ํตํด์ store ๊ฐ ์ธ์คํด์คํ ๋์ง ์๋๋ค๊ณ ํ๋ค.)
๊ฒฐ๊ณผ๋ ์ฌ์ ํ ํ์
์ค๋ฅ๊ฐ ๋ฐ์ํ์๋ค.
Type 'RedisStore' is not comparable to type 'CacheStore'
'CacheModuleAsyncOptions<RedisClientOptions<RedisModules, RedisFunctions, RedisScripts>>'
์๋ 2: ํ์ ์ ์์๋ก ์ง์
import { CacheStore } from '@nestjs/common/cache/interfaces/cache-manager.interface' | |
CacheModule.registerAsync({ | |
imports: [ConfigModule], | |
useFactory: async (configService: ConfigService) => | |
await redisStore({ | |
socket: { | |
host: configService.get<string>('REDIS_HOST'), | |
port: configService.get<number>('REDIS_PORT'), | |
}, | |
}) as unknown as CacheStore, | |
inject: [ConfigService], | |
}), |
์ด๋ ๊ฒ ์๋ํด ๋ณด์์ ๋, ํ์
์ค๋ฅ๋ ํด๊ฒฐ๋์์ผ๋, redisStore์์ ๋ฉ์๋๋ฅผ ๋ชป ์ฝ์ด์ค๋ ๋ฌธ์ ๊ฐ ๋ฐ์ํ๋ค.
[Nest] 24171 - 01/12/2023, 3:58:21 PM ERROR [ExceptionsHandler]
this.cacheManager.set is not a function
์ด๋ ์ฌ์ฉํ ๋ฒ์ ์ ๋ค์๊ณผ ๊ฐ๋ค.
"@nestjs/core": "9.0.11",
"cache-manager": "4.1.0",
"cache-manager-redis-store": "3.0.1",
๋ด ๊ธฐ์ต์ผ๋ก๋ cache-manager-redis-store ๋ฒ์ 2.0.0 ์ผ๋ก ๋ฎ์ถ์ด๋ ์ค๋ฅ๊ฐ ๋ฌ์๋ ๊ฒ ๊ฐ๋ค.
(๊ธฐ์ต์ ์์กดํ ๋ด์ฉ์ด๋ผ ์ด ๋ถ๋ถ์ ํ์คํ ๊ฒ์ ์๋๋ ๋ชจ๋ ์ปค์คํ
์ค์ ๋์ ๋ค์ด๊ทธ๋ ์ด๋ ๋ฐฉ์์ ์จ๋ณผ ์ฌ๋์ ํ๋ฒ ์๋ํด๋ด๋ ๋ ๊ฒ ๊ฐ๋ค.)
3.0์ผ๋ก ํ์๋๊ฒ ๊ณต์๋ฌธ์์์๋ redis v3 ์ฐ๋ผ๊ณ ์ ํ์์๋๋ฐ, ์ฌ์ฉํ๋ redis ๊ด๋ จ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ์ ์ฝ๋์ ๋ง์ง๋ง ๊บผ ๋ฟ์ด์๊ณ , ๊นํ๋ธ ์ด์์์ ์ฌ๋๋ค์ด ๋ฒ์ ๋ช
์๋ฅผ ์ ๋ ๊ฒ ํ๋๋ฐ ๋์๊ฐ๋ค๊ณ ํด์ ์ ๋ ๊ฒ ์ค์ ํ๋ค. (๊ทธ ์ธ์ ์ฌ๋๋ค์ด ํด๋ณด๋ ๋๋ก ๋ค ํด๋ดค๋๋ฐ ์ ์๋์๊ฐ๋ค.)
์๋ 3: ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋ฒ์ ์ ๊ณต์ ๋ฌธ์ ๊ธฐ์ค์ผ๋ก ๋ง์ถฐ๋ณด๊ธฐ
Redis cashe ๊ด๋ จ ๊ณต์๋ฌธ์์์ ์ฐ์ธ ์์ ์ฝ๋์ dependencies๋ ๋ค์๊ณผ ๊ฐ๋ค.
"@nestjs/common": "9.0.1",
"@nestjs/core": "9.0.1",
"cache-manager": "4.1.0",
"cache-manager-redis-store": "2.0.0",
"redis": "3.1.0" // ์์ ์ฝ๋์๋ ์์ง๋ง ๊ณต์๋ฌธ์์ ์ ํ ๋๋ก 3.x.x ๋ก ์ค์นํด๋ด
๊ทธ๋ฌ๋ ์ด๋ ๊ฒ ๋ฒ์ ์ ๋ง์ถ ๋ค์ ๊ณต์๋ฌธ์ ๋๋ก ์งํํ์ด๋, ๊ณ์ ์๋ฌ๊ฐ ๋ฐ์ํ์๋ค.
nest/sample/20-cache at master ยท nestjs/nest (github.com)
์ฌ์ง์ด ๋ ๋์ค ์บ์ ๊ด๋ จ ๊ธฐ๋ก ์ง์๋์;;; ์ปค๋ฐ๋ด์ญ ๋ค์ ธ์ ํ์ธํ๋ค.

๋ ์ฐพ์๋ณด๋๊น
- javascript - In Nest js, I added Redis as a cache manager. And can't find any added data in Redis after calling the set function. So, am I missing something? - Stack Overflow
- NestJS v9 incompatible with version 5 ยท Issue #210 ยท node-cache-manager/node-cache-manager ยท GitHub
Nest Js ๋ฒ์ 9 ์์ฒด์์ ํธํ์ด ์๋๋ ์ค๋ฅ์๋ค๊ณ ํ๋ค.
๋จ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋จ์์ ๋ง์ ๋ฌธ์ ๊ฐ ์๋์๋ค.
๋ํ node-cache-manager
version 5 ๋ํ Nest version 8๊ณผ ํธํ์ด ์๋๋ค๊ณ ํ๋ค.
nest@9.2์์ ํด๊ฒฐ๋์๋ค๋ ๊ธ์ ๊นํ๋ธ issue๋์์ ๋ณด์์์ด์, nest js ํ๋ ์์ํฌ๋ฅผ ์์ ์ต์ ๋ฒ์ ์ผ๋ก ์
๋ฐ์ดํธ๋ ํด๋ณด์๋ค.
๋ ํ๋ ์์ํฌ ์ต์ ๋ฒ์ ์ธ ์ํ๋ก ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ์์ ํ์ผ package.json ๋๋ก ๋ฒ์ ์ ์ด๋ฆฌ์ ๋ฆฌ ๋ฐ๊พธ์ด์ ์๋ํด ๋ณด์์ง๋ง ๋ชจ๋ ์ ๋๋ก ์๋๋์ง ์์๋ค.
์ตํ์ ์๋จ์ผ๋ก ํ๋ ์์ํฌ ์์ฒด ๋ฒ์ ์ 8๋ก ๋ฎ์ท๋๋ function์ด ์๋๋ผ๋ ์๋ฌ ๋ฉ์์ง๋ ์ ๋ด์ง๋ง, redis DB์๋ ๊ฐ์ด ์ ๋๋ก ๋ค์ด์ค์ง ์์๋ค.
์๋ 4: spread ์ฐ์ฐ์ ์ฌ์ฉํด์ ์ธํฐํ์ด์ค ๋ ธ์ถ์ํค๋ ๋ฐฉ๋ฒ
orlein.github.io/2022-10-23-nestjs-redis-cache.md at a08be1dd9f29e367baa87ce3fa684cfa1be5698d ยท orlein/orlein.github.io
์ฌ๊ธฐ ๋ฌธ์ ์ฐธ๊ณ ํด์ ๋ฐ๋ผํด๋ดค๋๋ฐ, ์ด๊ฒ๋ ํ์
์ค๋ฅ๋ ํด๊ฒฐ๋์๊ธด ํ๋ฐ ์ฌ์ ํ ์๋๋ค.
CACHE_MODULE_OPTIONS ์์กด์ฑ ์ค๋ฅ๊ฐ ๋จ๋๋ฐ, ๊ทผ๋ณธ์ ์ผ๋ก๋ Nest Js ํ๋ ์์ํฌ ์์ฒด ๋ฌธ์ ๋ผ์ ๊ทธ๋ฅ ๊ธ๋ก๋ฒ ๋ชจ๋์ ๋ฐ๋ก ๋ง๋ค์ด ์ฃผ๊ฑฐ๋ ๋ค์คํธ@9.2.1 ์ด์ ์
๋ฐ์ดํธํด์ ์ ์ฉํ๋ ๋ฐฉ๋ฒ์ด ํ์ฌ๋ก์๋ ์ต์ ์ธ ๊ฒ ๊ฐ๋ค.
์๋ 5: ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ฌ์ฉ
๊ตฌ๊ธ๋ง ํด๋ณด๋๊น, @liaoliaots/nestjs-redis - npm ํด๋น ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ๋ค์ด๋ก๋ ์๋ ๊ด์ฐฎ์ ๊ฒ ๊ฐ๊ณ , ์ค๋ช
์ ์ฝ์ด๋ณด๋ Nest v9์์๋ ์ ํธํ์ด ๋๋ค ํ์ฌ์ ์ฌ์ฉํด ๋ณด์๋ค.
๊ทผ๋ฐ... value ๊ฐ์ผ๋ก string๋ง ์ง์ํ๋ค.
redis๋ฅผ ์ฐ๋ ์ด์ ๊ฐ ๋ค์ํ ์๋ฃ๊ตฌ์กฐ๋ฅผ ๋ณด์ฅํ๊ธฐ ๋๋ฌธ์ธ๋ฐ ์ธ๋ชจ๊ฐ ์์๋ค.
์ฌ์ง์ด Json.stringfy()๋ฅผ ์จ์ ์ ์ฉํด ๋ณผ๊น ํ๋ค๊ฐ, ์ด๊ฒ๋ ์ค๋ฅ๊ฐ ๋ฐ์ํ๊ธธ๋ ์ฌ์ฉํ์ง ์์๋ค.
์๋ฌ ์ด์ ๋ถ์ ๋ฐ ๊ฒฐ๋ก
์๋ฌ ์ด์ ๋ถ์
1. CacheStoreFactory ๊ด๋ จ ํธํ ๋ฌธ์
nest js (๋ฒ์ 9.2.1 ์ดํ)๋ CacheStoreFactory ๊ฐ์ฒด ๋ด create ๋ฉ์๋๋, ํจ์๋ฅผ ํตํด์ ๋ฐํ๋ cashStore ๊ฐ์ฒด๋ฅผ ๊ธฐ๋ํ์ง๋ง, cache-manager ๋ผ์ด๋ธ๋ฌ๋ฆฌ์์๋ ๋ฒ์ 5์ผ๋ก ์
๋ฐ์ดํธ๋ฅผ ํ๋ฉด์ ๊ทธ๋ฐ ๋ฐฉ์์ ์์ ํ ๋ฒ๋ ธ๋ค.
ํด๋น ์ค๋ช
์ ์ฌ๊ธฐ ๊ธ์์ ์ฝ์ง 1 ๋ถ๋ถ์ ๋ณด๋ฉด ๋๋ค.
2. store ๊ฐ์ฒด ํ์ ํธํ ๋ฌธ์
๋ํ ๋ ๋ค ์ต์ ๋ฒ์ ๊ธฐ์ค์ผ๋ก (nest ๊ฐ์ฅ ์ต์ ๋ฒ์ : 9.2 , cache-manager v5) store ๊ฐ์ฒด ํ์
์ด ์๋ก ํ์
ํธํ์ด ์๋์ด์๋ค. (2023.1.13. ๊ธฐ์ค)
cache-manager-redis-store ๋ผ์ด๋ธ๋ฌ๋ฆฌ์์ ์ ์๋ RedisStore interface๋ ๋ค์๊ณผ ๊ฐ๋ค.
์ฝ๋ ์ถ์ฒ: dabroek/node-cache-manager-redis-store ยท GitHub
// cache-manager-redis-store ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋ด ์ฝ๋ | |
import type { Store, StoreConfig } from "cache-manager"; | |
import type { RedisClientType, RedisClientOptions } from "redis"; | |
// node_modules/cache-manager-redis-store/dist/index.d.ts | |
interface RedisStore extends Store { | |
name: string; | |
getClient: () => RedisClientType; | |
isCacheableValue: any; | |
set: (key: any, value: any, options: any, cb: any) => Promise<any>; | |
get: (key: any, options: any, cb: any) => Promise<any>; | |
del: (...args: any[]) => Promise<any>; | |
mset: (...args: any[]) => Promise<any>; | |
mget: (...args: any[]) => Promise<any>; | |
mdel: (...args: any[]) => Promise<any>; | |
reset: (cb: any) => Promise<any>; | |
keys: (pattern: string, cb: any) => Promise<any>; | |
ttl: (key: any, cb: any) => Promise<any>; | |
} | |
export function redisStore(config: RedisClientOptions & StoreConfig): Promise<RedisStore>; |
RedisStore ๋ Store ๋ผ๋ ์ธํฐํ์ด์ค๋ฅผ ์์๋ฐ๊ณ ์ค๋ฒ๋ผ์ด๋ฉํ๋ค.
nest js ํ๋ ์์ํฌ์์ ์ ์๋ CacheStore interface๋ ๋ค์๊ณผ ๊ฐ๋ค.
์ฝ๋ ์ถ์ฒ: nestjs/nest/cache-manager.interface.ts ยท GitHub
// nestJs github repository: packages/common/cache/interfaces/cache-manager.interface.ts | |
export interface CacheStore { | |
/** | |
* Create a key/value pair in the cache. | |
* | |
* @param key cache key | |
* @param value cache value | |
*/ | |
set<T>( | |
key: string, | |
value: T, | |
options?: CacheStoreSetOptions<T> | number, | |
): Promise<void> | void; | |
/** | |
* Retrieve a key/value pair from the cache. | |
* | |
* @param key cache key | |
*/ | |
get<T>(key: string): Promise<T | undefined> | T | undefined; | |
/** | |
* Destroy a key/value pair from the cache. | |
* | |
* @param key cache key | |
*/ | |
del?(key: string): void | Promise<void>; | |
} |
๋ฐ๋ผ์ ์๋ก ํ์
์ด ํธํ๋์ง ์๋๋ค.
๊ณต์๋ฌธ์์์๋ CacheModule์์ cacheStore๋ฅผ ์ฝ์ด์ค๊ธฐ ์ํด์
CacheModule.register<ClientOpts>({
store: redisStore,
// Store-specific configuration:
host: 'localhost',
port: 6379,
}),
๋ผ๊ณ ํ๋๋ฐ, ๋น์ฐํ ๋ ํฑ์ด ์๋ค.
์ฌ์ง์ด, ์ ์ด์ ClientOpts ๋ผ๋ ํ์
๋ ์๊ณ , ํ์
๋ค์ด ์์ ํ ๋ฐ๋์๋ค.
nest js๋ CacheStoreFactory ๊ฐ์ฒด ๋ด create ๋ฉ์๋๋, ํจ์๋ฅผ ํตํด์ ๋ฐํ๋ cashStore ๊ฐ์ฒด๋ฅผ ๊ธฐ๋ํ์ง๋ง, ๋ผ์ด๋ธ๋ฌ๋ฆฌ์์๋ ๊ทธ๋ฐ ๋ฐฉ์์ ์์ ํ ๋ฒ๋ ธ๋ค. (๊ทธ๋์ ์ต์ง๋ก ํ์
์ ๋ง์ถฐ์ฃผ์ด๋ ์ค๋ฅ๊ฐ ๋ฐ์ํ ๊ฒ ๊ฐ๋ค.)
๊ฒฐ๋ก
๊ฒฐ๊ตญ์ ํ๋ ์์ํฌ - ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ผ๋ฆฌ ์๋ก ํธํ์ด ์๋ ์ด์ฒด์ ๋๊ตญ์ด์๋ค.
์ค๋ฅ๊ฐ ๋๊ธฐ ์์ํ ๋ฒ์ ๊ธฐ์ค์ผ๋ก ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ํ๋ ์์ํฌ ์
๋ฐ์ดํธ ๋ ๋ ์ง๋ฅผ ํ์ธํด ๋ณด๋
- NestJs v9.0.0 - 2022.07.08.
Releases ยท nestjs/nest - Cache-manager: v.5.0.0 - 2022๋
10์
(github์์๋ ๋ฒ์ 4 ๋ฆด๋ฆฌ์ฆ๊ฐ ์ ๋์์์ง๋ง, ์๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ์๊ธฐ๊ฐ ๋น์ทํ ๊ฒ์ผ๋ก ์ถ์ ๋๋ค.)
Releases ยท cache-manager - node-cache-manager-redis-store: v3.0.0 - 2022.10.15.
Releases ยท node-cache-manager-redis-store
redis-store์์ ๋ฒ์ 3์ผ๋ก ์
๋ฐ์ดํธํ๋ฉด์ Breaking Changes์์ ์ถ๊ฐ์ ์ธ ์ ๋ณด๋ฅผ ์ ์ ์๋ค.
The store needs to be instantiated before passing it to cache-manager and can no longer be instantiated with the factory method.
์ถ๊ฐ์ ์ผ๋ก Nest ๋ฆด๋ฆฌ์ฆ ๋
ธํธ๋ฅผ ํ์ธํด๋ณด๋ฉด v 9.2.1 ์์ ํด๋น ๋ฌธ์ ๋ฅผ ๊ณ ์น๋ ค๋ PR ์ด ์๊ธด ํ๋ฐ, ๊ถ๊ทน์ ์ผ๋ก๋ ํด๊ฒฐ ์๋์๋ค.
์ข
ํฉํ์๋ฉด ๋ค์๊ณผ ๊ฐ๋ค.
- ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋ด redisStore์ Nest์์ cacheStore ๊ฐ์ฒด๋ผ๋ฆฌ ํ์ ์ด ํธํ๋์ง ์๋๋ค.
- ํด๋น ๊ฐ์ฒด๋ฅผ ํธ์ถํ๋ ๋ฐฉ์๋ ๋ฌ๋ผ์ก๋ค.
- ์ด๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด์ ์์ฒด์ ์ผ๋ก ๋ชจ๋ํ๋ฅผ ํ์๋ค.
Incompatible with NestJS cache store ยท Issue #53 ยท dabroek/node-cache-manager-redis-store (github.com)
> ๋ณด๋ฉด 1์ 20์ผ ๊ธฐ์ค ์์ง ์๊ณ ์ณ์ง
์
๋ฐ์ดํธ ๋ ์ง๋ฅผ ๋ณด์์ ๋, ์๋
๋ง์ ๋ฐ์ํ ์ด์๋ผ์ ๊ตฌ๊ธ๋ง ํด๋ ์ ๋๋ก ํด๊ฒฐ๋ฐฉ๋ฒ์ด ๋์ค์ง ์์์ ๊ฝค๋ ๊ณ ์์ ํ๋ค.
๊ทธ๋ฌ๋ ๊ฒฐ๊ตญ ์ค์ค๋ก ๋์์์ด ์ค๋ฅ๋ฅผ ํด๊ฒฐํ๊ณ , ์์ธ๋ ํ์
ํ ์ ์๊ฒ ๋์๋ค.
์ interface ์ ํ์
์ ๋ช
์ํ๋๊ฒ ์ ๋ง ์ค์ํ๋ค๋ ์ ๋ ์๊ฒ ๋์๋ค.
๋ง์ฝ ์ถ์ํ๊ฐ ๋์ด์์ง ์์๋ค๋ฉด, ์ฝ๋๋ฅผ ํ์
ํ๊ธฐ ์ด๋ ค์ ์ ๊ฒ ๊ฐ๊ณ , JS์ฒ๋ผ ํ์
์ด ์ ๋๋ก ๋ช
์ ๋์ด ์์ง ์๋ค๋ฉด, ๋๋ฒ๊น
์ ํด๋ ์์ธ์ ๋ชป์ฐพ์์ ๊ฒ ๊ฐ๋ค.
์ด๋ฅผ ํตํด์ ๋น์ทํ ์๋ฌ๊ฐ ๋ฐ์ํ์ ๋ ์ข ๋ ์๊ฐ์ ๋จ์ถํ ์ ์์ ๊ฒ์ด๋ค.
๊ณต์๋ฌธ์๋ง ๋ฏฟ๊ณ ๊ฐ์๋๋ฐ ์ฒ์ ๊ฒช์ด๋ณธ ์์ํ์ง ๋ชปํ ๋ฌธ์ ๊ฐ ๋ฐ์ํด์ ๋ง์ด ๋นํฉํ๋ค.
์ฌ์ค ์ข ๋ ๋์ ๋ฐฉ๋ฒ์ด ์์ ๊ฒ ๊ฐ๊ธด ํ๋ค.
์ด๋ฒ์๋ ๋ค์ด๊ทธ๋ ์ด๋ ํด๋ ์๋์ด ๋์ง ์์์ ์ด๋ ๊ฒ ๋ฐฉ๋ฒ์ ์ฑํํ๋ค.
๋ฒ์ ์ ๋ง์ถฐ์ค๋ค๋๊ฒ ์ฌ์ค ์ด๋๊น์ง๊ฐ ์์ ์ ์ผ๋ก ๋์๊ฐ๋ ๊ฒ์ธ์ง ํ์
ํ๊ธฐ๊ฐ ์ด๋ ค์ด ๊ฒ ๊ฐ๋ค.
๊ทธ๋ฆฌ๊ณ ํ์
์ any, unknown์ ์ฌ์ฉํ๊ฑฐ๋ ์๋ฌ ๋ฌด์ํ๊ฒ ํ๋ ๋ช
๋ น์ด๋ฅผ ์ถ๊ฐํ๋ ๋ฐฉ๋ฒ๋ ์๋ ๊ฒ ๊ฐ๊ธด ํ๋ฐ, ์์ง ๊ณต๋ถ ๋จ๊ณ์ธ์ง๋ผ ์ด๊ฒ์ ๊ฒ ์ฌ๋ฌ๊ฐ์ง๋ก ์๋ํด๋ณด์๋ค.
๋ค์ด๊ทธ๋ ์ด๋๊ฐ ๋์์ง, ๋ชจ๋์ ๋ฐ๋ก ๋ง๋ค์ด์ฃผ๋๊ฒ ๋์ ๊ฒ์ธ์ง ์ ํํ์ด์ผ ํ๋๋ฐ...
์ฌ์ค ์์ ์ ์ธ ๋ฒ์ ์ผ๋ก ๋ค์ด๊ทธ๋ ์ด๋ ํ๋ ๊ฒ์ด ์ค๋ฌด์์ ๋ ๋ง์ด ์ ์ฉ๋๋ ๋ฐฉ๋ฒ์ผ ๊ฒ ๊ฐ๋ค๋ ์๊ฐ์ด ๋ค์๋ค.
๊ทธ๋์ ๋ค์์ ๋ ์ด๋ฐ ์์กด์ฑ ๋ฌธ์ ๋ฅผ ๋ง๋๋ค๋ฉด, ์ต๋ํ ๊ฐ์ฅ ์์ ์ ์ธ ๋ฒ์ ์ด ๋ฌด์์ธ์ง๋ฅผ ์ฐพ์๋ณผ ๊ฒ์ ์ค์ ์ ๋ ๊ฒ ๊ฐ๋ค.
๋ Node js ์์ฒด๊ฐ ๋น๊ต์ ์ ๊ธฐ์ ์ด๋ผ ๊ทธ๋ฐ๊ฑด์ง ๋ชจ๋ฅด๊ฒ ์ง๋ง ๊ฐ๋ ์ด๋ฐ ์๊ฐ์ด ๋นํน์ค๋ฝ๊ธฐ๋ํ๋ค. (TypeOrm ์ด ์์ง๋ 0.xx ๋จ๊ณ์ธ ๊ฒ๋....)
์ฒจ์ธ:
cache-manager-redis-store-yet ์ด๋ฐ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ์๋ ๊ฒ ๊ฐ์๋ฐ, ์ด๋ป๊ฒ ์ฐ๋์ง ๋ฌธ์๊ฐ ์
๋ฐ์ดํธ ์๋์ด์๊ณ , ๊ตฌ๊ธ๋ง ํด๋ด๋ ์ ๋์ค๊ณ , github์ ํด๋น ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ด ์ฝ๋๊ฐ ์๋์ง ์๋ฌด๋ฆฌ ๊ฒ์ํด ๋ด๋ ๋ณด์ด์ง ์์์ ์ฌ์ฉํ์ง ์์๋ค.
โ 2023.1.20. ์ถ๊ฐ: ํด๊ฒฐ๋ฐฉ๋ฒ 2์ ์ฌ์ฉ๋์์
์ฐธ๊ณ : cach-manager v4์์๋ ttl ์๊ฐ ๋จ์๊ฐ sec๊ณ , v5์์๋ ms์ด๋ค. (๊ณจ ๋๋ฆผ;)
+ ๋๋ฐ ์งฑ ๊ธฐ๋ถ ์กฐ์ ๊ณต์๋ฌธ์ ์
๋๋๊ฑฐ ๋ณด๋๊น ๋ด๊ฐ ๋ถ์ํ๊ฒ ๋ง์์ใ
ใ
Caching | NestJS - A progressive Node.js framework

์ฐข์๋ค
'๋ฐฑ์๋ > ๐๏ธ Nest.js' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[Nest.js] Utils - ms๋ก ์๊ฐ ๋ณํํ๊ธฐ (0) | 2023.02.06 |
---|---|
[NestJs] Competing naming styles: mySQL snake ์คํ์ผ์ typeORM ์ํฐํฐ์์ Camel case๋ก ๋งคํํ๊ธฐ (0) | 2022.10.13 |