(최종 프로젝트 진행중)
TypeORM을 적용한 Nest.js 복습 중 해결한 에러를 간단히 정리했다.
에러 EntityMetadataNotFoundError: No metadata for "User" was found.
에러 EntityMetadataNotFoundError: No metadata for "User" was found.
발생 상황: npm run start으로 TypeORM 적용한 Nest.js 서버 가동 후 POST http://localhost:3000/user/signup
으로 요청보냄.
에러 메세지 전문:
[Nest] 13660 - 2023. 03. 01. 오후 5:50:35 ERROR [ExceptionsHandler] No metadata for "User" was found.
EntityMetadataNotFoundError: No metadata for "User" was found.
at DataSource.getMetadata (C:\Users\USER\Desktop\Sparta\04.3_nest_practice_with_typeorm\src\data-source\DataSource.ts:418:30)
at Repository.get metadata [as metadata] (C:\Users\USER\Desktop\Sparta\04.3_nest_practice_with_typeorm\src\repository\Repository.ts:52:40)
at Repository.findOne (C:\Users\USER\Desktop\Sparta\04.3_nest_practice_with_typeorm\src\repository\Repository.ts:529:42)
at UserService.getUserInfo (C:\Users\USER\Desktop\Sparta\04.3_nest_practice_with_typeorm\src\user\user.service.ts:46:38)
at UserService.createUser (C:\Users\USER\Desktop\Sparta\04.3_nest_practice_with_typeorm\src\user\user.service.ts:54:34)
at UserController.createUser (C:\Users\USER\Desktop\Sparta\04.3_nest_practice_with_typeorm\src\user\user.controller.ts:16:35)
at C:\Users\USER\Desktop\Sparta\04.3_nest_practice_with_typeorm\node_modules\@nestjs\core\router\router-execution-context.js:38:29
at InterceptorsConsumer.intercept (C:\Users\USER\Desktop\Sparta\04.3_nest_practice_with_typeorm\node_modules\@nestjs\core\interceptors\interceptors-consumer.js:11:20)
at C:\Users\USER\Desktop\Sparta\04.3_nest_practice_with_typeorm\node_modules\@nestjs\core\router\router-execution-context.js:46:60
at C:\Users\USER\Desktop\Sparta\04.3_nest_practice_with_typeorm\node_modules\@nestjs\core\router\router-proxy.js:9:23
시도: 찾아보니 app.module.ts 에 imports하는 entities에 User를 빼먹어서 그렇다고 한다.
// app.module.ts
@Module({
imports: [
TypeOrmModule.forRoot({
...
entities: [User] // User를 추가해줘야 함.
...
}),
...
],
})
내 경우는 TypeOrmModule > useClass를 이용하여 ormConfig에 데이터베이스 설정을 담아두었으므로, 다음과 같았다:
// app.module.ts
import { TypeOrmConfigService } from './config/typeorm.congif.service';
@Module({
imports: [
ConfigModule.forRoot({ isGlobal: true }),
TypeOrmModule.forRootAsync({
useClass: TypeOrmConfigService,
imports: [ConfigModule],
inject: [ConfigService],
}),
...
],
})
// config/typeorm.congif.service
@Injectable()
export class TypeOrmConfigService implements TypeOrmOptionsFactory {
constructor(private readonly configService: ConfigService) {}
createTypeOrmOptions(): TypeOrmModuleOptions {
return {
type: 'mysql',
...
// entities: [__dirname + '/**/*.entity{.ts,.js}'],
entities: [Article],
...
};
}
}
원인: 결국 app.module이 user.entity 파일에 정의된 “User” DB모델을 인식할 수 있도록 ‘entities’ 옵션에 나열해줘야 했다.
해결: (app.module.ts에 쓰이는) ormConfig 파일에 User 모델을 임포트하고 ‘entities’ 옵션에 넣어주니 해결되었다.
// config/typeorm.congif.service
import { User } from 'src/user/user.entity';
@Injectable()
export class TypeOrmConfigService implements TypeOrmOptionsFactory {
constructor(private readonly configService: ConfigService) {}
createTypeOrmOptions(): TypeOrmModuleOptions {
return {
type: 'mysql',
...
// entities: [__dirname + '/**/*.entity{.ts,.js}'],
entities: [Article, User],
...
};
}
}
(참고: https://stackoverflow.com/questions/51562162/no-metadata-for-user-was-found-using-typeorm)
에러 Error: secretOrPrivateKey must have a value
에러 Error: secretOrPrivateKey must have a value
발생 상황: npm run start으로 TypeORM 적용한 Nest.js 서버 가동 후 POST http://localhost:3000/user/signup
으로 요청보냄.
에러 메세지 전문:
[Nest] 6096 - 2023. 03. 01. 오후 6:06:08 ERROR [ExceptionsHandler] secretOrPrivateKey must have a value
Error: secretOrPrivateKey must have a value
at Object.module.exports [as sign] (C:\Users\USER\Desktop\Sparta\04.3_nest_practice_with_typeorm\node_modules\jsonwebtoken\sign.js:105:20)
at C:\Users\USER\Desktop\Sparta\04.3_nest_practice_with_typeorm\node_modules\@nestjs\jwt\dist\jwt.service.js:33:53
at new Promise (<anonymous>)
at JwtService.signAsync (C:\Users\USER\Desktop\Sparta\04.3_nest_practice_with_typeorm\node_modules\@nestjs\jwt\dist\jwt.service.js:33:16)
at UserService.createUser (C:\Users\USER\Desktop\Sparta\04.3_nest_practice_with_typeorm\src\user\user.service.ts:67:47)
at processTicksAndRejections (node:internal/process/task_queues:95:5)
at UserController.createUser (C:\Users\USER\Desktop\Sparta\04.3_nest_practice_with_typeorm\src\user\user.controller.ts:16:12)
at C:\Users\USER\Desktop\Sparta\04.3_nest_practice_with_typeorm\node_modules\@nestjs\core\router\router-execution-context.js:46:28
at C:\Users\USER\Desktop\Sparta\04.3_nest_practice_with_typeorm\node_modules\@nestjs\core\router\router-proxy.js:9:17
시도: process.env.JWT_KEY
뭔가 이걸 인식하지 못하고 있어서라고 해서 생각해보니, 나 JWT 시크릿 키 어디서 불러오고 있지? 설정해준 기억이 없다.
원인: JwtService가 JWT 토큰을 생성하고 검사하는 데 필요한 secret key가 제대로 인식되지 못해서 생긴 문제이다. 한 마디로 .env 파일에 JWT_SECRET 값을 만들어주지 않아서였다. 구체적으로는, app.module.ts와 user.module.ts에 사용되는 jwtConfig에 시크릿 키 옵션으로 지정해놓은 값이 제대로 읽히지 못해 발생한 에러라고 보면 되겠다.
// src/user/user.module.ts
import { JwtModule } from '@nestjs/jwt'
import { JwtConfigService } from 'src/config/jwt.config.service';
@Module({
imports: [
...
JwtModule.registerAsync({
imports: [ConfigModule],
useClass: JwtConfigService,
inject: [ConfigService],
}),
],
...
})
//
import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { JwtModuleOptions, JwtOptionsFactory } from '@nestjs/jwt';
@Injectable()
export class JwtConfigService implements JwtOptionsFactory {
constructor(private readonly configService: ConfigService) {}
createJwtOptions(): JwtModuleOptions {
return {
secret: this.configService.get<string>('JWT_SECRET'),
signOptions: { expiresIn: '3600s' },
};
}
}
// 3. 환경 변수를 읽어오는 ConfigService가 읽어오는 파일인 .env
DATABASE_HOST="localhost"
...
JWT_SECRET="my_secret_key" // 이 줄이 없었음.
해결: 위와 같이 .env 파일에 JWT_SECRET 값을 지정해주니 해결되었다.
(참고: https://stackoverflow.com/questions/58673430/error-secretorprivatekey-must-have-a-value)
에러 QueryFailedError: ER_DATA_TOO_LONG: Data too long for column 'password' at row 1
에러 QueryFailedError: ER_DATA_TOO_LONG: Data too long for column 'password' at row 1
발생 상황: npm run start으로 TypeORM 적용한 Nest.js 서버 가동 후 PUT http://localhost:3000/user/update
으로 유저 정보 수정 요청을 보냄.
// src/user/user.controller.ts
@Controller('user')
export class UserController {
...
@Put('/update')
updateUser() {
this.userService.updateUser('userId2', 'new_name', 'new_password');
}
}
⇒ ‘userId2’를 Id로 가진 유저의 name을 “new_name”으로, password를 “new_password”로 업데이트하고자 함.
에러 메세지 전문:
C:\Users\USER\Desktop\Sparta\04.3_nest_practice_with_typeorm\src\driver\mysql\MysqlQueryRunner.ts:222
new QueryFailedError(query, parameters, err),
^
QueryFailedError: ER_DATA_TOO_LONG: Data too long for column 'password' at row 1
at Query.<anonymous> (C:\Users\USER\Desktop\Sparta\04.3_nest_practice_with_typeorm\src\driver\mysql\MysqlQueryRunner.ts:222:33)
at Query.<anonymous> (C:\Users\USER\Desktop\Sparta\04.3_nest_practice_with_typeorm\node_modules\mysql\lib\Connection.js:526:10)
at Query._callback (C:\Users\USER\Desktop\Sparta\04.3_nest_practice_with_typeorm\node_modules\mysql\lib\Connection.js:488:16)
at Query.Sequence.end (C:\Users\USER\Desktop\Sparta\04.3_nest_practice_with_typeorm\node_modules\mysql\lib\protocol\sequences\Sequence.js:83:24)
at Query.ErrorPacket (C:\Users\USER\Desktop\Sparta\04.3_nest_practice_with_typeorm\node_modules\mysql\lib\protocol\sequences\Query.js:92:8)
at Protocol._parsePacket (C:\Users\USER\Desktop\Sparta\04.3_nest_practice_with_typeorm\node_modules\mysql\lib\protocol\Protocol.js:291:23)
at Parser._parsePacket (C:\Users\USER\Desktop\Sparta\04.3_nest_practice_with_typeorm\node_modules\mysql\lib\protocol\Parser.js:433:10)
at Parser.write (C:\Users\USER\Desktop\Sparta\04.3_nest_practice_with_typeorm\node_modules\mysql\lib\protocol\Parser.js:43:10)
at Protocol.write (C:\Users\USER\Desktop\Sparta\04.3_nest_practice_with_typeorm\node_modules\mysql\lib\protocol\Protocol.js:38:16)
at Socket.<anonymous> (C:\Users\USER\Desktop\Sparta\04.3_nest_practice_with_typeorm\node_modules\mysql\lib\Connection.js:88:28)
시도:
password 부분이 문제라길래 설마설마하며 ‘new_password’ → ‘new_pass’로 바꿔 실행해보았다. 그러니 잘 되는 것을 확인했다…
원인: 에러 메세지 그대로, MySQL에서 삽입하려고 하는 데이터가 해당 컬럼의 Length 값보다 큰 길이의 값일 때 발생하는 에러였다. 현재 User 모델을 찾아가보니 다음과 같이 password 필드의 길이 한도는 10으로 되어있었다:
// src/user/user.entity.ts
import ...
@Entity({ schema: 'board', name: 'users' })
export class User {
...
@Column('varchar', { length: 10, select: false })
password: string;
...
}
해결:
선택1. 해당 컬럼의 Length에 설정된 값보다 작은 길이를 넣어준다.
⇒ ‘new_password’ 는 12자. 따라서 ‘new_passwd’ 같이 한도인 10자 내로 바꿔준다.
선택2. 해당 컬럼의 Length값 자체를 늘려준다.
// src/user/user.entity.ts
@Entity({ schema: 'board', name: 'users' })
export class User {
...
@Column('varchar', { length: 30, select: false })
password: string;
...
}
해결된 모습:
id | userId | name | password | createdAt | updatedAt | deletedAt |
1 | userId | name | password | Wed Mar 01 2023 18:06:08 GMT+0900 (한국 표준시) | Wed Mar 01 2023 18:06:08 GMT+0900 (한국 표준시) | null |
2 | userId2 | new_name | new_passwd | Wed Mar 01 2023 19:00:22 GMT+0900 (한국 표준시) | Wed Mar 01 2023 19:27:00 GMT+0900 (한국 표준시) | null |
배운 점:
아주 간단한 문제였다. TypeORM의 모델에서 length 값이 실제로 일하는 모습을 보게 되어 좋았다. ;;
Uploaded by N2T