작성
·
350
·
수정됨
0
// users.module.ts
import { Module } from '@nestjs/common';
import { UsersService } from './users.service';
import { UsersController } from './users.controller';
import { TypeOrmModule } from '@nestjs/typeorm';
import { Users } from '../entities/Users';
@Module({
imports: [TypeOrmModule.forFeature([Users])],
providers: [UsersService],
controllers: [UsersController],
})
export class UsersModule {}
// app.module.ts
import { MiddlewareConsumer, Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { ConfigModule } from '@nestjs/config';
import { LoggerMiddleware } from './middlewares/logger.middleware';
import { UsersModule } from './users/users.module';
import { WorkspacesModule } from './workspaces/workspaces.module';
import { ChannelsModule } from './channels/channels.module';
import { DmsModule } from './dms/dms.module';
import { UsersService } from './users/users.service';
import * as process from 'process';
import { TypeOrmModule } from '@nestjs/typeorm';
import { Users } from './entities/Users';
@Module({
imports: [
ConfigModule.forRoot({ isGlobal: true }),
UsersModule,
WorkspacesModule,
ChannelsModule,
DmsModule,
TypeOrmModule.forRoot({
type: 'mysql',
host: 'localhost',
port: 3306,
username: process.env.DB_USER,
password: process.env.DB_PW,
database: process.env.DB_NAME,
entities: ['./entities/*.{js,ts}'],
synchronize: false,
logging: true,
keepConnectionAlive: true,
migrations: [__dirname + '/src/migrations/*.ts'],
}),
TypeOrmModule.forFeature([Users]),
],
controllers: [AppController],
providers: [AppService, UsersService],
})
export class AppModule {
configure(consumer: MiddlewareConsumer): void {
consumer.apply(LoggerMiddleware).forRoutes('*');
}
}
// users.controller.ts
import {
Body,
Controller,
Post,
Get,
Req,
Res,
UseInterceptors,
} from '@nestjs/common';
import { ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';
import { JoinRequestDto } from './dto/join.request.dto';
import { UsersService } from './users.service';
import { UserDto } from '../common/dto/user.dto';
import { User } from '../common/decorators/user.decorator';
import { UndefinedToNullInterceptor } from '../common/interceptors/undefinedToNull.interceptor';
@UseInterceptors(UndefinedToNullInterceptor)
@ApiTags('USER')
@Controller('api/users')
export class UsersController {
constructor(private usersService: UsersService) {}
//.....
@ApiOperation({ summary: '회원가입' })
@Post()
async join(@Body() body: JoinRequestDto) {
await this.usersService.join(body.email, body.nickname, body.password);
}
import { HttpException, Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Users } from '../entities/Users';
import bcrypt from 'bcrypt';
@Injectable()
export class UsersService {
constructor() {}
@InjectRepository(Users)
private usersRepository: Repository<Users>;
getUser() {}
async join(email: string, nickname: string, password: string) {
const user = this.usersRepository.findOne({ where: { email } });
if (!email) {
throw new HttpException('이메일이 없습니다.', 400);
}
if (!nickname) {
throw new HttpException('닉네임이 없습니다.', 400);
}
if (!password) {
throw new HttpException('비밀번호가 없습니다.', 400);
}
if (user) {
throw new HttpException('이미 존재하는 사용자입니다.', 400);
}
const hashedPassword = await bcrypt.hash(password, 12);
await this.usersRepository.save({
email,
nickname,
password: hashedPassword,
});
}
}
// a-nest/src/entities/Users.ts
import {
Column,
Entity,
Index,
OneToMany,
PrimaryGeneratedColumn,
} from "typeorm";
import { Channelchats } from "./Channelchats";
import { Channelmembers } from "./Channelmembers";
import { Dms } from "./Dms";
import { Mentions } from "./Mentions";
import { Workspacemembers } from "./Workspacemembers";
import { Workspaces } from "./Workspaces";
@Index("email", ["email"], { unique: true })
@Entity("users", { schema: "sleact" })
export class Users {
@PrimaryGeneratedColumn({ type: "int", name: "id" })
id: number;
@Column("varchar", { name: "email", unique: true, length: 30 })
email: string;
@Column("varchar", { name: "nickname", length: 30 })
nickname: string;
@Column("varchar", { name: "password", length: 100 })
password: string;
@Column("datetime", { name: "createdAt" })
createdAt: Date;
@Column("datetime", { name: "updatedAt" })
updatedAt: Date;
@Column("datetime", { name: "deletedAt", nullable: true })
deletedAt: Date | null;
@OneToMany(() => Channelchats, (channelchats) => channelchats.user)
channelchats: Channelchats[];
@OneToMany(() => Channelmembers, (channelmembers) => channelmembers.user)
channelmembers: Channelmembers[];
@OneToMany(() => Dms, (dms) => dms.sender)
dms: Dms[];
@OneToMany(() => Dms, (dms) => dms.receiver)
dms2: Dms[];
@OneToMany(() => Mentions, (mentions) => mentions.sender)
mentions: Mentions[];
@OneToMany(() => Mentions, (mentions) => mentions.receiver)
mentions2: Mentions[];
@OneToMany(
() => Workspacemembers,
(workspacemembers) => workspacemembers.user
)
workspacemembers: Workspacemembers[];
@OneToMany(() => Workspaces, (workspaces) => workspaces.owner)
workspaces: Workspaces[];
}
서버 실행 후 http://localhost:3002/api/users URL로 빈 값을 POST로 보내면 콘솔창에 400 이메일이 없습니다.
라는 문구가 뜬 이후에
C:\Users\xxx\Documents\Project\NestProject\a-nest\src\data-source\DataSource.ts:448
if (!metadata) throw new EntityMetadataNotFoundError(target)
^
EntityMetadataNotFoundError: No metadata for "Users" was found.
at DataSource.getMetadata (C:\Users\xxx\Documents\Project\NestProject\a-nest\src\data-source\DataSource.ts:448:30)
at Repository.get metadata [as metadata] (C:\Users\xxx\Documents\Project\NestProject\a-nest\src\repository\Repository.ts:53:40)
at Repository.findOne (C:\Users\xxx\Documents\Project\NestProject\a-nest\src\repository\Repository.ts:597:42)
at UsersService.join (C:\Users\xxx\Documents\Project\NestProject\a-nest\src\users\users.service.ts:13:39)
at UsersController.join (C:\Users\xxx\Documents\Project\NestProject\a-nest\src\users\users.controller.ts:37:29)
at C:\Users\xxx\Documents\Project\NestProject\a-nest\node_modules\@nestjs\core\router\router-execution-context.js:38:29
at processTicksAndRejections (node:internal/process/task_queues:95:5)
위와 같이 EntityMetadataNotFoundError에러가 발생합니다. DB 커넥션 부분도 확인해보고, entities 부분이 문제인가 싶어 아래와 같이 변경도 해보았지만
TypeOrmModule.forRoot({
entities: ['./entities/*.{js,ts}'],
],
해결되지 않아 질문드립니다.
추가적으로 \data-source\DataSource.ts 부분과
\repository\Repository.ts부분은 실제 디렉토리에 없는 것들인데 왜 뜨는지도 모르겠습니다.
해결 방법이 있을까요?
답변 2
0
안녕하세요, 인프런 AI 인턴입니다. CB S님,
제공해주신 정보를 바탕으로 살펴보았을 때, EntityMetadataNotFoundError
는 TypeORM이 데이터베이스 테이블과 연결될 엔티티의 메타데이터를 찾을 수 없을 때 발생하는 오류입니다. 이 문제는 대개 엔티티 파일의 위치가 잘못되었거나, TypeOrmModule
에 엔티티를 잘못 등록했을 때 발생합니다.
질문에 있으신 코드와 에러 메시지에서 확인할 수 있는 몇 가지 지점은 아래와 같습니다:
entities
의 경로가 문자열로 처리되고, .ts
와 .js
둘 다 포함되어 있으나, 실제 애플리케이션을 실행하는 환경(개발환경 또는 프로덕션)에서 올바르게 해석되지 않을 가능성이 있습니다. 실제 개발 환경에서는 .ts
파일로 작업하며, 빌드 후 프로덕션 환경에서는 .js
로 변환되기 때문입니다.
\data-source\DataSource.ts
와 \repository\Repository.ts
부분이 실제로 없다고 하셨는데, 이는 TypeORM이 내부적으로 사용하는 파일들입니다. 디렉토리에 직접적으로 존재하지 않아도 TypeORM이 작업을 수행하면서 런타임에 참조하는 것일 수 있습니다.
해결 방법으로는 다음과 같은 접근을 시도해보실 수 있습니다:
entities
경로를 절대경로로 제공하거나, 애플리케이션이 실행되는 환경에 맞게 확장자를 명확하게 지정해보세요..js
파일들이 위치한 dist
디렉토리를 참조해야 한다면, 해당 디렉토리 경로를 정확하게 지정해주셔야 합니다.유사한 문제를 해결한 다른 질문들을 참고하셔도 좋을 것 같습니다:
DB 생성시 Error: Cannot find module ‘./index.js가 계속 뜨는데 뭐가 문제인가요??
typeorm을 통해 db 생성을 하려고 하는데 에러가 발생합니다.
기술적인 문제 해결의 경우, 상황에 따라 다양한 요소를 검토해야 하므로 질문 내용에서 제시된 내용만으로는 정확한 원인을 파악하기 어려울 수 있습니다. 따라서 위의 내용을 참고해보시되, 문제가 해결되지 않는다면 추가적으로 강의 내용을 검토하시거나 직접 강사님께 상세한 상황을 설명하신 후 보다 정확한 답변을 받으실 수 있습니다.
저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다.
현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏
추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.
app.module.ts부분 중 아래와 같이 entities를 가져오는 부분을 수정했습니다.
@Module({
...
entities: [
Users,
Channels,
Dms,
Channelchats,
Mentions,
Channelmembers,
Workspacemembers,
Workspaces,
],
...
}
서버는 끊기지 않았지만
400 이메일이 없습니다.
query: SELECT `Users`.`id` AS `Users_id`, `Users`.`email` AS `Users_email`, `Users`.`nickname` AS `Users_nickname`, `Users`.`password` AS `Users_password`, `Users`.`createdAt` AS `Users_createdAt`, `Users`.`updatedAt` AS `Users_updatedAt`, `Users`.`deletedAt` AS `Users_deletedAt` FROM `users` `Users` LIMIT
1
콘솔창에 위와 같이 떴고, POSTMAN에서는 Sending request...가 뜨면서 무한 로딩에 걸렸습니다.
혹시 글로벌 필터 코드가 httpException.filter.ts을 의미 하시는걸까요?